<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Words - Luna McNulty</title>
  <id>https://lmcnulty.me/words/atom.xml"</id>
  <link rel="self" href="https://lmcnulty.me/words/atom.xml" />
  <entry>
    <title>Make a Personal Offline Subset of Wikipedia</title>
    <published>2023-02-04T00:00:00</published>
    <link href="https://lmcnulty.me/words/offline-wiki-subset" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;Today's personal computing devices have
    at least dozens of gigabytes of storage, and usually much more. When you think about it, that's
    pretty amazing: You could probably store your nearest library's entire book collection on your
    laptop's hard drive, maybe even your phone.&lt;/p&gt; &lt;p&gt;But do you
    &lt;em&gt;actually&lt;/em&gt; carry a library collection in your pocket? Probably not. Most
    people nowadays carry devices that provide an endless supply of information – until they go
    offline, at which point they become not much more than glorified digital cameras.&lt;/p&gt;
    &lt;p&gt;Even if you're rarely offline, you have to admit that this state of affairs is pretty
    lame. You have a library in your pocket, but there's nothing to read on the shelves.&lt;/p&gt;
    &lt;p&gt;How can you fix that?&lt;/p&gt; &lt;p&gt;Enter &lt;a
    href="https://www.kiwix.org"&gt;Kiwix&lt;/a&gt;. It's a program for viewing Zim files, which
    are compressed collections of web pages that can be accessed offline. You can get the full
    &lt;a href="https://gutenberg.org"&gt;Project Gutenberg&lt;/a&gt; library of public domain
    books &lt;a href="https://library.kiwix.org/?q=gutenberg"&gt;in 75GB&lt;/a&gt;. You can get a
    &lt;a
    href="https://download.kiwix.org/zim/wikipedia/wikipedia_en_all_nopic_2022-01.zim"&gt;text-only
    copy of English Wikipedia&lt;/a&gt; in 50GB.&lt;/p&gt; &lt;p&gt;But even if you're enthusiastic
    about having offline reading material, 50 or more GB of it that might be too much. You can
    instead get &lt;a href="https://library.kiwix.org/?lang=eng&amp;q=best+of+wikipedia"&gt;the top
    50,000 most important articles&lt;/a&gt; for a few hundred megabytes in text-only or a couple
    GB with images. That should be enough for most people.&lt;/p&gt; &lt;p&gt;But you're not most
    people, are you?&lt;/p&gt; &lt;p&gt;I found that the top 50,000 articles was good enough for
    general topics but that the depth wasn't sufficient in particular areas of interest. So I did
    what anyone would do and researched how to make my own Zim files. What I wanted was to the top
    N Wikipedia articles, plus a large selection of articles in my areas of interest.&lt;/p&gt;
    &lt;p&gt;I found &lt;a href="https://github.com/openzim/mwoffliner"&gt;mwoffline&lt;/a&gt;,
    which takes a list of pages on a Wiki and produces a zim file containing those pages. E.g. for
    a text-only collection:&lt;/p&gt; &lt;div class="sourceCode" id="cb1"&gt;&lt;pre
    class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb1-1"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;mwoffliner&lt;/span&gt; &lt;span class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb1-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb1-2"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;-mwUrl&lt;/span&gt;=https://en.wikipedia.org/ &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb1-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb1-3"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;--adminEmail&lt;/span&gt;=foo@bar.net &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb1-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb1-4"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;--articleList&lt;/span&gt; articleList &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb1-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb1-5"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;--format&lt;/span&gt; nopic&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Where articleList is a text file listing Wikipedia articles by the part of the url the
    comes after &lt;code&gt;https://en.wikipedia.org/wiki/&lt;/code&gt;. So for instance:&lt;/p&gt;
    &lt;pre&gt;&lt;code&gt;Wikipedia Kiwix Wikimedia_Foundation …&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;Note that the pages listed in this file can't contain url-encodings, so it needs to be
    &lt;code&gt;Germaine_de_Staël&lt;/code&gt; and not
    &lt;code&gt;Germaine_de_Sta%C3%ABl&lt;/code&gt;.&lt;/p&gt; &lt;p&gt;That's cool, but how do you
    get a list of articles you want? I wrote a quick script to query the Wikipedia API for a
    several pages with a large of number of links I'd be interested in and output those links in a
    list.&lt;/p&gt; &lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode
    python"&gt;&lt;code class="sourceCode python"&gt;&lt;span id="cb3-1"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-1"&gt;&lt;/a&gt;&lt;span
    class="co"&gt;#!/usr/bin/env python3&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-2"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-2"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb3-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-3"&gt;&lt;/a&gt;&lt;span
    class="co"&gt;# get-articles-list.py&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-4"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-4"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb3-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-5"&gt;&lt;/a&gt;&lt;span
    class="im"&gt;from&lt;/span&gt; urllib.parse &lt;span class="im"&gt;import&lt;/span&gt;
    unquote&lt;/span&gt; &lt;span id="cb3-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-6"&gt;&lt;/a&gt;&lt;span
    class="im"&gt;from&lt;/span&gt; bs4 &lt;span class="im"&gt;import&lt;/span&gt;
    BeautifulSoup&lt;/span&gt; &lt;span id="cb3-7"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-7"&gt;&lt;/a&gt;&lt;span
    class="im"&gt;import&lt;/span&gt; requests&lt;/span&gt; &lt;span id="cb3-8"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-8"&gt;&lt;/a&gt;&lt;span
    class="im"&gt;import&lt;/span&gt; json&lt;/span&gt; &lt;span id="cb3-9"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-9"&gt;&lt;/a&gt;&lt;span
    class="im"&gt;from&lt;/span&gt; sys &lt;span class="im"&gt;import&lt;/span&gt;
    argv&lt;/span&gt; &lt;span id="cb3-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-10"&gt;&lt;/a&gt;&lt;/span&gt;
    &lt;span id="cb3-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-11"&gt;&lt;/a&gt;pages &lt;span
    class="op"&gt;=&lt;/span&gt; argv[&lt;span class="dv"&gt;1&lt;/span&gt;:]&lt;/span&gt; &lt;span
    id="cb3-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-12"&gt;&lt;/a&gt;&lt;/span&gt;
    &lt;span id="cb3-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-13"&gt;&lt;/a&gt;encountered &lt;span
    class="op"&gt;=&lt;/span&gt; &lt;span class="bu"&gt;set&lt;/span&gt;()&lt;/span&gt; &lt;span
    id="cb3-14"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-14"&gt;&lt;/a&gt;&lt;/span&gt;
    &lt;span id="cb3-15"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-15"&gt;&lt;/a&gt;&lt;span
    class="cf"&gt;for&lt;/span&gt; page &lt;span class="kw"&gt;in&lt;/span&gt; pages:&lt;/span&gt;
    &lt;span id="cb3-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-16"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;try&lt;/span&gt;:&lt;/span&gt; &lt;span id="cb3-17"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-17"&gt;&lt;/a&gt; response &lt;span
    class="op"&gt;=&lt;/span&gt; requests.get(&lt;/span&gt; &lt;span id="cb3-18"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-18"&gt;&lt;/a&gt;
    &lt;span class="st"&gt;'https://en.wikipedia.org/w/api.php?'&lt;/span&gt; &lt;span
    class="op"&gt;+&lt;/span&gt; &lt;span class="st"&gt;'&amp;'&lt;/span&gt;.join([&lt;/span&gt;
    &lt;span id="cb3-19"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-19"&gt;&lt;/a&gt; &lt;span
    class="st"&gt;'action=parse'&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb3-20"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-20"&gt;&lt;/a&gt;
    &lt;span class="st"&gt;'prop=text'&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb3-21"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-21"&gt;&lt;/a&gt;
    &lt;span class="st"&gt;'format=json'&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb3-22"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-22"&gt;&lt;/a&gt;
    &lt;span class="st"&gt;'formatversion=2'&lt;/span&gt;,&lt;/span&gt; &lt;span
    id="cb3-23"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-23"&gt;&lt;/a&gt; &lt;span
    class="st"&gt;'page='&lt;/span&gt; &lt;span class="op"&gt;+&lt;/span&gt; page&lt;/span&gt;
    &lt;span id="cb3-24"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-24"&gt;&lt;/a&gt; ])&lt;/span&gt;
    &lt;span id="cb3-25"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-25"&gt;&lt;/a&gt; )&lt;/span&gt;
    &lt;span id="cb3-26"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-26"&gt;&lt;/a&gt; json &lt;span
    class="op"&gt;=&lt;/span&gt; response.json()&lt;/span&gt; &lt;span id="cb3-27"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-27"&gt;&lt;/a&gt;
    text &lt;span class="op"&gt;=&lt;/span&gt; json[&lt;span
    class="st"&gt;'parse'&lt;/span&gt;][&lt;span class="st"&gt;'text'&lt;/span&gt;]&lt;span
    class="op"&gt;;&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-28"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-28"&gt;&lt;/a&gt; soup &lt;span
    class="op"&gt;=&lt;/span&gt; BeautifulSoup(text, &lt;span
    class="st"&gt;'html.parser'&lt;/span&gt;)&lt;/span&gt; &lt;span id="cb3-29"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-29"&gt;&lt;/a&gt;
    &lt;span class="cf"&gt;for&lt;/span&gt; a &lt;span class="kw"&gt;in&lt;/span&gt;
    soup.find_all(&lt;span class="st"&gt;'a'&lt;/span&gt;):&lt;/span&gt; &lt;span
    id="cb3-30"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-30"&gt;&lt;/a&gt; href &lt;span
    class="op"&gt;=&lt;/span&gt; a.get(&lt;span class="st"&gt;'href'&lt;/span&gt;)&lt;/span&gt;
    &lt;span id="cb3-31"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-31"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;if&lt;/span&gt; href &lt;span class="kw"&gt;and&lt;/span&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/'&lt;/span&gt;) &lt;span
    class="kw"&gt;and&lt;/span&gt; &lt;span class="kw"&gt;not&lt;/span&gt; (&lt;/span&gt; &lt;span
    id="cb3-32"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-32"&gt;&lt;/a&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/Category:'&lt;/span&gt;) &lt;span
    class="kw"&gt;or&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-33"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-33"&gt;&lt;/a&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/Wikipedia:'&lt;/span&gt;) &lt;span
    class="kw"&gt;or&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-34"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-34"&gt;&lt;/a&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/File:'&lt;/span&gt;) &lt;span
    class="kw"&gt;or&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-35"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-35"&gt;&lt;/a&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/Template:'&lt;/span&gt;) &lt;span
    class="kw"&gt;or&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-36"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-36"&gt;&lt;/a&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/Special:'&lt;/span&gt;) &lt;span
    class="kw"&gt;or&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-37"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-37"&gt;&lt;/a&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/Portal:'&lt;/span&gt;) &lt;span
    class="kw"&gt;or&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-38"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-38"&gt;&lt;/a&gt;
    href.startswith(&lt;span class="st"&gt;'/wiki/User:'&lt;/span&gt;) &lt;span
    class="kw"&gt;or&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-39"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-39"&gt;&lt;/a&gt; href &lt;span
    class="kw"&gt;in&lt;/span&gt; encountered&lt;/span&gt; &lt;span id="cb3-40"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-40"&gt;&lt;/a&gt;
    ):&lt;/span&gt; &lt;span id="cb3-41"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-41"&gt;&lt;/a&gt;
    encountered.add(href)&lt;/span&gt; &lt;span id="cb3-42"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-42"&gt;&lt;/a&gt; &lt;span
    class="bu"&gt;print&lt;/span&gt;(unquote(a[&lt;span
    class="st"&gt;'href'&lt;/span&gt;].replace(&lt;span class="st"&gt;'/wiki/'&lt;/span&gt;,
    &lt;span class="st"&gt;''&lt;/span&gt;)))&lt;/span&gt; &lt;span id="cb3-43"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-43"&gt;&lt;/a&gt;
    &lt;span class="cf"&gt;except&lt;/span&gt;:&lt;/span&gt; &lt;span id="cb3-44"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb3-44"&gt;&lt;/a&gt;
    &lt;span class="cf"&gt;pass&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;There are a lot of Wikipedia pages that are mostly links to other pages. To find ones
    for your interests, try searching "outline," "portal," "history of," "index of," and "list of".
    For general topics, there are five levels of &lt;a
    href="https://en.wikipedia.org/wiki/Wikipedia:Vital_articles"&gt;"vital articles"&lt;/a&gt;,
    with a larger number at each level. I took all of the level 4 articles plus extras in my areas
    of interest.&lt;/p&gt; &lt;p&gt;Example usage:&lt;/p&gt; &lt;div class="sourceCode"
    id="cb4"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span
    id="cb4-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-1"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;./get-articles-list.py&lt;/span&gt; &lt;span
    class="op"&gt;&gt;&lt;/span&gt;articleList &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-2"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;History_of_computer_science&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-3"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;History_of_philosophy&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-4"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;Index_of_computing_articles&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-5"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;Index_of_language_articles&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-6"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;List_of_philosophical_concepts&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-7"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-7"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;List_of_language_families&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-8"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;Outline_of_chess&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-9"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;Outline_of_computer_science&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-10"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;Outline_of_computing&lt;/span&gt; &lt;/span&gt; &lt;span id="cb4-11"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-11"&gt;&lt;/a&gt;
    &lt;span class="ex"&gt;Outline_of_linguistics&lt;/span&gt; &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-12"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;Portal&lt;/span&gt;:Free_and_open-source_software &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-13"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;Portal&lt;/span&gt;:Visual_arts &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-14"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-14"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Arts &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-15"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-15"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Biology_and_health_sciences
    &lt;span class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-16"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-16"&gt;&lt;/a&gt;
    &lt;span class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Everyday_life &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-17"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-17"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Geography &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-18"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-18"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Mathematics &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-19"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-19"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/People &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-20"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-20"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/History &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-21"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-21"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Philosophy_and_religion &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-22"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-22"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Society_and_social_sciences
    &lt;span class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb4-23"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/offline-wiki-subset/#cb4-23"&gt;&lt;/a&gt;
    &lt;span
    class="ex"&gt;wikipedia&lt;/span&gt;:Vital_articles/Level/4/Technology&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;This will run pretty fast, since it only needs to query the pages you specify. I
    edited the resulting &lt;code&gt;articleList&lt;/code&gt; file to add every Wikipedia article
    in my browser history/bookmarks and remove some that seemed unlikely to be useful.&lt;/p&gt;
    &lt;p&gt;The last step is to run &lt;code&gt;mwoffliner&lt;/code&gt;. This can take hours
    depending on the size of your list.&lt;/p&gt; &lt;div class="sourceCode" id="cb5"&gt;&lt;pre
    class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb5-1"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb5-1"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;mwoffliner&lt;/span&gt; &lt;span class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb5-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb5-2"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;-mwUrl&lt;/span&gt;=https://en.wikipedia.org/ &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb5-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb5-3"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;--adminEmail&lt;/span&gt;=foo@bar.net &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb5-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb5-4"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;--articleList&lt;/span&gt; articleList &lt;span
    class="kw"&gt;&amp;lt;/span&gt;&lt;/span&gt; &lt;span id="cb5-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/offline-wiki-subset/#cb5-5"&gt;&lt;/a&gt; &lt;span
    class="ex"&gt;--format&lt;/span&gt; nopic&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;The resulting zim file will appear in a directory called &lt;code&gt;out&lt;/code&gt;.
    You can load it into Kiwix and finally have, if not a library, a fantastic collection of
    information available offline.&lt;/p&gt; &lt;p&gt;A bonus I found is that the "random article"
    button for my offline Wikipedia subset is much more useful than the one on full Wikipedia. The
    latter usually takes you to something like &lt;a
    href="https://en.wikipedia.org/wiki/Lands_administrative_divisions_of_New_South_Wales"&gt;"Lands
    administrative divisions of New South Wales"&lt;/a&gt;, whereas the former generally results in
    something of interest to me.&lt;/p&gt; &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>How to Calculate Resonance</title>
    <published>2022-12-20T00:00:00</published>
    <link href="https://lmcnulty.me/words/how-to-calculate-resonance" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;Since developing &lt;a
    href="https://acousticgender.space"&gt;AcousticGender.space&lt;/a&gt;, a lot of people have
    asked me how the resonance calculation works.&lt;/p&gt; &lt;p&gt;The brief explanation is that
    the system finds the &lt;a href="https://en.wikipedia.org/wiki/Formant"&gt;formants&lt;/a&gt;
    in each vowel sound. Then it measures how high or low they are compared to the average for that
    vowel. The higher they are, the higher the resonance score, with with F₁ counting for about
    three times as much as F₂ and F₃ counting for little-to-nothing.&lt;/p&gt; &lt;figure&gt;
    &lt;img src="https://lmcnulty.me/words/how-to-calculate-resonance/./formants-praat.png"
    style="max-width: 400px" width="400"/&gt; &lt;figcaption&gt;
    &lt;p&gt;&lt;em&gt;Formants&lt;/em&gt; are bands of concentrated energy in the sound spectrum.
    They're created by sound waves bouncing around as they move through a passage, such as a vocal
    tract. The smaller the psasage, the more they bounce around and the higher the frequency. The
    base frequency of the sound is called F₀, or pitch. The first formant above F₀ is called F₁,
    the second is called F₂, etc.&lt;/p&gt; &lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;For my
    Master's project, I wrote a formal definition with math that looks like this:&lt;/p&gt;
    &lt;p&gt;&lt;img alt="complicated-looking math"
    src="https://lmcnulty.me/words/how-to-calculate-resonance/math.png" style="max-width: 400px"
    width="400"/&gt;&lt;/p&gt; &lt;p&gt;However, the notation makes it look way more complicated
    than it actually is. It's really just high school-level statistics.&lt;/p&gt; &lt;p&gt;Walking
    through an example, in the "please call Stella" example recording, the formant frequencies you
    get from &lt;a href="https://www.fon.hum.uva.nl/praat/"&gt;Praat&lt;/a&gt; for the "a" in
    "call" (= /ɔ/) were&lt;/p&gt; &lt;pre&gt;&lt;code&gt;F₁: 620Hz F₂: 1077Hz F₃:
    3079Hz&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;Given that, can we find how far above or below the
    average for an /ɔ/ each of those values are. The unit we use is standard deviations
    (σ).&lt;/p&gt; &lt;pre&gt;&lt;code&gt;F₁: 620Hz vs average 612Hz = 0.053σ = just barely above
    average for an /ɔ/ F₂: 1077Hz vs average 1097Hz = -0.042σ = just barely below average for an
    /ɔ/ F₃: 3079Hz vs average 2522Hz = 1.234σ = above average for an /ɔ/&lt;/code&gt;&lt;/pre&gt;
    &lt;p&gt;Now, each of the three formants aren't equally significant to how we perceive gendered
    resonance. So we have to multiply each normalized frequency by a certain a certain constant
    "weight". The set of weights that that most accurately distinguished between male and female
    recordings in a sample dataset was:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;F₁: 0.732 F₂: 0.268 F₃:
    0.000&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;So the weighted average is&lt;/p&gt;
    &lt;pre&gt;&lt;code&gt; 0.732 × 0.053 + 0.236 × -0.042 + 0.000 × 1.234 =
    0.027&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;I didn't realize in advance that the weight for F₃
    would be zero, so it could also be considered a weighted average of just F₁ and F₂. However,
    using different data or outlier removal schemes can change this so that F₃ has a small but
    non-zero value, so who knows.&lt;/p&gt; &lt;p&gt;Now, the number 0.027 is on a scale where 0 is
    the average, 1 is moderately above average, and 2 is far above average. For below average, it's
    the same but the numbers are negative. So at 0.027, the resonance in this recording is slightly
    above average. Technically we can stop there, but I thought people would find it easier to
    think of 50% as the average, 75% as above average, and 100% as far above average. For that to
    be the case, we just add 2 to each result, then divide by 4 and multiply by a
    hundred.&lt;/p&gt; &lt;pre&gt;&lt;code&gt;(0 + 2) / 4 × 100 = 1/2 × 100 = 50% (1 + 2) / 4 × 100
    = 3/4 × 100 = 75% (2 + 2) / 4 × 100 = 4/4 × 100 = 100%&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;So,
    the percentage for 0.027 is:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;(0.027 + 2) / 4 × 100 =
    50.68%.&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;That's for a single syllable. When you're not playing
    back a clip, the application shows you the median resonance across every syllable – that's
    typically what you want to focus on, especially when starting out.&lt;/p&gt;
    &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>One Brain, Two Minds</title>
    <published>2022-01-15T00:00:00</published>
    <link href="https://lmcnulty.me/words/one-brain-two-minds" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;div class="preface"&gt; &lt;p&gt;This is a
    post I made in the forum of my Spring 2021 class on &lt;em&gt;Language Processing in Humans and
    Machines&lt;/em&gt;. It was be written late at night while I felt enlightened after finishing
    an assigned reading – as a result, it should be taken with a grain of salt.&lt;/p&gt;
    &lt;p&gt;The paper in question was &lt;a
    href="http://ruccs.rutgers.edu/images/personal-zenon-pylyshyn/proseminars/Proseminar13/ConnectionistArchitecture.pdf"&gt;Connectionism
    and cognitive architecture: A critical analysis&lt;/a&gt;, a 1988 critique of connectionism by
    Jeremy Fodor and Zenon Pylyshyn. Connectionism was then a popular theory viewing cognition in
    humans as fundamentally similar to computations done in neural networks. Fodor and Pylyshyn
    argued that some of the brain's capabilities could only be explained if it was doing symbol
    processing in the manner of classical Turing machines.&lt;/p&gt; &lt;/div&gt; &lt;hr/&gt;
    &lt;p&gt;I just finished the Fodor and Pylyshyn reading, and throughout I was pre-occupied with
    one idea that was only addressed briefly at the end: the possibility that a connectionist and
    classical models of cognitive processing could co-exist in the same brain. F&amp;P mention
    throughout the paper that connectionist models could serve as an implementation for a classical
    architecture / Turing machine. Only at the very end, they suggest that&lt;/p&gt;
    &lt;blockquote&gt; &lt;p&gt;A good bet might be that networks sustain &lt;em&gt;some&lt;/em&gt;
    cognitive processes as can be analyzed as the drawing of statistical inferences; as far as we
    can tell, what network models really are is just analog machines for computing such inferences.
    Since we doubt that much of cognitive processing does consist of analyzing statistical
    relations, this would be a quite a modest estimate of the prospects for network theory compared
    to what the connectionists themselves have been offering.&lt;/p&gt; &lt;/blockquote&gt;
    &lt;p&gt;This possibility seems much more significant today, where we can see that neural nets
    can do all sorts of tasks, and the question is whether they can do
    &lt;em&gt;everything&lt;/em&gt; the brain can do. Supposing that they can't, it still seems
    plausible that brains use a network-like architecture for many tasks in addition to a
    neurally-implemented Turing machine that handles what networks can't. The answer to the
    question of "how do you combine them?" mentioned in Monday's lecture then might simply be "you
    don't." The network system doesn't have access to symbols, and the symbolic system doesn't have
    access to nodes. There would be, essentially, two largely-independent minds in one
    brain.&lt;/p&gt; &lt;p&gt;Indeed, a lot of people have the intuition that the brain has two
    systems, one of which is precise and methodical and the other of which is more fuzzy and
    intuitive. In pop psych these are called the left and right sides of the brain. We know that
    these systems aren't actually divided in the brain this way, but it's conceivable the mythology
    reflects some real aspect of how the brain works. In &lt;em&gt;Thinking Fast and
    Slow&lt;/em&gt;, Daniel Kahneman talks in similar terms about how human behavior can be
    understood in terms of a fast, automatic "system one" and a slow, logical "system two." The
    existence of two systems explains why almost everyone has intuitions like "if 2 chickens can
    lay 2 eggs in 2 days, 4 chickens can lay 4 eggs in 4 days" even though we can pretty easily
    work out that it's wrong. The fast, associationist system gives the wrong answer before the
    slow, methodical system gives the right answer. That would make perfect sense if system one
    were a massively-parallel neural network and system two was a serial Turing machine (at some
    level of representation).&lt;/p&gt; &lt;p&gt;This would also seem to explain certain
    observations about language processing if we suppose that both systems are involved in
    &lt;em&gt;overlapping&lt;/em&gt; but &lt;em&gt;disconnected&lt;/em&gt; language-related tasks.
    For instance, Rumelhart and McClelland gave the example of "The man the boy the girl hit kissed
    moved" to show that we have trouble understanding the deep recursive structures that the
    classical model says are so important. However, even though most people would fail to
    comprehend this sentence on the first pass, we &lt;em&gt;can&lt;/em&gt; understand it if we
    think about it a little longer. Again, this makes sense if we suppose that the "first pass" is
    carried out by a fast, connectionist-like neural architecture and the second is carried out by
    a slow neural Turing machine. This would also explain why the different levels of language
    processing seem to happen in parallel even though we have trouble formulating rules that work
    on a partial input: first-pass processing is done with a parallel architecture, while the rules
    are carried out on a serial one.&lt;/p&gt; &lt;p&gt;The presence in the brain of a slow,
    rule-based system for processing language might also enable the network-based system to do more
    with less data. The systems could be independent of each other in terms of their
    representations, but could potentially take as input the output of the other system. This would
    enable the rule-based system to generate valid sentences which could be fed as input to the
    network system, allowing it to get really good at quickly performing most, but not all,
    language-related tasks. (I'm not sure if a two-system model of cognition could explain the data
    problem on other tasks, though.)&lt;/p&gt; &lt;p&gt;This also seems consistent with biological
    evolution. A connectionist network can do some useful tasks with just a few neurons, so it's
    easy to imagine a mutation creating a proto-brain of just a few neurons that grew over many
    generations, to the point where it was large enough to implement a Turing machine (in addition
    to its other functions). By contrast, if the brain were &lt;em&gt;just&lt;/em&gt; a Turing
    machine, it's hard to imagine how it would evolve from more rudimentary structures, especially
    without maintaining any residual functions.&lt;/p&gt; &lt;p&gt;If the human brain in particular
    evolved to implement a Turing machine, that would also explain the leap between what human
    brains can do and what other animals can do. A chimp's brain doesn't seem all
    &lt;em&gt;that&lt;/em&gt; different from a human brain, but no matter how hard we've tried, we
    can't teach a chimp to use recursive syntactic structure. That would make sense if human brains
    have, and chimp brains lack, a system that fundamentally works by processing symbols according
    to recursive constituent relations.&lt;/p&gt; &lt;p&gt;Likewise, my understanding is that
    humans started to do all the things we associate with our cognitive sophistication over
    animals—like language, religion, art, technological development—at around the same time on an
    evolutionary scale. That too would make sense if all of those things are a result of the
    ability to process symbols, which appeared all at once when the human brain evolved to
    implement a Turing machine.&lt;/p&gt; &lt;p&gt;Fodor and Pylyshyn claimed that it's implausible
    that human cognition is systematic and the cognition of other animals is not. However, I wasn't
    convinced by their argument. They state:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;It is not,
    however, plausible that only the minds of verbal organisms are systematic. Think what it would
    mean for this to be the case. It would have to be quite usual to find, for example, animals
    capable of representing the state of affairs a&lt;strong&gt;R&lt;/strong&gt;b but incapable of
    representing the state of affairs b&lt;strong&gt;R&lt;/strong&gt;a.&lt;/p&gt;
    &lt;/blockquote&gt; &lt;p&gt;I don't find it at all obvious that this isn't usual among
    non-human animals, at least if I'm understanding what's being said correctly. I've heard that
    Galapagos tortoises don't fear larger animals (like humans) because they don't have any natural
    predators. It seems reasonable to suppose, then, that they can't conceive of something eating a
    tortoise. However, presumably they can conceive of a tortoise eating something else, seeing as
    they haven't all starved by now.&lt;/p&gt; &lt;hr/&gt; &lt;p&gt;I've since learned that the
    idea I proposed here is known as "Dual Process Theory." A &lt;abbr title="teacher's
    assistant"&gt;TA&lt;/abbr&gt; referred me to &lt;a
    href="https://royalsocietypublishing.org/doi/pdf/10.1098/rstb.2012.0211"&gt;this
    paper&lt;/a&gt; which makes similar arguments more formally, and with reference to cognition in
    general more than just language.&lt;/p&gt; &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>No One is “Non-Technical”</title>
    <published>2022-01-15T00:00:00</published>
    <link href="https://lmcnulty.me/words/non-technical" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;As I've been searching for jobs, I've
    noticed that many postings list as a requirement the ability to communicate with
    "non-technical" people. While it's important for those with certain technical expertise to be
    able to communicate their ideas to those without it, this goal is not helped by characterizing
    some people as "non-technical."&lt;/p&gt; &lt;p&gt;First off, many supposedly "non-technical"
    people in fact have advanced technical skills – just ones that don't concern computers. Someone
    who can repair cars is still very technically capable even if they don't know how to send an
    email. There's nothing special about computers that makes people who understand them uniquely
    capable, important, or "technical".&lt;/p&gt; &lt;p&gt;Even if we take "technical" as referring
    narrowly to computer skills, almost everyone in a modern workplace is technical at some level.
    If you know what a file is, that's a technical skill – one that &lt;a
    href="https://www.theverge.com/22684730/students-file-folder-directory-structure-education-gen-z"&gt;many
    people lack&lt;/a&gt;. To be sure, some people have more computer skills than others – but it's
    a difference of degree, not of kind. When you're trying to communicate technical ideas, not
    everyone who you might consider "non-technical" is at the same level. An octogenarian just
    learning to send a text message is different from an Art History PhD who recently got into
    Digital Humanities is different from that kid in &lt;a
    href="https://youtube.com/watch?v=3S5BLs51yDQ"&gt;the "what's a computer" commercial&lt;/a&gt;.
    Communicating with these three "non-technical" people is likely to require different
    strategies.&lt;/p&gt; &lt;p&gt;Furthermore, calling people "non-technical" underrates their
    ability to learn. We're all at a certain level of technical proficiency, and we all have the
    potential to reach a higher one. Some people are discouraged from doing so because they think
    of that they're not "technical" – that they're not "computer people." But in fact, there are no
    "computer people." There are only regular people who accumulated bits of computer knowledge
    little by little – sometimes from being taught in school, but more often from facing their own
    computer problems with the confidence and will to learn. Far too many people lack that
    confidence &lt;em&gt;because&lt;/em&gt; they learn to think of themselves as "non-technical."
    It's true that not everyone has time or energy to devote specifically to learning about
    computers – and they shouldn't have to. However, anyone who uses computers at all will at times
    encounter organic opportunities to learn: we should avoid encouraging people to squander these
    in a fit of learned helplessness.&lt;/p&gt; &lt;p&gt;When we explain a technical concept to
    someone who lacks some of the requisite background, we should do so in a way that facilitates
    their own technical growth. This requires us to recognize that everyone is a technical person –
    some of us are just at different places in our journey than others.&lt;/p&gt;
    &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>Using Code to Intuit the Monty Hall Problem</title>
    <published>2020-06-23T00:00:00</published>
    <link href="https://lmcnulty.me/words/monty-hall" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;The Monty Hall problem is a famous puzzle
    that shows how statistical facts can be unintuitive. It's based on a game show in which the
    contestant selects one of three doors, receiving whatever prize is behind it. One door has a
    desirable prize behind it, which is usually a car, and the others have a gag prize, usually a
    goat. My father told me about this problem when I was probably under 10, and at the time I
    neither understood the math, nor why anyone would want a car when they could have &lt;a
    href="https://xkcd.com/1282/"&gt;&lt;em&gt;a goat&lt;/em&gt;&lt;/a&gt;. So for the rest of this
    article, assume that the preferred prize is a goat, and the others are, say, bags of
    sand.&lt;/p&gt; &lt;!--blockquote class="pull-away" style="width: 11em;"&gt; writing the
    problem in code, the answer seemed &lt;em&gt;completely obvious&lt;/em&gt;.
    &lt;/blockquote--&gt; &lt;p&gt;Anyway, after the contestant selects a door, the show host
    (originally named Monty Hall) opens another door, revealing a bag of sand. The contestant then
    has the option to switch to the remaining door. The question is: Is it better to switch or does
    it make no difference?&lt;/p&gt; &lt;p&gt;The answer, as you may have heard before, is that
    it's better to switch, because the probability of getting the goat when you initially pick a
    door is ⅓, which doesn't change until you switch. This is confusing, however, because it seems
    like after the host shows you the bag of sand, there's one door with a goat behind it, and one
    door with sand behind, so the probability of winning should be ½, regardless of which door you
    pick. There are a zillion articles explaining why this isn't the case, which comes down to the
    fact that this is a &lt;em&gt;conditional&lt;/em&gt; probability, not just a choice between two
    random options. However, depending on your background, you may have a better intuition for code
    than for math, in which case the easiest way to understand the problem is by seeing it as a
    program.&lt;/p&gt; &lt;p&gt;Take the following Python script. If you're new to Python, don't be
    intimidated by the &lt;a
    href="https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions"&gt;list
    comprehensions&lt;/a&gt;, which is where you have &lt;code&gt;for&lt;/code&gt;s and
    &lt;code&gt;if&lt;/code&gt;s inside brackets: they are not hard to understand and they will
    make your life much easier if you learn to use them.&lt;/p&gt; &lt;div class="sourceCode"
    id="cb1"&gt;&lt;pre class="sourceCode python"&gt;&lt;code class="sourceCode python"&gt;&lt;span
    id="cb1-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-1"&gt;&lt;/a&gt;&lt;span
    class="im"&gt;import&lt;/span&gt; random, statistics&lt;/span&gt; &lt;span id="cb1-2"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-2"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb1-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-3"&gt;&lt;/a&gt;&lt;span
    class="kw"&gt;def&lt;/span&gt; simulate(switch):&lt;/span&gt; &lt;span id="cb1-4"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/monty-hall/#cb1-4"&gt;&lt;/a&gt; &lt;span
    class="co"&gt;"""Return True if the contestant wins the goat, False
    otherwise."""&lt;/span&gt;&lt;/span&gt; &lt;span id="cb1-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-5"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb1-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-6"&gt;&lt;/a&gt; &lt;span class="co"&gt;#
    Shuffle the doors and pick one at random&lt;/span&gt;&lt;/span&gt; &lt;span id="cb1-7"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/monty-hall/#cb1-7"&gt;&lt;/a&gt; doors
    &lt;span class="op"&gt;=&lt;/span&gt; [&lt;span class="st"&gt;'goat'&lt;/span&gt;, &lt;span
    class="st"&gt;'sand'&lt;/span&gt;, &lt;span class="st"&gt;'sand'&lt;/span&gt;]&lt;/span&gt;
    &lt;span id="cb1-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-8"&gt;&lt;/a&gt;
    random.shuffle(doors)&lt;/span&gt; &lt;span id="cb1-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-9"&gt;&lt;/a&gt; choice &lt;span
    class="op"&gt;=&lt;/span&gt; random.randint(&lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="dv"&gt;2&lt;/span&gt;)&lt;/span&gt; &lt;span id="cb1-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-10"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb1-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-11"&gt;&lt;/a&gt; &lt;span class="co"&gt;# Pick
    one of the doors with sand behind it to show &lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb1-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-12"&gt;&lt;/a&gt; remaining_sand &lt;span
    class="op"&gt;=&lt;/span&gt; [i &lt;span class="cf"&gt;for&lt;/span&gt; i &lt;span
    class="kw"&gt;in&lt;/span&gt; &lt;span class="bu"&gt;range&lt;/span&gt;(&lt;span
    class="dv"&gt;3&lt;/span&gt;) &lt;span class="cf"&gt;if&lt;/span&gt; doors[i] &lt;span
    class="op"&gt;==&lt;/span&gt; &lt;span class="st"&gt;'sand'&lt;/span&gt; &lt;span
    class="kw"&gt;and&lt;/span&gt; i &lt;span class="op"&gt;!=&lt;/span&gt; choice]&lt;/span&gt;
    &lt;span id="cb1-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-13"&gt;&lt;/a&gt; shown &lt;span
    class="op"&gt;=&lt;/span&gt; random.choice(remaining_sand)&lt;/span&gt; &lt;span
    id="cb1-14"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-14"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb1-15"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-15"&gt;&lt;/a&gt; &lt;span class="co"&gt;# If
    switch is selected, switch choice to the remaining door&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb1-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-16"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;if&lt;/span&gt; switch: choice &lt;span class="op"&gt;=&lt;/span&gt; [i &lt;span
    class="cf"&gt;for&lt;/span&gt; i &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span
    class="bu"&gt;range&lt;/span&gt;(&lt;span class="dv"&gt;3&lt;/span&gt;) &lt;span
    class="cf"&gt;if&lt;/span&gt; &lt;span class="kw"&gt;not&lt;/span&gt; i &lt;span
    class="kw"&gt;in&lt;/span&gt; (choice, shown)][&lt;span
    class="dv"&gt;0&lt;/span&gt;]&lt;/span&gt; &lt;span id="cb1-17"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-17"&gt;&lt;/a&gt; &lt;/span&gt; &lt;span
    id="cb1-18"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-18"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;return&lt;/span&gt; doors[choice] &lt;span class="op"&gt;==&lt;/span&gt; &lt;span
    class="st"&gt;'goat'&lt;/span&gt;&lt;/span&gt; &lt;span id="cb1-19"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-19"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb1-20"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-20"&gt;&lt;/a&gt;trials &lt;span
    class="op"&gt;=&lt;/span&gt; &lt;span class="dv"&gt;100000&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb1-21"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/monty-hall/#cb1-21"&gt;&lt;/a&gt;&lt;span
    class="bu"&gt;print&lt;/span&gt;(&lt;span class="st"&gt;"Switch: "&lt;/span&gt;,
    statistics.mean([simulate(&lt;span class="va"&gt;True&lt;/span&gt;) &lt;span
    class="cf"&gt;for&lt;/span&gt; i &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span
    class="bu"&gt;range&lt;/span&gt;(trials)]))&lt;/span&gt; &lt;span id="cb1-22"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/monty-hall/#cb1-22"&gt;&lt;/a&gt;&lt;span
    class="bu"&gt;print&lt;/span&gt;(&lt;span class="st"&gt;"Stay: "&lt;/span&gt;,
    statistics.mean([simulate(&lt;span class="va"&gt;False&lt;/span&gt;) &lt;span
    class="cf"&gt;for&lt;/span&gt; i &lt;span class="kw"&gt;in&lt;/span&gt; &lt;span
    class="bu"&gt;range&lt;/span&gt;(trials)]))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Run the program, and we see that indeed, you win twice as often if you switch than if
    you stay:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;Switch: 0.66462 Stay:
    0.33362&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;But we already knew that. However, the key insight is
    on line 16:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;if switch: choice = [i for i in range(3) if not i
    in (choice, shown)][0]&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;This is the line that changes the
    choice to the remaining door. If &lt;code&gt;switch&lt;/code&gt; is
    &lt;code&gt;False&lt;/code&gt;, it won't run. Comment out line 16, and your IDE or your linter
    will tell you something like this:&lt;/p&gt; &lt;pre&gt;&lt;code&gt;monty-hall.py:13:4: W0612:
    Unused variable 'shown' (unused-variable)&lt;/code&gt;&lt;/pre&gt; &lt;p&gt;When the contestant
    doesn't switch, the information provided by opening the door isn't used at all. In fact, the
    Python VM will probably skip over the lines computing &lt;code&gt;shown&lt;/code&gt; because
    it's not used. In other words, choosing not to switch is &lt;em&gt;exactly the same&lt;/em&gt;
    as picking randomly from three options.&lt;/p&gt; &lt;p&gt;I decided to write this article
    because after writing the problem in code, the answer seemed &lt;em&gt;completely
    obvious&lt;/em&gt;. Before, I was sort of able to understand the standard stats textbook
    explanation, but the answer still seemed sort of opaque. Hopefully, there will be a few other
    people out there to whom code is a more native language than math who will find this as
    clarifying as I did.&lt;/p&gt; &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>A Better Solution for Married Surnames</title>
    <published>2020-06-19T00:00:00</published>
    <link href="https://lmcnulty.me/words/surnames" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;In my country, tradition dictates that
    when a couple gets married, the woman takes her husband's last name, which is also passed on to
    any children they might have. This has two benefits:&lt;/p&gt; &lt;ol type="1"&gt;
    &lt;li&gt;You can usually refer to a household by name, as in: "let's invite the Tooks and the
    Baggins' for dinner."&lt;/li&gt; &lt;li&gt;You can sort of use it to trace your patrilineal
    ancestry.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;However, it has a bunch of problems:&lt;/p&gt; &lt;ol
    type="1"&gt; &lt;li&gt;It's associated with the now widely-rejected idea that the man is
    supposed to be the head of the household.&lt;/li&gt; &lt;li&gt;Not every marriage
    &lt;em&gt;has&lt;/em&gt; a man and a woman anymore.&lt;/li&gt; &lt;li&gt;Changing your last
    name may be detrimental in certain careers.&lt;/li&gt; &lt;li&gt;Over time, it &lt;a
    href="https://en.wikipedia.org/wiki/Galton%E2%80%93Watson_process"&gt;results in fewer and
    fewer last names&lt;/a&gt;, because a surname goes extinct if there are no male children to
    carry it. This has had a particularly strong impact on China, where people have had names like
    "Li" or "Zhang" since at least 2,500 years ago, which was before the West even
    &lt;em&gt;had&lt;/em&gt; surnames, let alone settling whether they would be Latin or Greek.
    Thus, Chinese names have had more time to go extinct, which is why I ended up calling both of
    my Chinese teachers in school Li lăoshi&lt;a class="footnote-ref"
    href="https://lmcnulty.me/words/surnames/#fn1" id="fnref1"
    role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;Some
    people have taken to hyphenating their last name with that of their spouse. This is probably
    more egalitarian and mitigates the career damage that comes with a name-change. However, it has
    the serious issue that it gets unreasonable over multiple generations. For instance, if Alice
    Abrams and Bob Bell get married and name their daughter "Carol Abrams-Bell," that works fine.
    But what happens when Carol marries Frank Delaney-Edwards? They could proceed recursively and
    adopt the name Abrams-Bell-Delaney-Edwards, but that's monstrous. Alternately they could follow
    the Iberian tradition and use the first name from each pair, yielding Abrams-Delaney. But that
    has the same problem as the traditional system: half the names get lost.&lt;/p&gt; &lt;p&gt;But
    this problem is inevitable, isn't it? Everyone has 4 grandparents, 8 great-grandparents, and
    2&lt;sup&gt;n+2&lt;/sup&gt;
    great&lt;sub&gt;1&lt;/sub&gt;-great&lt;sub&gt;2&lt;/sub&gt;…great&lt;sub&gt;n&lt;/sub&gt;-grandparents.
    You can't share a name with all of them. So at some point one parent's name has to predominate,
    right?&lt;/p&gt; &lt;p&gt;Wrong. There's a way for everyone to share a name with both of their
    parents, their children, and their spouse. Just follow these rules:&lt;/p&gt; &lt;ol
    type="1"&gt; &lt;li&gt;&lt;p&gt;When a couple gets married, they &lt;strong&gt;invent a new
    name&lt;/strong&gt;.&lt;/p&gt; &lt;div class="example"&gt; &lt;p&gt;Romeo Montague and Juliet
    Capulet get married. When he's giving the vows, Friar Lawrence asks them "What will be the name
    of this union?" Together they answer "Starcross."&lt;/p&gt; &lt;/div&gt;&lt;/li&gt;
    &lt;li&gt;&lt;p&gt;This name gets added to their current last names with a hyphen.&lt;/p&gt;
    &lt;div class="example"&gt; &lt;p&gt;"Romeo Montague-Starcross" and "Juliet
    Capulet-Starcross"&lt;/p&gt; &lt;/div&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;When a couple has
    children, they inherit &lt;strong&gt;only the new name&lt;/strong&gt;.&lt;/p&gt; &lt;div
    class="example"&gt; &lt;p&gt;This is an alternate reality where Romeo and Juliet act much more
    sensibly, so they survive and have a child, whom they decide to name after the Friar who
    married them. The child is thus named "Lawrence Starcross"&lt;/p&gt; &lt;/div&gt;&lt;/li&gt;
    &lt;/ol&gt; &lt;p&gt;This means you won't share a name with your grandparents, but you already
    don't share a name with half of your grandparents, so surnames were never a very meaningful
    reflection of your family beyond one generation anyway. Furthermore, since each child's name
    carries a "reference" to their parent, you get a "linked list" tracing your ancestry
    matrilineally &lt;em&gt;and&lt;/em&gt; patrilineally.&lt;/p&gt; &lt;figure&gt; &lt;img
    src="https://lmcnulty.me/words/surnames/tree.png"/&gt; &lt;figcaption&gt; Here, suppose that
    Alice and Bob decided to make their household name a combination of their original names
    (another good solution, with which this is "backwards-compatible"). However, Frank was so
    turned off by this that he decided not to marry Carol, who was then so upset that she
    teleported through time and space to 16th-century Verona and married Lawrence Starcross.
    Realizing that they both had incredibly un-Italian names, they then decided that their
    household name would reflect their home, and their child would be named "Antonio."
    &lt;/figcaption&gt; &lt;/figure&gt; &lt;p&gt;This solution combines the benefits of both the
    traditional and hyphenated systems. Like the traditional system:&lt;/p&gt; &lt;ul&gt;
    &lt;li&gt;It preserves household names (even distinguishing between the households of male
    siblings!)&lt;/li&gt; &lt;li&gt;It allows tracing ancestry, in a less direct but more complete
    way.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Like the hyphenated system:&lt;/p&gt; &lt;ul&gt;
    &lt;li&gt;It's egalitarian.&lt;/li&gt; &lt;li&gt;It keeps a reasonable number of different
    names in usage.&lt;/li&gt; &lt;li&gt;It doesn't require anyone to abandon their own family
    name.&lt;/li&gt; &lt;li&gt;It signals that you're the type of person to break with tradition.
    (Which may or may not be desirable)&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Finally, it has several
    unique benefits:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;It gives people more choice over their own
    name&lt;/li&gt; &lt;li&gt;It's a gender-neutral way of indicating marriage status. Eg. Miss
    vs.&#160;Mrs.&#160;indicates whether a woman is married, but there's no equivalent for men. If
    this system were widely-adopted, a hyphen would mean married, and no hyphen would mean
    unmarried.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;Assuming that you're willing to accept that you
    won't share a name with one of your 32 great-great-great-great-grandfathers, I can think of
    three disadvantages:&lt;/p&gt; &lt;ol type="1"&gt; &lt;li&gt;&lt;p&gt;Hyphenated names are
    slightly more cumbersome and could be mistaken for a middle name plus a last name when
    pronounced.&lt;/p&gt;&lt;/li&gt; &lt;li&gt;&lt;p&gt;You'd end up with "fad" family names. For
    instance, you can imagine that many couples who married in the year 2000 might have decided to
    choose the name "Millennium." This isn't necessarily bad, but I don't personally like the sound
    of it, and I hope that people would try to choose unique names.&lt;/p&gt;&lt;/li&gt;
    &lt;li&gt;&lt;p&gt;Both partners would "have to" go through the bureaucracy of adding to their
    name. This would preferably be mitigated by reducing the amount of bureaucracy required, but I
    wouldn't hold my breath on that.&lt;/p&gt;&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;I am not married and
    do not intend to marry anytime soon. However, if I ever do, I hope to convince my partner to go
    along with this idea. In the unlikely event that this article convinces you and you go along
    with it, please let me know! My preferred email address can always be found on &lt;a
    href="https://lmcnulty.gitlab.io/resume/"&gt;my résumé&lt;/a&gt;.&lt;/p&gt; &lt;section
    class="footnotes" role="doc-endnotes"&gt; &lt;hr/&gt; &lt;ol&gt; &lt;li id="fn1"
    role="doc-endnote"&gt;&lt;p&gt;In Chinese, you address your teacher by their family name +
    lăoshī (老师), which means "teacher".&lt;a class="footnote-back"
    href="https://lmcnulty.me/words/surnames/#fnref1"
    role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/section&gt;
    &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>How to Pronounce “th” in English</title>
    <published>2020-05-19T00:00:00</published>
    <link href="https://lmcnulty.me/words/english-th" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;In my article on &lt;a
    href="https://lmcnulty.me/words/english-th/../french-vowels"&gt;French vowels&lt;/a&gt;, I
    explained how different languages have different phonemes, giving the example of how native
    French speakers have trouble with the "th" sounds while learning English. In fact, these sounds
    are quite unusual cross-linguistically, appearing in only about 4% of the world's languages —so
    they give trouble to a huge number of English second-language learners, not just the French.
    I'm a native English speaker, so I don't remember learning to pronounce these sounds as a
    toddler —but I thought it would be an interesting phonetics exercise to try and describe their
    pronunciation. I refrained from publishing this until I heard back from one of my French
    friends that this was helpful to them, so hopefully it will be to others as well.&lt;/p&gt;
    &lt;hr/&gt; &lt;p&gt;The first thing to understand is that there are actually
    &lt;strong&gt;two&lt;/strong&gt; 'th' sounds in English. Although most English speakers aren't
    aware of the difference, they can tell between the words "thigh" (part of the leg) and "thy"
    (an old-fashioned way of saying "you").&lt;/p&gt; &lt;p&gt;The 'th' in "&lt;a
    href="https://forvo.com/word/thigh/#en"&gt;thigh&lt;/a&gt;" is /θ/ in &lt;abbr
    title="International Phonetic Alphabet"&gt;IPA.&lt;br/&gt; The 'th' in "&lt;a
    href="https://forvo.com/word/thy/#en"&gt;thy&lt;/a&gt;" is /ð/ in IPA.&lt;/abbr&gt;&lt;/p&gt;
    &lt;p&gt;I'll explain the difference later, but let's start with /θ/&lt;/p&gt; &lt;p&gt;When
    non-native speakers don't know how to make this sound, they usually produce a /f/ or a /s/
    instead: eg, they'll sometimes say "fink" or "sink" instead of "think." This isn't arbitrary:
    they choose these sounds because they are both &lt;strong&gt;fricatives&lt;/strong&gt;, just
    like /θ/. A fricative is a sound that's made by making a closure between two parts of the mouth
    and letting out a small stream of air.&lt;/p&gt; &lt;p&gt;When you make an /s/, you touch the
    tip of your tongue to the alveolar ridge (the little bump on the top of your mouth behind the
    teeth). Hold the /s/ in "yessssssss—". You will feel how you are releasing a little bit of air
    between your tongue and the roof of your mouth.&lt;/p&gt; &lt;p&gt;Now try the same thing with
    /f/. You make an /f/ by touching your front teeth to your bottom lip. Now if you hold the /f/
    in "stufffffff—", you'll feel how you are letting the air pass between your lip and your teeth.
    Notice that a little bit of air also goes around the sides of your teeth.&lt;/p&gt;
    &lt;p&gt;/θ/ is the same, only instead of making the closure with your teeth and your lips, you
    make it with your teeth and your tongue. To make the /θ/, touch the tip of your tongue to your
    two front teeth. Then blow a little air between your teeth and your tongue, just as you do to
    make an /f/, just substituting the lips for the tongue. The opening of your mouth should not be
    too wide, or else all the air will go around and not between the tongue and the teeth. However,
    you should have a little opening at the sides of your mouth, or else the sound will not be loud
    enough. Once you're doing this, you should be able to transition to saying
    "—thhhhhhhhigh."&lt;/p&gt; &lt;p&gt;/ð/ is exactly the same, only you also vibrate your vocal
    folds. To understand what this means, put your hand on your neck. Then hold a /v/ sound as in
    "slavvvvvvvvvvvv—" you will feel a vibration in your nest. Now do the same thing but holding
    /f/, like in "struff". You'll notice that you don't feel the same vibration in your neck when
    you make the /f/ sound.&lt;/p&gt; &lt;p&gt;Linguistics call this property
    &lt;strong&gt;voice&lt;/strong&gt;. Languages differentiate between sounds depending on whether
    they are voiced or not. /v/ is the voiced version of /f/, /z/ is the voiced version of /s/, /d/
    is the voiced version of /t/, etc.&lt;/p&gt; &lt;p&gt;To learn how to control the voicing, try
    to transition between a /s/ sound and a /z/ sound. They are exactly the same except for the
    voicing. Keep your hand on your neck and go "ssssssss zzzzzzzzs ssssssss zzzzzzzz." As you do
    this you can become conscious of how your vocal folds are vibrating.&lt;/p&gt; &lt;p&gt;To make
    a /ð/, try and hold a /θ/. A good word that ends with this is "bathhhhhh—". Now, as you hold
    the /θ/ sound, start vibrating your vocal folds, the same way you did as you transitioned from
    /s/ to /z/. If you do it, you'll be making the /ð/ sound and you can transition to
    "—thhhhhy"&lt;/p&gt; &lt;p&gt;Some words that use /θ/ (voiceless): think, thanks, thunder,
    thirsty, thumb, throw, theory, throat, bath.&lt;/p&gt; &lt;p&gt;Some words that use /ð/
    (voiced): this, they, father, weather, bother, bathe.&lt;/p&gt; &lt;p&gt;As is often the case
    in English orthography, there is to my knowledge no way to determine the sound from the
    spelling of the word. However, now that you know the IPA for each sound, you'll at least be
    able to tell from the pronunciation guides in dictionaries.&lt;/p&gt;
    &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>Writing BMP Images from Scratch</title>
    <published>2020-03-28T00:00:00</published>
    <link href="https://lmcnulty.me/words/bmp-output" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;Many of my programming projects revolve
    around &lt;a href="https://lmcnulty.gitlab.io/wallpaper-generator/"&gt;making pretty
    pictures&lt;/a&gt; or turning them into websites. Recently, however, it occurred to me that
    I've never worked with a raster graphics file directly. At the lowest-level, I've always just
    manipulated an RGB array in memory, then called out to some library to handle saving my
    work.&lt;/p&gt; &lt;p&gt;This thought made me a little uncomfortable. The way I used computers
    was completely overturned once I came to understand the underlying text representation that
    makes up web pages, config files, source code, etc. What if understanding binary data
    representations is just as important?&lt;/p&gt; &lt;p&gt;Thus, I decided it was time to write a
    program that could produce images from scratch. This meant using a language without a runtime,
    that's good for manipulating bytes directly, and which I already needed to brush up on anyway:
    C. I went with BMP as an output format. There are a few even simpler formats, like &lt;a
    href="https://en.wikipedia.org/wiki/Truevision_TGA"&gt;TGA&lt;/a&gt;, but since I'm writing a
    blog post, I thought I might as well go with something viewable in a browser.&lt;/p&gt;
    &lt;p&gt;&lt;a href="https://gitlab.com/lmcnulty/bmp-encoder"&gt;For the impatient, here's the
    end product&lt;/a&gt;. For everyone else, let's walk through the problem together.&lt;/p&gt;
    &lt;h2 id="dissecting-a-bmp"&gt;Dissecting a BMP&lt;/h2&gt; &lt;p&gt;Before we begin coding,
    let's start by looking inside an existing BMP file. Here's the one we'll be starting with:
    &lt;img alt="a single red pixel"
    src="https://lmcnulty.me/words/bmp-output/1x1.bmp"/&gt;&lt;/p&gt; &lt;p&gt;Ok, maybe that's too
    hard to see. Let's scale it by 50x: &lt;img alt="a single red pixel" class="pixel" height="50"
    src="https://lmcnulty.me/words/bmp-output/1x1.bmp" width="50"/&gt;&lt;/p&gt; &lt;p&gt;Yes, this
    is just a 1x1 pixel image with RGB color (239, 65, 53). I made it in GIMP, making sure to check
    "Do not write color space information" in the export dialogue.&lt;a class="footnote-ref"
    href="https://lmcnulty.me/words/bmp-output/#fn1" id="fnref1"
    role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; Now, let's look inside the file with
    &lt;code&gt;cat&lt;/code&gt; and see how it's made:&lt;/p&gt; &lt;div class="sourceCode"
    id="cb1"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span
    id="cb1-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb1-1"&gt;&lt;/a&gt;$ &lt;span
    class="fu"&gt;cat&lt;/span&gt; 1x1.bmp&lt;/span&gt; &lt;span id="cb1-2"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb1-2"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;BM&lt;/span&gt;:6(#.#.5A�&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Oh yeah. This is a binary file. So to see inside it, we'll need a different tool. For
    this, let's use the command &lt;code&gt;xxd&lt;/code&gt;. This will show us the byte data of a
    file in hexadecimal format. We'll use the &lt;code&gt;-g 1&lt;/code&gt; flag to group the data
    in 1-byte groups:&lt;/p&gt; &lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode
    bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb2-1"&gt;&lt;/a&gt;$ &lt;span
    class="ex"&gt;xxd&lt;/span&gt; -g 1 1x1.bmp &lt;/span&gt; &lt;span id="cb2-2"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb2-2"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;00000000&lt;/span&gt;: 42 4d 3a 00 00 00 00 00 00 00 36 00 00 00 28 00
    BM:.......6...(.&lt;/span&gt; &lt;span id="cb2-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb2-3"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;00000010&lt;/span&gt;: 00 00 01 00 00 00 01 00 00 00 01 00 18 00 00 00
    ................&lt;/span&gt; &lt;span id="cb2-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb2-4"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;00000020&lt;/span&gt;: 00 00 04 00 00 00 23 2e 00 00 23 2e 00 00 00 00
    ......#...#.....&lt;/span&gt; &lt;span id="cb2-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb2-5"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;00000030&lt;/span&gt;: 00 00 00 00 00 00 35 41 ef 00
    ......5A..&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p&gt;This is better, but how
    do we read it?&lt;/p&gt; &lt;p&gt;The most import part is in the center, starting with
    &lt;code&gt;42&lt;/code&gt; &lt;code&gt;4d&lt;/code&gt;… and ending with
    …&lt;code&gt;ef&lt;/code&gt; &lt;code&gt;00&lt;/code&gt;. This is the byte-data of the file in
    hexadecimal format. As a reminder, hexadecimal is a base-sixteen representation of a number
    using a-f for the digits after 9. Some people can easily convert between hexadecimal and
    decimal in their heads, but for the rest of us, there's &lt;code&gt;printf&lt;/code&gt;. Let's
    convert the &lt;code&gt;42&lt;/code&gt; and &lt;code&gt;4d&lt;/code&gt; to decimal:&lt;/p&gt;
    &lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code
    class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb3-1"&gt;&lt;/a&gt;$ &lt;span
    class="bu"&gt;printf&lt;/span&gt; &lt;span class="st"&gt;"%d"&lt;/span&gt; 0x42&lt;/span&gt;
    &lt;span id="cb3-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb3-2"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;66&lt;/span&gt;&lt;/span&gt; &lt;span id="cb3-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb3-3"&gt;&lt;/a&gt;$ &lt;span
    class="bu"&gt;printf&lt;/span&gt; &lt;span class="st"&gt;"%d"&lt;/span&gt; 0x4d&lt;/span&gt;
    &lt;span id="cb3-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb3-4"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;77&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; &lt;p&gt;These
    numbers are the &lt;a href="https://www.ascii-code.com/"&gt;ascii codes&lt;/a&gt; for 'B' and
    'M', which appear at the start of every BMP file to indicate its format. You'll notice that
    these letters also appear on the right-hand side of the &lt;code&gt;xxd&lt;/code&gt; output:
    it's just a representation of the same data in ascii. We won't need to worry about it too much,
    since most of our data is not in ascii format. Finally, on the left-hand side, we have
    &lt;code&gt;000000xx:&lt;/code&gt;. These are just the indices in hexadecimal. There are 16
    columns in each row of bytes, so the numbering increases 0x10 in each row.&lt;/p&gt;
    &lt;p&gt;Now that we know how to read the &lt;code&gt;xxd&lt;/code&gt; output, let's try and
    interpret the byte data. In principle we should be looking at &lt;a
    href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wmf/4813e7fd-52d0-4f42-965f-228c8b7488d2"&gt;the
    specification&lt;/a&gt;, but that will be boring… so lets just go to the &lt;a
    href="https://en.wikipedia.org/wiki/BMP_file_format#File_structure"&gt;Wikipedia
    article&lt;/a&gt;, which tells us that every BMP file starts with a 14-byte header. Let's mark
    that in blue:&lt;/p&gt; &lt;pre&gt; &lt;span style="color: blue"&gt;42 4d 3a 00 00 00 00 00 00
    00 36 00 00 00&lt;/span&gt; 28 00 00 00 01 00 00 00 01 00 00 00 01 00 18 00 00 00 00 00 04 00
    00 00 23 2e 00 00 23 2e 00 00 00 00 00 00 00 00 00 00 35 41 ef 00 &lt;/pre&gt; &lt;p&gt;The
    middle of the file is a little complicated, so for now let's skip to the last part: the pixel
    array. Each pixel is three bytes, one for each color. Since BMP is a Microsoft format and
    Microsoft likes doing things backwards, the order of the bytes is normally Blue, Green, Red,
    starting at the bottom-left pixel of the image. Each row of pixels gets zero-padded to a
    multiple of four bytes. We have one row of one pixel, so it will be three bytes padded to four.
    Thus, our pixel array will by the last four bytes of the file. Let's just confirm that
    &lt;code&gt;35 41 ef&lt;/code&gt; matches the colors we chose at the beginning: which were
    (239, 65, 53)&lt;/p&gt; &lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode
    bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb4-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb4-1"&gt;&lt;/a&gt;$ &lt;span
    class="bu"&gt;printf&lt;/span&gt; &lt;span class="st"&gt;"%d %d %d"&lt;/span&gt; 0x35 0x41
    0xef&lt;/span&gt; &lt;span id="cb4-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb4-2"&gt;&lt;/a&gt;&lt;span
    class="ex"&gt;53&lt;/span&gt; 65 239&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Great, it matches. Not coincidentally, &lt;span style="color: #ef4135"&gt;this is the
    color we get if we add&lt;/span&gt; &lt;code&gt;color: #ef4135&lt;/code&gt; in CSS. Let's use
    it to mark the pixel array in our &lt;code&gt;xxd&lt;/code&gt; output:&lt;/p&gt; &lt;pre&gt;
    &lt;span style="color: blue"&gt;42 4d 3a 00 00 00 00 00 00 00 36 00 00 00&lt;/span&gt; 28 00 00
    00 01 00 00 00 01 00 00 00 01 00 18 00 00 00 00 00 04 00 00 00 23 2e 00 00 23 2e 00 00 00 00 00
    00 00 00 00 00 &lt;span style="color: #ef4135"&gt;35 41 ef 00&lt;/span&gt; &lt;/pre&gt;
    &lt;p&gt;In-between the header and the pixel data, we have 40 bytes. This matches the size of a
    DIB header in &lt;code&gt;BITMAPINFOHEADER&lt;/code&gt; format, so it's probably safe to assume
    that this is what we have. Let's mark it in green:&lt;/p&gt; &lt;pre&gt; &lt;span style="color:
    blue"&gt;42 4d 3a 00 00 00 00 00 00 00 36 00 00 00&lt;/span&gt; &lt;span style="color:
    green"&gt;28 00 00 00 01 00 00 00 01 00 00 00 01 00 18 00 00 00 00 00 04 00 00 00 23 2e 00 00
    23 2e 00 00 00 00 00 00 00 00 00 00 &lt;/span&gt;&lt;span style="color: red"&gt;35 41 ef
    00&lt;/span&gt; &lt;/pre&gt; &lt;p&gt;Great. Now that we've got a basic understanding of the
    format, let's lay the groundwork for our C code.&lt;/p&gt; &lt;h2
    id="starting-with-c-the-bmp-header"&gt;Starting with C — The BMP Header&lt;/h2&gt;
    &lt;p&gt;Let's try and write a program that will output an identical 1×1 BMP file. Here's what
    we'll start with:&lt;/p&gt; &lt;div class="sourceCode" id="cb5"&gt;&lt;pre class="sourceCode
    c"&gt;&lt;code class="sourceCode c"&gt;&lt;span id="cb5-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb5-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-2"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdlib.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb5-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-3"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;int&lt;/span&gt; main() {&lt;/span&gt; &lt;span id="cb5-4"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-4"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb5-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-5"&gt;&lt;/a&gt; &lt;span class="co"&gt;// Make
    an array containing the B and M characters that&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb5-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-6"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    identify the file as a BMP.&lt;/span&gt;&lt;/span&gt; &lt;span id="cb5-7"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb5-7"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; tag[] = { &lt;span class="ch"&gt;'B'&lt;/span&gt;, &lt;span
    class="ch"&gt;'M'&lt;/span&gt; };&lt;/span&gt; &lt;span id="cb5-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-8"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb5-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-9"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;FILE&lt;/span&gt; 
    <em>fp = fopen(&lt;span class="st"&gt;"test.bmp"&lt;/span&gt;, &lt;span
    class="st"&gt;"w+"&lt;/span&gt;); &lt;span class="co"&gt;// Open a file for
    writing&lt;/span&gt;&lt;/span&gt; &lt;span id="cb5-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-10"&gt;&lt;/a&gt; fwrite(&amp;tag, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(tag), &lt;span class="dv"&gt;1&lt;/span&gt;, fp); &lt;span
    class="co"&gt;// Write the tag to the file&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb5-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-11"&gt;&lt;/a&gt; fclose(fp); &lt;span
    class="co"&gt;// Close the file&lt;/span&gt;&lt;/span&gt; &lt;span id="cb5-12"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb5-12"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;If we run this now, it will output the first two bytes of the BMP header. Let's add
    the rest. According to Wikipedia, the rest of the header consists of:&lt;/p&gt; &lt;ul&gt;
    &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; The size of the BMP file in bytes&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; Reserved; actual value depends on the
    application that creates the image&lt;/li&gt; &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt;
    The offset, i.e.&#160;starting address, of the byte where the bitmap image data (pixel array)
    can be found.&lt;/li&gt; &lt;/ul&gt; &lt;p&gt;We'll figure out how to calculate the size and
    offset later. But for now, let's just copy what we got from the &lt;code&gt;xxd&lt;/code&gt;
    output.&lt;/p&gt; &lt;pre&gt; 00000000: &lt;span style="color: blue"&gt;42 4d &lt;strong&gt;3a
    00 00 00&lt;/strong&gt; &lt;em&gt;00 00 00 00&lt;/em&gt; &lt;strong&gt;36 00 00
    00&lt;/strong&gt;&lt;/span&gt; 28 00 BM:.......6...(. &lt;/pre&gt; &lt;p&gt;These are all
    integers, so we'll add a new &lt;code&gt;int&lt;/code&gt; array to our C code and write it to
    the file. To represent a hexadecimal number in C, you put &lt;code&gt;0x&lt;/code&gt; before
    it. Note that we write &lt;code&gt;0x3a&lt;/code&gt; rather than
    &lt;code&gt;0x0000003a&lt;/code&gt; because the file data is stored in little-endian format,
    where the least-significant bit comes first, whereas in C, we write the hex numbers in
    big-endian format. If this is confusing, think about how dates are written differently in
    various parts of the world. Europeans write dates in Day-Month-Year format, where the smallest
    unit comes first. The Chinese, by contrast, write dates in Year-Month-Day format, where the
    biggest unit comes first.&lt;a class="footnote-ref"
    href="https://lmcnulty.me/words/bmp-output/#fn2" id="fnref2"
    role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; The dates are the same, whether it's
    03-28-2020 or 2020-28-03; the former is just in big-endian and the latter in little-endian. The
    same is true with hex numbers: &lt;code&gt;0x3a000000&lt;/code&gt; in little endian equals
    &lt;code&gt;0x0000003a&lt;/code&gt; in big endian.&lt;/p&gt; &lt;div class="sourceCode"
    id="cb6"&gt;&lt;pre class="sourceCode c"&gt;&lt;code class="sourceCode c"&gt;&lt;span
    id="cb6-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb6-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-2"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdlib.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb6-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-3"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;int&lt;/span&gt; main() {&lt;/span&gt; &lt;span id="cb6-4"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb6-4"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; tag[] = { &lt;span class="ch"&gt;'B'&lt;/span&gt;, &lt;span
    class="ch"&gt;'M'&lt;/span&gt; };&lt;/span&gt; &lt;span id="cb6-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-5"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb6-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-6"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Create an integer array for the header &lt;/span&gt;&lt;/span&gt; &lt;span id="cb6-7"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb6-7"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; header[] = {&lt;/span&gt; &lt;span id="cb6-8"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb6-8"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x3a&lt;/span&gt;, &lt;span class="co"&gt;// File Size&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb6-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-9"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x00&lt;/span&gt;, &lt;span class="co"&gt;// Unused&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb6-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-10"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x36&lt;/span&gt; &lt;span class="co"&gt;// Byte offset of pixel
    data&lt;/span&gt;&lt;/span&gt; &lt;span id="cb6-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-11"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb6-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-12"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb6-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-13"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;FILE&lt;/span&gt;</em>fp = fopen(&lt;span class="st"&gt;"test.bmp"&lt;/span&gt;,
    &lt;span class="st"&gt;"w+"&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb6-14"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb6-14"&gt;&lt;/a&gt;
    fwrite(&amp;tag, &lt;span class="kw"&gt;sizeof&lt;/span&gt;(tag), &lt;span
    class="dv"&gt;1&lt;/span&gt;, fp);&lt;/span&gt; &lt;span id="cb6-15"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb6-15"&gt;&lt;/a&gt;
    fwrite(&amp;header, &lt;span class="kw"&gt;sizeof&lt;/span&gt;(header), &lt;span
    class="dv"&gt;1&lt;/span&gt;, fp); &lt;span class="co"&gt;// Write the header to
    disk&lt;/span&gt;&lt;/span&gt; &lt;span id="cb6-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-16"&gt;&lt;/a&gt; fclose(fp);&lt;/span&gt;
    &lt;span id="cb6-17"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb6-17"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;h2 id="the-dib-header"&gt;The DIB Header&lt;/h2&gt; &lt;p&gt;Great. Now that we've made our
    way through the BMP header, we need to write the DIB header. This will specify more information
    needed to display the image. It can be in various formats, but we saw above that we're using
    the 40-byte &lt;code&gt;BITMAPINFOHEADER&lt;/code&gt;. So again, let's check each field against
    our &lt;code&gt;xxd&lt;/code&gt; output:&lt;/p&gt; &lt;pre&gt; &lt;span style="color:
    blue"&gt;42 4d 3a 00 00 00 00 00 00 00 36 00 00 00&lt;/span&gt; &lt;span style="color:
    green"&gt;&lt;strong&gt;28 00 00 00&lt;/strong&gt; &lt;em&gt;01 00 00 00&lt;/em&gt;
    &lt;strong&gt;01 00 00 00&lt;/strong&gt; &lt;em&gt;01 00&lt;/em&gt; &lt;strong&gt;18
    00&lt;/strong&gt; &lt;em&gt;00 00 00 00&lt;/em&gt; &lt;strong&gt;04 00 00 00&lt;/strong&gt;
    &lt;em&gt;23 2e 00 00&lt;/em&gt; &lt;strong&gt;23 2e 00 00&lt;/strong&gt; &lt;em&gt;00 00 00
    00&lt;/em&gt; &lt;strong&gt;00 00 00 00&lt;/strong&gt; &lt;/span&gt;&lt;span style="color:
    red"&gt;35 41 ef 00&lt;/span&gt; &lt;/pre&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;4
    bytes&lt;/strong&gt; - The size of this header, in bytes: &lt;code&gt;28 00 00 00&lt;/code&gt;.
    &lt;ul&gt; &lt;li&gt;This is 40 bytes in hexadecimal. Our header will remain the same
    length.&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; - The
    bitmap width in pixels: &lt;code&gt;01 00 00 00&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; - The bitmap height in pixels: &lt;code&gt;01 00
    00 00&lt;/code&gt;. &lt;ul&gt; &lt;li&gt;Instead of copying directly, we should output
    &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; variables.&lt;/li&gt;
    &lt;/ul&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;2 bytes&lt;/strong&gt; - The number of color
    planes (must be 1): &lt;code&gt;01 00&lt;/code&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;2
    bytes&lt;/strong&gt; - the number of bits per pixel: &lt;code&gt;18 00&lt;/code&gt; &lt;ul&gt;
    &lt;li&gt;We will combine these into a single integer so that we can store it in the same
    array.&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; - The
    compression method being used: &lt;code&gt;00 00 00 00&lt;/code&gt; &lt;ul&gt; &lt;li&gt;0
    means no compression&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;4
    bytes&lt;/strong&gt; - The image size (in bytes): &lt;code&gt;04 00 00 00&lt;/code&gt;
    &lt;ul&gt; &lt;li&gt;This is actually ignored for images without compression, so we can just
    use 0.&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; - The
    horizontal resolution of the image: &lt;code&gt;23 2e 00 00&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; - The vertical resolution of the image:
    &lt;code&gt;23 2e 00 00&lt;/code&gt; &lt;ul&gt; &lt;li&gt;As far as I can tell, these only
    matter for printing. We'll just use what Gimp gave us.&lt;/li&gt; &lt;/ul&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; - the number of colors in the color palette, or
    0 to default to 2&lt;sup&gt;n&lt;/sup&gt;: &lt;code&gt;00 00 00 00&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;&lt;strong&gt;4 bytes&lt;/strong&gt; - the number of important colors used, or 0 when
    every color is important; generally ignored: &lt;code&gt;00 00 00 00&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt; &lt;p&gt;Adding all of these to our C code, we get:&lt;/p&gt; &lt;div
    class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode c"&gt;&lt;code class="sourceCode
    c"&gt;&lt;span id="cb7-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb7-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-2"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdlib.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb7-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-3"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;int&lt;/span&gt; main() {&lt;/span&gt; &lt;span id="cb7-4"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-4"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb7-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-5"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; width = &lt;span class="dv"&gt;1&lt;/span&gt;; &lt;span
    class="co"&gt;// Keep these in variables, since&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb7-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-6"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; height = &lt;span class="dv"&gt;1&lt;/span&gt;; &lt;span
    class="co"&gt;// they'll change later.&lt;/span&gt;&lt;/span&gt; &lt;span id="cb7-7"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-7"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb7-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-8"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; tag[] = { &lt;span class="ch"&gt;'B'&lt;/span&gt;, &lt;span
    class="ch"&gt;'M'&lt;/span&gt; };&lt;/span&gt; &lt;span id="cb7-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-9"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; header[] = {&lt;/span&gt; &lt;span id="cb7-10"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb7-10"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x3a&lt;/span&gt;, &lt;span class="bn"&gt;0x00&lt;/span&gt;, &lt;span
    class="bn"&gt;0x36&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb7-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-11"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x28&lt;/span&gt;, &lt;span class="co"&gt;// Header
    Size&lt;/span&gt;&lt;/span&gt; &lt;span id="cb7-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-12"&gt;&lt;/a&gt; width, height, &lt;span
    class="co"&gt;// Image dimensions in pixels&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb7-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-13"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x180001&lt;/span&gt;, &lt;span class="co"&gt;// 24 bits/pixel, 1 color
    plane&lt;/span&gt;&lt;/span&gt; &lt;span id="cb7-14"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-14"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="co"&gt;// BI_RGB no
    compression&lt;/span&gt;&lt;/span&gt; &lt;span id="cb7-15"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-15"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="co"&gt;// Pixel data size in
    bytes&lt;/span&gt;&lt;/span&gt; &lt;span id="cb7-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-16"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span
    class="co"&gt;// Print resolution&lt;/span&gt;&lt;/span&gt; &lt;span id="cb7-17"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb7-17"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span class="co"&gt;//
    No color palette&lt;/span&gt;&lt;/span&gt; &lt;span id="cb7-18"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-18"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb7-19"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-19"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb7-20"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-20"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;FILE&lt;/span&gt; 
    <em>fp = fopen(&lt;span class="st"&gt;"test.bmp"&lt;/span&gt;, &lt;span
    class="st"&gt;"w+"&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb7-21"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-21"&gt;&lt;/a&gt; fwrite(&amp;tag, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(tag), &lt;span class="dv"&gt;1&lt;/span&gt;,
    fp);&lt;/span&gt; &lt;span id="cb7-22"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-22"&gt;&lt;/a&gt; fwrite(&amp;header, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(header), &lt;span class="dv"&gt;1&lt;/span&gt;, fp);
    &lt;/span&gt; &lt;span id="cb7-23"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-23"&gt;&lt;/a&gt; fclose(fp);&lt;/span&gt;
    &lt;span id="cb7-24"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb7-24"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;h2 id="the-pixel-data"&gt;The Pixel Data&lt;/h2&gt; &lt;p&gt;Finally, we need to output an
    array of pixels. Recall that each pixel is represented by its B, G, and R values, and each row
    is padded to a multiple of 4 bytes. Since we have one pixel, that means we'll be outputting an
    array of 4 bytes.&lt;/p&gt; &lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode
    c"&gt;&lt;code class="sourceCode c"&gt;&lt;span id="cb8-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-1"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb8-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-2"&gt;&lt;/a&gt;&lt;span class="pp"&gt;#include
    &lt;/span&gt;&lt;span class="im"&gt;&lt;stdlib.h&gt;&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb8-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-3"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;int&lt;/span&gt; main() {&lt;/span&gt; &lt;span id="cb8-4"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-4"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; width = &lt;span class="dv"&gt;1&lt;/span&gt;; &lt;/span&gt;
    &lt;span id="cb8-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-5"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; height = &lt;span class="dv"&gt;1&lt;/span&gt;;&lt;/span&gt;
    &lt;span id="cb8-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-6"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; tag[] = { &lt;span class="ch"&gt;'B'&lt;/span&gt;, &lt;span
    class="ch"&gt;'M'&lt;/span&gt; };&lt;/span&gt; &lt;span id="cb8-7"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-7"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; header[] = {&lt;/span&gt; &lt;span id="cb8-8"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-8"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x3a&lt;/span&gt;, &lt;span class="bn"&gt;0x00&lt;/span&gt;, &lt;span
    class="bn"&gt;0x36&lt;/span&gt;, &lt;span class="bn"&gt;0x28&lt;/span&gt;, width, height,
    &lt;span class="bn"&gt;0x180001&lt;/span&gt;, &lt;/span&gt; &lt;span id="cb8-9"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-9"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt; &lt;/span&gt; &lt;span
    id="cb8-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-10"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb8-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-11"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb8-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-12"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Store as char array, because we want each value to take up&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb8-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-13"&gt;&lt;/a&gt; &lt;span class="co"&gt;// one
    byte.&lt;/span&gt;&lt;/span&gt; &lt;span id="cb8-14"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-14"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; bitmap[] = {&lt;/span&gt; &lt;span id="cb8-15"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-15"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x35&lt;/span&gt;, &lt;span class="co"&gt;// Blue&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb8-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-16"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x41&lt;/span&gt;, &lt;span class="co"&gt;// Green&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb8-17"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-17"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0xef&lt;/span&gt;, &lt;span class="co"&gt;// Red&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb8-18"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-18"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x00&lt;/span&gt; &lt;span class="co"&gt;// Padding&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb8-19"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-19"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb8-20"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-20"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb8-21"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-21"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;FILE&lt;/span&gt;</em>fp = fopen(&lt;span class="st"&gt;"test.bmp"&lt;/span&gt;,
    &lt;span class="st"&gt;"w+"&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb8-22"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-22"&gt;&lt;/a&gt;
    fwrite(&amp;tag, &lt;span class="kw"&gt;sizeof&lt;/span&gt;(tag), &lt;span
    class="dv"&gt;1&lt;/span&gt;, fp);&lt;/span&gt; &lt;span id="cb8-23"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-23"&gt;&lt;/a&gt;
    fwrite(&amp;header, &lt;span class="kw"&gt;sizeof&lt;/span&gt;(header), &lt;span
    class="dv"&gt;1&lt;/span&gt;, fp); &lt;/span&gt; &lt;span id="cb8-24"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-24"&gt;&lt;/a&gt;
    fwrite(&amp;bitmap, &lt;span class="kw"&gt;sizeof&lt;/span&gt;(bitmap), &lt;span
    class="dv"&gt;1&lt;/span&gt;, fp);&lt;/span&gt; &lt;span id="cb8-25"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb8-25"&gt;&lt;/a&gt;
    fclose(fp);&lt;/span&gt; &lt;span id="cb8-26"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb8-26"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Alright, now let's run the program and see what we get:&lt;/p&gt; &lt;p&gt;&lt;img
    alt="A single red pixel" class="pixel" height="50"
    src="https://lmcnulty.me/words/bmp-output/test.bmp" width="50"/&gt;&lt;br/&gt; &lt;/p&gt;
    &lt;p&gt;Yay! Let's try and change the color:&lt;/p&gt; &lt;div class="sourceCode"
    id="cb9"&gt;&lt;pre class="sourceCode c"&gt;&lt;code class="sourceCode c"&gt;&lt;span
    id="cb9-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb9-1"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;char&lt;/span&gt; bitmap[] = {&lt;/span&gt; &lt;span id="cb9-2"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb9-2"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0xa4&lt;/span&gt;, &lt;span class="co"&gt;// Blue&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb9-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb9-3"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x55&lt;/span&gt;, &lt;span class="co"&gt;// Green&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb9-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb9-4"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x00&lt;/span&gt;, &lt;span class="co"&gt;// Red&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb9-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb9-5"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x00&lt;/span&gt; &lt;span class="co"&gt;// Padding&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb9-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb9-6"&gt;&lt;/a&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;&lt;img alt="A single navy blue pixel" class="pixel" height="50"
    src="https://lmcnulty.me/words/bmp-output/test2.bmp" width="50"/&gt;&lt;br/&gt; &lt;/p&gt;
    &lt;p&gt;Hurrah!&lt;/p&gt; &lt;h2 id="generalizing"&gt;Generalizing&lt;/h2&gt; &lt;p&gt;Ok, so
    now we know how to output a valid BMP file. But sometime we might want to output a different
    image, maybe even one with more than one pixel. So let's refactor our
    &lt;code&gt;main&lt;/code&gt; into a function that outputs a given RGB array to a
    file.&lt;/p&gt; &lt;p&gt;The pixel data is stored in a 1D array – this might seem
    counter-intuitive for a 2D image, but it's the normal way of handling pixel data in computer
    graphics, because it's more efficient and saves us from having to deal with pointers to arrays.
    Since the pixel data is 1D, in addition to passing its length as an argument (as C doesn't
    automatically track array lengths), we also need the width of the image so we know where each
    new row starts.&lt;/p&gt; &lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode
    c"&gt;&lt;code class="sourceCode c"&gt;&lt;span id="cb10-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-1"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;void&lt;/span&gt; write_bmp(&lt;span class="dt"&gt;char&lt;/span&gt; 
    <em>filename, &lt;span class="dt"&gt;char&lt;/span&gt; rgb[], &lt;span
    class="dt"&gt;int&lt;/span&gt; length, &lt;span class="dt"&gt;int&lt;/span&gt; width)
    {&lt;/span&gt; &lt;span id="cb10-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-2"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-3"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Calculate the image height from its width and the array length&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb10-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-4"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; height = (length / &lt;span class="dv"&gt;3&lt;/span&gt;) /
    width;&lt;/span&gt; &lt;span id="cb10-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-5"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-6"&gt;&lt;/a&gt; &lt;span class="co"&gt;// The
    size of the pixel data. For now, use width + 1 to handle &lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb10-7"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-7"&gt;&lt;/a&gt; &lt;span class="co"&gt;// row
    padding.&lt;/span&gt;&lt;/span&gt; &lt;span id="cb10-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-8"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; bitmap_size = &lt;span class="dv"&gt;3&lt;/span&gt;</em>height *
    (width + &lt;span class="dv"&gt;1&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb10-9"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-9"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-10"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    The pixel data is now variable-length, so we need to use&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb10-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-11"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    malloc.&lt;/span&gt;&lt;/span&gt; &lt;span id="cb10-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-12"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; 
    <em>bitmap = (&lt;span class="dt"&gt;char&lt;/span&gt;</em>) malloc(bitmap_size * &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(&lt;span class="dt"&gt;char&lt;/span&gt;));&lt;/span&gt;
    &lt;span id="cb10-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-13"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-14"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-14"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Zeroing out the data will set all the pixels to black.&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb10-15"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-15"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; i = &lt;span
    class="dv"&gt;0&lt;/span&gt;; i &lt; bitmap_size; i++) bitmap[i] = &lt;span
    class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb10-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-16"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-17"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-17"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; tag[] = { &lt;span class="ch"&gt;'B'&lt;/span&gt;, &lt;span
    class="ch"&gt;'M'&lt;/span&gt; };&lt;/span&gt; &lt;span id="cb10-18"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb10-18"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; header[] = {&lt;/span&gt; &lt;span id="cb10-19"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb10-19"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="co"&gt;// File size... update at the
    end.&lt;/span&gt;&lt;/span&gt; &lt;span id="cb10-20"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-20"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="bn"&gt;0x36&lt;/span&gt;, &lt;span
    class="bn"&gt;0x28&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb10-21"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-21"&gt;&lt;/a&gt; width, height, &lt;span
    class="co"&gt;// Image dimensions in pixels&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb10-22"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-22"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-23"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-23"&gt;&lt;/a&gt; &lt;span
    class="bn"&gt;0x180001&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span
    class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="dv"&gt;0&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb10-24"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-24"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb10-25"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-25"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Update file size: just the sum of the sizes of the arrays&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb10-26"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-26"&gt;&lt;/a&gt; &lt;span class="co"&gt;// we
    write to disk.&lt;/span&gt;&lt;/span&gt; &lt;span id="cb10-27"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-27"&gt;&lt;/a&gt; header[&lt;span
    class="dv"&gt;0&lt;/span&gt;] = &lt;span class="kw"&gt;sizeof&lt;/span&gt;(tag) + &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(header) + bitmap_size;&lt;/span&gt; &lt;span
    id="cb10-28"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-28"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-29"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-29"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;FILE&lt;/span&gt; 
    <em>fp = fopen(filename, &lt;span class="st"&gt;"w+"&lt;/span&gt;);&lt;/span&gt; &lt;span
    id="cb10-30"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-30"&gt;&lt;/a&gt; fwrite(&amp;tag, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(tag), &lt;span class="dv"&gt;1&lt;/span&gt;,
    fp);&lt;/span&gt; &lt;span id="cb10-31"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-31"&gt;&lt;/a&gt; fwrite(&amp;header, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(header), &lt;span class="dv"&gt;1&lt;/span&gt;,
    fp);&lt;/span&gt; &lt;span id="cb10-32"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-32"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb10-33"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-33"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Malloc returns a pointer, so we no longer need to get the&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb10-34"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-34"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    adress of bitmap&lt;/span&gt;&lt;/span&gt; &lt;span id="cb10-35"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-35"&gt;&lt;/a&gt; fwrite(bitmap,
    bitmap_size</em>&lt;span class="kw"&gt;sizeof&lt;/span&gt;(&lt;span
    class="dt"&gt;char&lt;/span&gt;), &lt;span class="dv"&gt;1&lt;/span&gt;, fp);&lt;/span&gt;
    &lt;span id="cb10-36"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-36"&gt;&lt;/a&gt; fclose(fp);&lt;/span&gt;
    &lt;span id="cb10-37"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-37"&gt;&lt;/a&gt; &lt;/span&gt; &lt;span
    id="cb10-38"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-38"&gt;&lt;/a&gt; free(bitmap);&lt;/span&gt;
    &lt;span id="cb10-39"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb10-39"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Now that we've got that, let's try calling it on an RGB array. For no particular
    reason, let's try and output this 3×2 pixel image:&lt;/p&gt; &lt;p&gt;&lt;img alt="The french
    flag" class="flag" src="https://lmcnulty.me/words/bmp-output/french_flag.bmp"
    width="150"/&gt;&lt;br/&gt; &lt;/p&gt; &lt;div class="sourceCode" id="cb11"&gt;&lt;pre
    class="sourceCode c"&gt;&lt;code class="sourceCode c"&gt;&lt;span id="cb11-1"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb11-1"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;int&lt;/span&gt; main() {&lt;/span&gt; &lt;span id="cb11-2"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb11-2"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; fr[] = {&lt;/span&gt; &lt;span id="cb11-3"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb11-3"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;85&lt;/span&gt;, &lt;span
    class="dv"&gt;164&lt;/span&gt;, &lt;span class="co"&gt;// Bleu&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb11-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-4"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;255&lt;/span&gt;, &lt;span class="dv"&gt;255&lt;/span&gt;, &lt;span
    class="dv"&gt;255&lt;/span&gt;, &lt;span class="co"&gt;// Blanc&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb11-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-5"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;239&lt;/span&gt;, &lt;span class="dv"&gt;65&lt;/span&gt;, &lt;span
    class="dv"&gt;53&lt;/span&gt;, &lt;span class="co"&gt;// Rouge&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb11-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-6"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;85&lt;/span&gt;, &lt;span
    class="dv"&gt;164&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb11-7"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-7"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;255&lt;/span&gt;, &lt;span class="dv"&gt;255&lt;/span&gt;, &lt;span
    class="dv"&gt;255&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb11-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-8"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;239&lt;/span&gt;, &lt;span class="dv"&gt;65&lt;/span&gt;, &lt;span
    class="dv"&gt;53&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb11-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-9"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb11-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-10"&gt;&lt;/a&gt; write_bmp(&lt;span
    class="st"&gt;"french_flag.bmp"&lt;/span&gt;, fr, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(fr) / &lt;span class="kw"&gt;sizeof&lt;/span&gt;(&lt;span
    class="dt"&gt;char&lt;/span&gt;), &lt;span class="dv"&gt;3&lt;/span&gt;);&lt;/span&gt; &lt;span
    id="cb11-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb11-11"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Run that program and we get:&lt;/p&gt; &lt;p&gt;&lt;img alt="An image with the aspect
    ratio of the above French flag, but entirely black" class="flag"
    src="https://lmcnulty.me/words/bmp-output/french_flag_black.bmp" width="150"/&gt;&lt;br/&gt;
    &lt;/p&gt; &lt;p&gt;Ok, so we've got the dimensions right. Now all we need to do is copy the
    RGB data into the &lt;code&gt;bitmap&lt;/code&gt; array in the correct order (BGR) and with the
    correct padding.&lt;/p&gt; &lt;div class="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode
    c"&gt;&lt;code class="sourceCode c"&gt;&lt;span id="cb12-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;//
    Function to round an int to a multiple of 4&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb12-2"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-2"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;int&lt;/span&gt; round4(&lt;span class="dt"&gt;int&lt;/span&gt; x) {&lt;/span&gt;
    &lt;span id="cb12-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-3"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;return&lt;/span&gt; x % &lt;span class="dv"&gt;4&lt;/span&gt; == &lt;span
    class="dv"&gt;0&lt;/span&gt; ? x : x - x % &lt;span class="dv"&gt;4&lt;/span&gt; + &lt;span
    class="dv"&gt;4&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb12-4"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-4"&gt;&lt;/a&gt;}&lt;/span&gt; &lt;span
    id="cb12-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-5"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb12-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-6"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;void&lt;/span&gt; write_bmp(&lt;span class="dt"&gt;char&lt;/span&gt; 
    <em>filename, &lt;span class="dt"&gt;char&lt;/span&gt; rgb[], &lt;span
    class="dt"&gt;int&lt;/span&gt; length, &lt;span class="dt"&gt;int&lt;/span&gt; width)
    {&lt;/span&gt; &lt;span id="cb12-7"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-7"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; height = (length / &lt;span class="dv"&gt;3&lt;/span&gt;) /
    width;&lt;/span&gt; &lt;span id="cb12-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-8"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb12-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-9"&gt;&lt;/a&gt; &lt;span class="co"&gt;// Pad
    the width of the destination to a multiple of 4&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb12-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-10"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; padded_width = round4(width</em>&lt;span
    class="dv"&gt;3&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb12-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-11"&gt;&lt;/a&gt; &lt;/span&gt; &lt;span
    id="cb12-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-12"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; bitmap_size = height * padded_width * &lt;span
    class="dv"&gt;3&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb12-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-13"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; 
    <em>bitmap = (&lt;span class="dt"&gt;char&lt;/span&gt;</em>) malloc(bitmap_size * &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(&lt;span class="dt"&gt;char&lt;/span&gt;));&lt;/span&gt;
    &lt;span id="cb12-14"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-14"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; i = &lt;span
    class="dv"&gt;0&lt;/span&gt;; i &lt; bitmap_size; i++) bitmap[i] = &lt;span
    class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb12-15"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-15"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb12-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-16"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    For each pixel in the RGB image...&lt;/span&gt;&lt;/span&gt; &lt;span id="cb12-17"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb12-17"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; row = &lt;span
    class="dv"&gt;0&lt;/span&gt;; row &lt; height; row++) {&lt;/span&gt; &lt;span
    id="cb12-18"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-18"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; col = &lt;span
    class="dv"&gt;0&lt;/span&gt;; col &lt; width; col++) {&lt;/span&gt; &lt;span
    id="cb12-19"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-19"&gt;&lt;/a&gt; &lt;/span&gt; &lt;span
    id="cb12-20"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-20"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    For R, G, and B...&lt;/span&gt;&lt;/span&gt; &lt;span id="cb12-21"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-21"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; color = &lt;span
    class="dv"&gt;0&lt;/span&gt;; color &lt; &lt;span class="dv"&gt;3&lt;/span&gt;; color++)
    {&lt;/span&gt; &lt;span id="cb12-22"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-22"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb12-23"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-23"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Get the index of the destination image&lt;/span&gt;&lt;/span&gt; &lt;span id="cb12-24"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb12-24"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; index = row * padded_width + col * &lt;span
    class="dv"&gt;3&lt;/span&gt; + color;&lt;/span&gt; &lt;span id="cb12-25"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-25"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb12-26"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-26"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Set the destination to the value of the src at row, col.&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb12-27"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-27"&gt;&lt;/a&gt; bitmap[index] = rgb[&lt;span
    class="dv"&gt;3&lt;/span&gt;
    <em>(row</em>width + col) + (&lt;span class="dv"&gt;2&lt;/span&gt; - color)];&lt;/span&gt;
    &lt;span id="cb12-28"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-28"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb12-29"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-29"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb12-30"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-30"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb12-31"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-31"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb12-32"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-32"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; tag[] = { &lt;span class="ch"&gt;'B'&lt;/span&gt;, &lt;span
    class="ch"&gt;'M'&lt;/span&gt; };&lt;/span&gt; &lt;span id="cb12-33"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb12-33"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;int&lt;/span&gt; header[] = {&lt;/span&gt; &lt;span id="cb12-34"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb12-34"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="bn"&gt;0x36&lt;/span&gt;, &lt;span class="bn"&gt;0x28&lt;/span&gt;, width, height,
    &lt;span class="bn"&gt;0x180001&lt;/span&gt;, &lt;/span&gt; &lt;span id="cb12-35"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb12-35"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span class="bn"&gt;0x002e23&lt;/span&gt;, &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb12-36"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-36"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb12-37"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-37"&gt;&lt;/a&gt; header[&lt;span
    class="dv"&gt;0&lt;/span&gt;] = &lt;span class="kw"&gt;sizeof&lt;/span&gt;(tag) + &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(header) + bitmap_size;&lt;/span&gt; &lt;span
    id="cb12-38"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-38"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;FILE&lt;/span&gt; 
    <em>fp = fopen(filename, &lt;span class="st"&gt;"w+"&lt;/span&gt;);&lt;/span&gt; &lt;span
    id="cb12-39"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-39"&gt;&lt;/a&gt; fwrite(&amp;tag, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(tag), &lt;span class="dv"&gt;1&lt;/span&gt;,
    fp);&lt;/span&gt; &lt;span id="cb12-40"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-40"&gt;&lt;/a&gt; fwrite(&amp;header, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(header), &lt;span class="dv"&gt;1&lt;/span&gt;,
    fp);&lt;/span&gt; &lt;span id="cb12-41"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-41"&gt;&lt;/a&gt; fwrite(bitmap,
    bitmap_size</em>&lt;span class="kw"&gt;sizeof&lt;/span&gt;(&lt;span
    class="dt"&gt;char&lt;/span&gt;), &lt;span class="dv"&gt;1&lt;/span&gt;, fp);&lt;/span&gt;
    &lt;span id="cb12-42"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-42"&gt;&lt;/a&gt; fclose(fp);&lt;/span&gt;
    &lt;span id="cb12-43"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-43"&gt;&lt;/a&gt; free(bitmap);&lt;/span&gt;
    &lt;span id="cb12-44"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb12-44"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;Alright, that should do it. Now lets write out some flags (chosen for
    simplicity):&lt;/p&gt; &lt;div class="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode
    c"&gt;&lt;code class="sourceCode c"&gt;&lt;span id="cb13-1"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-1"&gt;&lt;/a&gt;&lt;span
    class="dt"&gt;int&lt;/span&gt; main() {&lt;/span&gt; &lt;span id="cb13-2"&gt;&lt;a
    aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-2"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb13-3"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-3"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; fr[] = {&lt;/span&gt; &lt;span id="cb13-4"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-4"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;85&lt;/span&gt;, &lt;span
    class="dv"&gt;164&lt;/span&gt;, &lt;span class="co"&gt;// Bleu&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb13-5"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-5"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;255&lt;/span&gt;, &lt;span class="dv"&gt;255&lt;/span&gt;, &lt;span
    class="dv"&gt;255&lt;/span&gt;, &lt;span class="co"&gt;// Blanc&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb13-6"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-6"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;239&lt;/span&gt;, &lt;span class="dv"&gt;65&lt;/span&gt;, &lt;span
    class="dv"&gt;53&lt;/span&gt;, &lt;span class="co"&gt;// Rouge&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb13-7"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-7"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;85&lt;/span&gt;, &lt;span
    class="dv"&gt;164&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb13-8"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-8"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;255&lt;/span&gt;, &lt;span class="dv"&gt;255&lt;/span&gt;, &lt;span
    class="dv"&gt;255&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb13-9"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-9"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;239&lt;/span&gt;, &lt;span class="dv"&gt;65&lt;/span&gt;, &lt;span
    class="dv"&gt;53&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb13-10"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-10"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb13-11"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-11"&gt;&lt;/a&gt; write_bmp(&lt;span
    class="st"&gt;"french_flag.bmp"&lt;/span&gt;, fr, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(fr) / &lt;span class="kw"&gt;sizeof&lt;/span&gt;(&lt;span
    class="dt"&gt;char&lt;/span&gt;), &lt;span class="dv"&gt;3&lt;/span&gt;);&lt;/span&gt; &lt;span
    id="cb13-12"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-12"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb13-13"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-13"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; bgm[] = {&lt;/span&gt; &lt;span id="cb13-14"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-14"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="co"&gt;// Black&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb13-15"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-15"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;253&lt;/span&gt;, &lt;span class="dv"&gt;218&lt;/span&gt;, &lt;span
    class="dv"&gt;36&lt;/span&gt;, &lt;span class="co"&gt;// Yellow&lt;/span&gt;&lt;/span&gt;
    &lt;span id="cb13-16"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-16"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;239&lt;/span&gt;, &lt;span class="dv"&gt;51&lt;/span&gt;, &lt;span
    class="dv"&gt;64&lt;/span&gt;, &lt;span class="co"&gt;// Red&lt;/span&gt;&lt;/span&gt; &lt;span
    id="cb13-17"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-17"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;0&lt;/span&gt;, &lt;span class="dv"&gt;0&lt;/span&gt;, &lt;span
    class="dv"&gt;0&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb13-18"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-18"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;253&lt;/span&gt;, &lt;span class="dv"&gt;218&lt;/span&gt;, &lt;span
    class="dv"&gt;36&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb13-19"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-19"&gt;&lt;/a&gt; &lt;span
    class="dv"&gt;239&lt;/span&gt;, &lt;span class="dv"&gt;51&lt;/span&gt;, &lt;span
    class="dv"&gt;64&lt;/span&gt;,&lt;/span&gt; &lt;span id="cb13-20"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-20"&gt;&lt;/a&gt; };&lt;/span&gt; &lt;span
    id="cb13-21"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-21"&gt;&lt;/a&gt; write_bmp(&lt;span
    class="st"&gt;"belgian_flag.bmp"&lt;/span&gt;, bgm, &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(bgm) / &lt;span class="kw"&gt;sizeof&lt;/span&gt;(&lt;span
    class="dt"&gt;char&lt;/span&gt;), &lt;span class="dv"&gt;3&lt;/span&gt;);&lt;/span&gt; &lt;span
    id="cb13-22"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-22"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb13-23"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-23"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Transgender Pride Flag&lt;/span&gt;&lt;/span&gt; &lt;span id="cb13-24"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-24"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; 
    <em>trans = (&lt;span class="dt"&gt;char&lt;/span&gt;</em>) malloc(&lt;span
    class="dv"&gt;8&lt;/span&gt; * &lt;span class="dv"&gt;5&lt;/span&gt;* &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(&lt;span class="dt"&gt;char&lt;/span&gt;) * &lt;span
    class="dv"&gt;3&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb13-25"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-25"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; row = &lt;span
    class="dv"&gt;0&lt;/span&gt;; row &lt; &lt;span class="dv"&gt;5&lt;/span&gt;; row++)
    {&lt;/span&gt; &lt;span id="cb13-26"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-26"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; col = &lt;span
    class="dv"&gt;0&lt;/span&gt;; col &lt; &lt;span class="dv"&gt;8&lt;/span&gt;; col++)
    {&lt;/span&gt; &lt;span id="cb13-27"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-27"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;if&lt;/span&gt; (row == &lt;span class="dv"&gt;0&lt;/span&gt; || row == &lt;span
    class="dv"&gt;4&lt;/span&gt;) {&lt;/span&gt; &lt;span id="cb13-28"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-28"&gt;&lt;/a&gt; trans[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; + col)] = &lt;span
    class="dv"&gt;91&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-29"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-29"&gt;&lt;/a&gt; trans[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;1&lt;/span&gt;] = &lt;span class="dv"&gt;207&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-30"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-30"&gt;&lt;/a&gt; trans[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;2&lt;/span&gt;] = &lt;span class="dv"&gt;250&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-31"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-31"&gt;&lt;/a&gt; } &lt;span
    class="cf"&gt;else&lt;/span&gt; &lt;span class="cf"&gt;if&lt;/span&gt; (row == &lt;span
    class="dv"&gt;1&lt;/span&gt; || row == &lt;span class="dv"&gt;3&lt;/span&gt;) {&lt;/span&gt;
    &lt;span id="cb13-32"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-32"&gt;&lt;/a&gt; trans[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; + col)] = &lt;span
    class="dv"&gt;245&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-33"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-33"&gt;&lt;/a&gt; trans[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;1&lt;/span&gt;] = &lt;span class="dv"&gt;171&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-34"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-34"&gt;&lt;/a&gt; trans[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;2&lt;/span&gt;] = &lt;span class="dv"&gt;185&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-35"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-35"&gt;&lt;/a&gt; } &lt;span
    class="cf"&gt;else&lt;/span&gt; {&lt;/span&gt; &lt;span id="cb13-36"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-36"&gt;&lt;/a&gt;
    trans[&lt;span class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; +
    col)] = &lt;span class="dv"&gt;255&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-37"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-37"&gt;&lt;/a&gt;
    trans[&lt;span class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; +
    col) + &lt;span class="dv"&gt;1&lt;/span&gt;] = &lt;span
    class="dv"&gt;255&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-38"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-38"&gt;&lt;/a&gt; trans[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;8&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;2&lt;/span&gt;] = &lt;span class="dv"&gt;255&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-39"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-39"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb13-40"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-40"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb13-41"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-41"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb13-42"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-42"&gt;&lt;/a&gt; write_bmp(&lt;span
    class="st"&gt;"trans_flag.bmp"&lt;/span&gt;, trans, &lt;span class="dv"&gt;3&lt;/span&gt;
    <em>&lt;span class="dv"&gt;5&lt;/span&gt;</em>&lt;span class="dv"&gt;8&lt;/span&gt;, &lt;span
    class="dv"&gt;8&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb13-43"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-43"&gt;&lt;/a&gt; &lt;/span&gt; &lt;span
    id="cb13-44"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-44"&gt;&lt;/a&gt; &lt;span class="co"&gt;//
    Flag of the United Arab Emirates&lt;/span&gt;&lt;/span&gt; &lt;span id="cb13-45"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-45"&gt;&lt;/a&gt; &lt;span
    class="dt"&gt;char&lt;/span&gt; 
    <em>uae = (&lt;span class="dt"&gt;char&lt;/span&gt;</em>) malloc(&lt;span
    class="dv"&gt;12&lt;/span&gt; * &lt;span class="dv"&gt;6&lt;/span&gt;* &lt;span
    class="kw"&gt;sizeof&lt;/span&gt;(&lt;span class="dt"&gt;char&lt;/span&gt;) * &lt;span
    class="dv"&gt;3&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb13-46"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-46"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; row = &lt;span
    class="dv"&gt;0&lt;/span&gt;; row &lt; &lt;span class="dv"&gt;6&lt;/span&gt;; row++)
    {&lt;/span&gt; &lt;span id="cb13-47"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-47"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;for&lt;/span&gt; (&lt;span class="dt"&gt;int&lt;/span&gt; col = &lt;span
    class="dv"&gt;0&lt;/span&gt;; col &lt; &lt;span class="dv"&gt;12&lt;/span&gt;; col++)
    {&lt;/span&gt; &lt;span id="cb13-48"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-48"&gt;&lt;/a&gt; &lt;span
    class="cf"&gt;if&lt;/span&gt; (col &lt; &lt;span class="dv"&gt;3&lt;/span&gt;) {&lt;/span&gt;
    &lt;span id="cb13-49"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-49"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col)] = &lt;span
    class="dv"&gt;255&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-50"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-50"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;1&lt;/span&gt;] = &lt;span class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-51"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-51"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;2&lt;/span&gt;] = &lt;span class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-52"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-52"&gt;&lt;/a&gt; } &lt;span
    class="cf"&gt;else&lt;/span&gt; &lt;span class="cf"&gt;if&lt;/span&gt; (row &lt; &lt;span
    class="dv"&gt;2&lt;/span&gt;) {&lt;/span&gt; &lt;span id="cb13-53"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-53"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col)] = &lt;span
    class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-54"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-54"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;1&lt;/span&gt;] = &lt;span class="dv"&gt;116&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-55"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-55"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;2&lt;/span&gt;] = &lt;span class="dv"&gt;33&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-56"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-56"&gt;&lt;/a&gt; } &lt;span
    class="cf"&gt;else&lt;/span&gt; &lt;span class="cf"&gt;if&lt;/span&gt; (row &lt; &lt;span
    class="dv"&gt;4&lt;/span&gt;) {&lt;/span&gt; &lt;span id="cb13-57"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-57"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col)] = &lt;span
    class="dv"&gt;255&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-58"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-58"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;1&lt;/span&gt;] = &lt;span class="dv"&gt;255&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-59"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-59"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;2&lt;/span&gt;] = &lt;span class="dv"&gt;255&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-60"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-60"&gt;&lt;/a&gt; } &lt;span
    class="cf"&gt;else&lt;/span&gt; {&lt;/span&gt; &lt;span id="cb13-61"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-61"&gt;&lt;/a&gt;
    uae[&lt;span class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; +
    col)] = &lt;span class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-62"&gt;&lt;a
    aria-hidden="true" href="https://lmcnulty.me/words/bmp-output/#cb13-62"&gt;&lt;/a&gt;
    uae[&lt;span class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; +
    col) + &lt;span class="dv"&gt;1&lt;/span&gt;] = &lt;span
    class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span id="cb13-63"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-63"&gt;&lt;/a&gt; uae[&lt;span
    class="dv"&gt;3&lt;/span&gt; * (row * &lt;span class="dv"&gt;12&lt;/span&gt; + col) + &lt;span
    class="dv"&gt;2&lt;/span&gt;] = &lt;span class="dv"&gt;0&lt;/span&gt;;&lt;/span&gt; &lt;span
    id="cb13-64"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-64"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb13-65"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-65"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb13-66"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-66"&gt;&lt;/a&gt; }&lt;/span&gt; &lt;span
    id="cb13-67"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-67"&gt;&lt;/a&gt; write_bmp(&lt;span
    class="st"&gt;"uae_flag.bmp"&lt;/span&gt;, uae, &lt;span class="dv"&gt;3&lt;/span&gt;
    <em>&lt;span class="dv"&gt;6&lt;/span&gt;</em>&lt;span class="dv"&gt;12&lt;/span&gt;, &lt;span
    class="dv"&gt;12&lt;/span&gt;);&lt;/span&gt; &lt;span id="cb13-68"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-68"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span
    id="cb13-69"&gt;&lt;a aria-hidden="true"
    href="https://lmcnulty.me/words/bmp-output/#cb13-69"&gt;&lt;/a&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;And there we have it:&lt;/p&gt; &lt;p&gt;&lt;img alt="The French flag" class="flag"
    height="100" src="https://lmcnulty.me/words/bmp-output/french_flag.bmp"/&gt; &lt;img alt="The
    Belgian flag" class="flag" height="100"
    src="https://lmcnulty.me/words/bmp-output/belgian_flag.bmp"/&gt; &lt;img alt="The trangender
    pride flag" class="flag" height="100"
    src="https://lmcnulty.me/words/bmp-output/trans_flag.bmp"/&gt; &lt;img alt="The flag of the
    United Arab Emirates" class="flag" height="100"
    src="https://lmcnulty.me/words/bmp-output/uae_flag.bmp"/&gt;&lt;/p&gt; &lt;h2
    id="limitations"&gt;Limitations&lt;/h2&gt; &lt;p&gt;This only produces uncompressed files. This
    is fine for the tiny images we're making: in fact, it beats most other formats in terms of disk
    usage at this size because of how little metadata we use. However, as the image size increases,
    we start to get very large file sizes: at 512×512, the output of this program is more than 100x
    the size of the same image converted to a lossless PNG. Thus, you wouldn't want to use this
    program as much more than a toy. Nevertheless, walking through a toy program can be a great way
    to learn.&lt;/p&gt; &lt;section class="footnotes" role="doc-endnotes"&gt; &lt;hr/&gt;
    &lt;ol&gt; &lt;li id="fn1" role="doc-endnote"&gt;&lt;p&gt;Actually, I didn't realize to do this
    until after I had gone through these steps. But it makes everything simpler, so lets pretend I
    did it right the first time.&lt;a class="footnote-back"
    href="https://lmcnulty.me/words/bmp-output/#fnref1"
    role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; &lt;li id="fn2"
    role="doc-endnote"&gt;&lt;p&gt;Incidentally, the Chinese date format is almost always the one
    you want to use in computing, because its the only one where the alphabetical sort gives the
    dates in-order.&lt;/p&gt; &lt;p&gt;The US date format doesn't make much numeric sense, and thus
    doesn't help understanding endian-ness, because it puts the
    &lt;em&gt;second&lt;/em&gt;-smallest unit first.&lt;a class="footnote-back"
    href="https://lmcnulty.me/words/bmp-output/#fnref2"
    role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/section&gt;
    &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>Meal Plan Explained</title>
    <published>2020-02-13T00:00:00</published>
    <link href="https://lmcnulty.me/words/meal-plan" />
    <content type="html">&lt;html&gt;&lt;body&gt;&lt;p&gt;When I first arrived at Brown, I found
    the meal plans confusing. However, during my four years, I've finally figured out all the
    details. For anyone still confused, it's actually quite simple:&lt;/p&gt; &lt;p&gt;Meals at
    campus eateries can be paid for in Bear Bucks, Meal Points, Meal Credits, cash, credit, and
    traveler's checks. You may combine a maximum of three payment methods, which may not include
    both meal points and Bear bucks, except at the Ivy Room.&lt;/p&gt; &lt;p&gt;One credit can be
    exchanged for between $7.60 and $8.20 (or less) worth of food from a campus eatery. However you
    cannot exchange a credit for points at the Blue Room on Saturdays or on Wednesdays after 12am
    and before 4pm. Furthermore, you cannot exchange credits for points at any campus eatery except
    the V-Dub on days that fall within the first or last two weeks of a semester or that are
    designated as federal holidays, but not both. When a point is exchanged for credits, those
    credits must be used immediately, and any remaining credits are discarded, unless you use two
    or more credits in one swipe. Note that a "swipe" is distinct from a "transaction."&lt;/p&gt;
    &lt;p&gt;Students on a meal plan (excluding "flex" meal plans) receive the corresponding number
    of credits and points every Thursday. Unlike points, credits do not carry over between weeks,
    but they carry over between days. However, you may not use more than three credits within a
    24-hour period. Therefore, if you are on a 20 meals/week plan, you can only use carried-over
    points on Sundays. Note that the 24-hour period is extended to 36 hours during reading period.
    This is the only time during which the Sharpe Refectory serves breakfast on Sundays, however,
    meal plan-holders are not given an additional credit for the extra meal.&lt;/p&gt;
    &lt;p&gt;Students may choose either a weekly or a "flex" meal plan. The twenty meals/week is
    available to all students throughout their four years at Brown, but not to fifth-year seniors.
    Of the remaining weekly meal plans, the 14 meals/week plan is offered to all students except
    freshmen, and the 7 and 10 meals/week plans to juniors and seniors, respectively. Of the flex
    plans, the flex 460 plan is available to freshmen, Flex 330 to sophomores, and Flex 240 to
    juniors and seniors, not respectively. Graduate students are allowed purchase a meal plan, but
    it is considered embarrassing. To determine the number of credits, points, and guest swipes
    provided in a given meal plan, consult the Dining services website at &lt;a
    href="http://brown.cafebonappetit.com/"&gt;brown.cafebonappetit.com&lt;/a&gt; or &lt;a
    href="https://dining.brown.edu/"&gt;dining.brown.edu&lt;/a&gt;. Note: the provided figures on
    these websites are not guaranteed to be accurate or to match one another.&lt;/p&gt;
    &lt;p&gt;Meal plans include between 2 and 5 guest swipes per semester per year (inclusive).
    Unlike ordinary credits, guest swipes may be used for a person other than the student on the
    meal plan. Married couples count as the same person for this purpose, but they require two
    guest swipes to be admitted to the Sharpe Refectory or the V-Dub. Brown University recognizes
    marriages performed in every country except the Czech Republic.&lt;/p&gt; &lt;p&gt;All campus
    eateries except the Blue Room are closed beginning at the first day of Spring break and ending
    on the day two-days before classes resume (not inclusive). Meal plans are not credited between
    the first Thursday of Spring break and the day before classes resume (inclusive). On
    odd-numbered years,&lt;a class="footnote-ref" href="https://lmcnulty.me/words/meal-plan/#fn1"
    id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; campus eateries are open
    one additional day before classes resume.&lt;/p&gt; &lt;p&gt;The Blue Room is open from 9am to
    4pm on Mondays, Wednesdays and Thursdays and from 9am to 1pm on Fridays. On Tuesdays and
    Sundays, it's open from 10:30am to 9pm, and it is open all day on Sunday. Additionally, the
    Blue Room closes every 300 days not including Federal Holidays except Christmas, unless it
    falls on a Sunday or Monday, starting from July 2, 1776.&lt;/p&gt; &lt;p&gt;The meal plans of
    graduating seniors are terminated at 2pm on the day of their graduation. However, in special
    circumstances, students may receive a dean's note to extend their meal plan at most four days,
    but no fewer than two.&lt;/p&gt; &lt;p&gt;Muslim students in good academic standing may elect
    to cancel their meal plan for the month of Ramadan. They will be refunded by an amount posted
    in the University Chaplain's office up to four days before the start of Ramadan. Note that the
    amount may be, but is not necessarily, dependent on whether a student is receiving financial
    aid. This offer is extended to students who have not recorded themselves as Muslim in Banner,
    however they will be refunded by the same amount as students not receiving financial aid,
    regardless of their own status. Note also that Sikhs and Yazidis are considered Muslim for this
    purpose.&lt;/p&gt; &lt;p&gt;Every fortnight, the President of the College and zero or more
    representatives from Johnson &amp; Wales University will meet at an agreed-upon location for
    secret coin-flip. If the result is "heads," then the cost of fruits and snack-foods will be
    synchronized between Josiah's and Andrew's. Otherwise, one of the two will have prices 20 cents
    higher than the other on an alternating basis.&lt;/p&gt; &lt;section class="footnotes"
    role="doc-endnotes"&gt; &lt;hr/&gt; &lt;ol&gt; &lt;li id="fn1"
    role="doc-endnote"&gt;&lt;p&gt;Reminder: students should use the Hebrew calendar to determine
    the number of the current year, excepting Francophone Studies concentrators and students of the
    Eastern Orthodox faith, the former of whom may optionally use the French Republican calendar
    and the latter of whom are &lt;em&gt;required&lt;/em&gt; to use the Julian Calendar.&lt;a
    class="footnote-back" href="https://lmcnulty.me/words/meal-plan/#fnref1"
    role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/section&gt;
    &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
  <entry>
    <title>Advice for College Students (Part 1)</title>
    <published>2020-01-31T00:00:00</published>
    <link href="https://lmcnulty.me/words/college-advice-1" />
    <content type="html">&lt;html&gt;&lt;head&gt;&lt;style&gt; .pull-away { font-size: 120%;
    text-align: center; float: right; width: 20ch; display: block; position: relative;
    padding-left: 3ch; padding-right: 3ch; margin: 5px; margin-bottom: 0px; background: none;
    border: none; } .pull-away:before, .pull-away:after { font-size: 300%; line-height: .2em;
    vertical-align: bottom; position: absolute; bottom: 0px; line-height: 100%; } .pull-away:after
    { content: """; right: 0px; } .pull-away:before { content: """; left: 0px; } &lt;/style&gt;
    &lt;/head&gt;&lt;body&gt;&lt;p&gt;Last semester, I spent time with some first-years who, upon
    learning that I was a senior, asked me if I had any accumulated "wisdom" to share. At first I
    found this funny, but I've nevertheless reflected on the question and decided to record my
    thoughts.&lt;/p&gt; &lt;blockquote class="pull-away"&gt; college courses are not croissants
    &lt;/blockquote&gt; &lt;p&gt;The items are arranged roughly in order of importance. Thus, this
    article has more high-level, philosophical sort of advice, some of which might seem obvious.
    You might want to jump right to &lt;a
    href="https://lmcnulty.me/words/college-advice-1/../college-advice-2"&gt;part 2&lt;/a&gt; if
    you're interested in more specifics.&lt;/p&gt; &lt;h2 id="prioritize-learning"&gt;Prioritize
    Learning Before Grades&lt;/h2&gt; &lt;p&gt;Unless you study &lt;a
    href="https://lmcnulty.me/words/college-advice-1/../college-advice-2/#study-abroad-every-semester"&gt;outside
    the U.S.&lt;/a&gt;, college is an enormous expense. It might not be worth it if all you're
    getting out of it is a diploma. Yes, there are some schools and fields where degrees carry a
    lot of economic value. However, if you're studying something like literature at a mid-tier
    university or if you want to go into a field where a degree isn't required, you should
    primarily be in college because you love learning and want to grow as a person. If you succeed
    in this, college will be worth it.&lt;/p&gt; &lt;p&gt;I experienced High School mostly as an
    ordeal I had to get through so that I could go to a good college. Yes, a few classes,
    particularly in Art and English, impacted me in a deeper way, but many contributed to my
    personal and intellectual development about as much as the SATs. I checked my grades at least
    once a day, and on a few occasions I convinced my parents to let me stay home from school to
    have more time to study for tests. This approach is the exact opposite of what you should do in
    college. Unless you're planning to go to Law/Med School, college is not a means to end. It is a
    rare opportunity in life to spend several years working with the end-goal of improving
    yourself: take advantage of it. The letters on your transcript are of secondary
    importance.&lt;/p&gt; &lt;p&gt;Understand that the optimal strategies for maximizing grades are
    not necessarily the most effective for learning. For instance, when I was a TA in 2D Game
    Engines, a lot of students would turn in projects that were not very polished or engaging as
    games&lt;a class="footnote-ref" href="https://lmcnulty.me/words/college-advice-1/#fn1"
    id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; but which technically met
    all the requirements for an A. They were acting completely rationally from the perspective of
    someone trying to optimize grades: any extra time spent on sprite animation or level generation
    could have been used studying for midterms. However, the students who "irrationally" chose to
    put in the extra work came out of the class knowing how to make great games that they could
    proudly include in a portfolio.&lt;/p&gt; &lt;p&gt;Some people will try to take easy classes
    because they're protective of their GPA. My school tries to deter this by giving students the
    option to take any class pass/fail, which I think is a great idea. But even if your school
    makes you take every class for a grade, you should still not take classes just because they
    will be easy. This is not only a bad way to learn, but it might not even work: sometimes the
    hard classes aren't what you would expect. For instance, I took Moral Philosophy because the
    subject interested me, but I didn't imagine that it would be very hard. However, I didn't do as
    well as I expected, partly because I still had a little of &lt;a
    href="http://existentialcomics.com/comic/191"&gt;this guy&lt;/a&gt; in me.&lt;/p&gt;
    &lt;p&gt;If you take classes below your level and forget everything after tests, you might be
    able to leave college with a 4.0 GPA while having learned very little, but you would only be
    &lt;a href="https://www.smbc-comics.com/comic/2011-05-15"&gt;cheating
    yourself&lt;/a&gt;.&lt;/p&gt; &lt;h2 id="go-to-class"&gt;Go to class&lt;/h2&gt; &lt;p&gt;This
    should be obvious, but it's important enough to be worth emphasizing.&lt;/p&gt; &lt;p&gt;Yes,
    there might be a few courses that you can pass without attending lectures. Many of my
    classmates in Software Engineering skipped class because the content wasn't needed to complete
    assignments, which constituted almost the entire course grade. However, the students who
    attended got more out of the class.&lt;/p&gt; &lt;p&gt;Besides the direct value of course
    content, the routine of going to class is incredibly valuable: it motivates you to do the work
    you need, and it gives you feedback on how well you're understanding the material. If you skip
    classes, you will end up sleeping during the day and just generally being
    dysfunctional.&lt;/p&gt; &lt;p&gt;Some classes might record lectures. Do not use this as an
    excuse to skip class: anytime you tell yourself that you'll watch the lecture capture, there's
    a high chance that you won't.&lt;/p&gt; &lt;h2
    id="read-and-annotate-the-assigned-texts"&gt;Read &lt;em&gt;and annotate&lt;/em&gt; the
    assigned texts&lt;/h2&gt; &lt;p&gt;Readings are the main homework in humanities classes.
    Skipping a reading is like deciding not to hand in a problem-set or a coding project. Also,
    understand that "reading" a text is not the same as "looking at it." Even if your eyes passed
    over some words, your brain may not have learned anything. This will become clear on the
    occasions when you have to read something like this:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;When
    we come to the concomitant question of the consciousness of the subaltern, the notion of what
    the work cannot say becomes important. In the semioses of the social text, elaborations of
    insurgency stand in the place of 'the utterance'. The sender – 'the peasant' – is marked only
    as a pointer to an irretrievable consciousness. As for the receiver, we must ask who is 'the
    real receiver' of an 'insurgency'? The historian, transforming 'insurgency' into 'text for
    knowledge', is only one 'receiver' of any collectively intended social act. &lt;a
    class="footnote-ref" href="https://lmcnulty.me/words/college-advice-1/#fn2" id="fnref2"
    role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt; &lt;/blockquote&gt;
    &lt;p&gt;The best way to ensure that you're actually reading is to highlight and annotate the
    text. I resisted doing this for far too long, because I didn't like defacing books. However,
    many or most of the time your readings will not be given in the format of print books. More
    often I as given low-quality PDF scans from books. These are not well-suited to on-screen
    reading, So you should either print them out or annotate them on a tablet. I recommend &lt;a
    href="http://xournal.sourceforge.net/"&gt;Xournal&lt;/a&gt; if you're on GNU/Linux. If you
    don't interact with the text, especially when it's on a screen, the temptation to skim is too
    strong.&lt;/p&gt; &lt;h2 id="sit-in-the-front-row"&gt;Sit in the front row&lt;/h2&gt;
    &lt;p&gt;If you're too intimidated to sit in the front row, sit in the second row. Professors
    will remember and judge you better if you sit closer to them. I had one class where I sat in
    the seat directly in front of the professor, and as a consequence, he would individually greet
    me when I entered the classroom of 40+ people.&lt;/p&gt; &lt;p&gt;Besides making a good
    impression, sitting in the front will make it easier for you to ask questions, both because
    you'll have an easier time making yourself heard, and you'll start to find the professor less
    intimidating.&lt;/p&gt; &lt;p&gt;In the front, you'll also be less tempted to look at your
    phone or stare into space. You will also have an extra incentive to &lt;a
    href="https://lmcnulty.me/words/college-advice-1/#go-to-class-and-do-the-readings"&gt;go to
    class&lt;/a&gt;, because your absence will be noticed.&lt;/p&gt; &lt;h2
    id="speak-in-class"&gt;Speak in class&lt;/h2&gt; &lt;p&gt;Speaking in class can be
    intimidating. Nevertheless, learning to speak elegantly in front of a group of smart people is
    an important skill, and college is one of the best places to learn it. This is one of the
    reasons why you should do the readings: you'll won't feel confident speaking in class if you're
    behind.&lt;/p&gt; &lt;p&gt;If you identify a class where you have trouble contributing, be sure
    to take advantage of times when the class shifts to a topic you know more about. For instance,
    I had a lot of trouble following the math-heavy lectures in my Computer Graphics class, so I
    made sure to answer the professor's questions when we talked about art history.&lt;/p&gt;
    &lt;h2 id="put-away-the-laptop"&gt;Put away the laptop&lt;/h2&gt; &lt;p&gt;I like computers. I
    spend most of my time in front of one. I'm even part of the &lt;a
    href="https://www.pewresearch.org/fact-tank/2019/09/25/one-in-five-americans-now-listen-to-audiobooks/"&gt;small
    minority&lt;/a&gt; that reads ebooks more than paper books. Nevertheless, I recommend putting
    away your laptop in class.&lt;/p&gt; &lt;p&gt;Some professors will say that they don't mind
    laptops, but virtually none &lt;em&gt;prefer&lt;/em&gt; that you use one. Taking notes by hand
    will give a better impression, if for no other reason than that it's certain that you're not
    using Facebook in class. (If you do use Facebook in class, spend some time thinking about &lt;a
    href="https://lmcnulty.me/words/college-advice-1/#prioritize-learning"&gt;why&lt;/a&gt; you're
    in that class—or in college generally.) If you take notes by hand, you'll be less distracted
    and you'll feel closer to your professor due to not having a barrier in front of you.&lt;/p&gt;
    &lt;p&gt;A lot of people like to use laptops because they think they can take more detailed
    notes. This is probably less important than you think. The main benefit of note-taking is that
    it helps you pay attention and remember what you learned: you're more likely to remember
    something that you wrote down by hand, even if you never review your notes. There's probably
    something better to review than your own notes anyway: a textbook, lecture slides, notes you
    get from a classmate, etc.&lt;/p&gt; &lt;p&gt;Even if you're the type of person who gets a lot
    out of typed-up notes and doesn't get distracted by a laptop, screens have a captivating effect
    that can distract other people in class. &lt;a class="footnote-ref"
    href="https://lmcnulty.me/words/college-advice-1/#fn3" id="fnref3"
    role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;And one last minor
    note: your college notes can be an opportunity to improve your handwriting. I started college
    with awful handwriting that I hated: now I regularly get compliments on it.&lt;/p&gt; &lt;h2
    id="continue-working-on-fun-stuff"&gt;Continue working on fun stuff&lt;/h2&gt; &lt;p&gt;When
    you're in college, you'll almost always have schoolwork that you "should" be doing. (If you
    don't, you should probably be taking more advanced classes.) This can sometimes make you feel
    as if you can't justify putting effort into things besides schoolwork. After all, how can you
    read a book for pleasure when you have three other books to read for your classes? How can you
    spend time learning to make a website when you have a project due this week?&lt;/p&gt;
    &lt;p&gt;Resist this type of thinking. As much as it might feel like it, you almost certainly
    don't spend every free minute on your schoolwork, and any time you "save" by not reading a
    novel is more likely to be wasted scrolling through internet feeds.&lt;/p&gt; &lt;p&gt;Formal
    education is kind of a weird way to learn. It's super useful, but the way that people naturally
    learn is by exploring, playing around, and trying new things. You should continue doing this
    even as you're in a formal learning environment: you will learn twice as much. I learned
    JavaScript while I "should" have been working on Syntax homework, I learned LaTeX while I
    "should" have been writing papers, and I wrote about half of my blog posts while I was
    procrastinating on another task.&lt;/p&gt; &lt;p&gt;Incidentally, this also goes for social
    relationships. When I've turned down invitations because I "have work to do," I've almost never
    accomplished whatever it is I wanted to do in the time I gained. In fact, I've probably lost
    more time wallowing in loneliness than I've ever saved from not being around other
    people.&lt;/p&gt; &lt;p&gt;In fact, even if you really did have to make academic sacrifices for
    your social life, that's usually going to be worth it. No one on their deathbed wishes that
    they had spent more time studying and less time with friends and family.&lt;/p&gt; &lt;p&gt;I
    realize that there are some people who need to hear the opposite advice: the type who see
    college primarily as a way to meet attractive people their own age. However, I somehow doubt
    that many of those people read blogs hosted on &lt;code&gt;gitlab.io&lt;/code&gt;.&lt;/p&gt;
    &lt;h2 id="take-artisan-classes"&gt;Take "artisan" classes&lt;/h2&gt; &lt;p&gt;Artisan classes
    are those that are designed and taught by a single professor. These tend to be more niche
    subjects in which the professor is a passionate expert. It's a very good sign if the course
    contains information that the professor personally discovered, invented, or theorized: there's
    likely no better way you could learn that specific material. Sometimes, it will be slanted
    towards the professor's particular views on a subject. For instance, my syntax professor spent
    a lot of time on &lt;a href="https://en.wikipedia.org/wiki/Categorial_grammar"&gt;Categorial
    Grammar&lt;/a&gt;, which is not the most mainstream theory. However, it's better to get great
    coverage of one viewpoint than poor coverage of many.&lt;/p&gt; &lt;p&gt;Avoid "mass-produced"
    classes. These are ones that have many sections, are offered every semester, and have large
    class sizes. They are less likely to have you do meaningful work, as the grading burden will be
    huge. They are often taught by adjuncts or grad students who would rather be doing something
    else. The less your teacher cares, the less value you get from taking a class rather than just
    reading about the subject on your own.&lt;/p&gt; &lt;p&gt;&lt;small&gt;(To be clear: Grad
    students can be great teachers — my first two French classes were both taught by grad students,
    and they were both excellent. But those were small, highly intimidate classes, not the type I'm
    talking about here.)&lt;/small&gt;&lt;/p&gt; &lt;p&gt;You might need to take this sort of class
    as a requirement for your major or a pre-requisite for other courses you'd like to take: that's
    why so many people need to take them. I recommend that you see if you can have the requirement
    waived or replaced by a different class. You might be surprised, and there's no harm in
    asking.&lt;/p&gt; &lt;p&gt;A "real" croissant rolled by hand will cost more than one molded
    from frozen dough in a factory. But college courses are not croissants: you generally pay the
    same for a lovingly-crafted seminar as for a detached, uninspired lecture.&lt;/p&gt;
    &lt;p&gt;&lt;a
    href="https://lmcnulty.me/words/college-advice-1/../college-advice-2"&gt;Continue to Part
    2&lt;/a&gt;&lt;/p&gt; &lt;section class="footnotes" role="doc-endnotes"&gt; &lt;hr/&gt;
    &lt;ol&gt; &lt;li id="fn1" role="doc-endnote"&gt;&lt;p&gt;To be clear, a lackluster project
    didn't necessarily mean that a student wasn't learning. Some students had less experience
    programming and had to put in a lot of effort to meet the minimum requirements: they also
    learned a lot, just different things from the more experienced programmers.&lt;a
    class="footnote-back" href="https://lmcnulty.me/words/college-advice-1/#fnref1"
    role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; &lt;li id="fn2"
    role="doc-endnote"&gt;&lt;p&gt;Gayatri Chakravorty Spivak, &lt;em&gt;Can the Subaltern
    Speak&lt;/em&gt;&lt;a class="footnote-back"
    href="https://lmcnulty.me/words/college-advice-1/#fnref2"
    role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; &lt;li id="fn3"
    role="doc-endnote"&gt;&lt;p&gt;Faria Sana, Tina Weston, and Nicholas J. Cepeda, "&lt;a
    href="https://www.sciencedirect.com/science/article/pii/S0360131512002254"&gt;Laptop
    multitasking hinders classroom learning for both users and nearby peers&lt;/a&gt;,"
    &lt;em&gt;Computers &amp; Education&lt;/em&gt; 62 (2013) p.&#160;24-31&lt;a
    class="footnote-back" href="https://lmcnulty.me/words/college-advice-1/#fnref3"
    role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt; &lt;/ol&gt; &lt;/section&gt;
    &lt;/body&gt;&lt;/html&gt;</content>
  </entry>
</feed>
