<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>elijah.run - blog</title><subtitle>most of my writing</subtitle>
    <link rel="self" type="application/atom+xml" href="https://elijah.run/blog/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://elijah.run/blog/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2025-12-25T00:00:00+00:00</updated>
    <id>https://elijah.run/blog/atom.xml</id>
    <entry xml:lang="en">
        <title>Media Mono-Tasking</title>
        <published>2025-12-25T00:00:00+00:00</published>
        <updated>2025-12-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/media-monotasking/"/>
        <id>https://elijah.run/blog/media-monotasking/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/media-monotasking/">&lt;p&gt;I, like many people in 2025, have a looooong list of games, movies, tv, and books that I want to enjoy sometime between now and death.&lt;&#x2F;p&gt;
&lt;p&gt;Some tools I have created to deal with this problem include a &lt;a href=&quot;&#x2F;backlog&#x2F;&quot;&gt;backlog&lt;&#x2F;a&gt;, and a &lt;a href=&quot;&#x2F;whats-good&#x2F;&quot;&gt;monthly reflection on what I enjoyed&lt;&#x2F;a&gt;.
These both help me focus; I either finish a piece of media or I give up entirely.
None of this &quot;Oh I started five books and two shows and a dozen games this month&quot; no: either finish what you started, or basnish it to the shadow realm; there is too much good stuff to drag a bunch of half finish &lt;em&gt;stuff&lt;&#x2F;em&gt; around too.&lt;&#x2F;p&gt;
&lt;p&gt;Between work, taking care of the kids, walking the dog, keeping the house tidy, eating, sleeping, keeping up with friends, and exercising I have ~1-2 hours of &quot;me time&quot; per day to spend on &lt;em&gt;whatever&lt;&#x2F;em&gt;.
In the past I woud mindlessly scroll for &lt;em&gt;hours&lt;&#x2F;em&gt; after work and on the weekends, but I had to &lt;a href=&quot;&#x2F;whats-good&#x2F;2024&#x2F;10&#x2F;#tech-screenzen&quot;&gt;lock that shit down&lt;&#x2F;a&gt; pretty quick after having a kid; life&#x27;s too short to waste perfectly good free time.&lt;&#x2F;p&gt;
&lt;p&gt;Ok here&#x27;s the thing: between What&#x27;s Good and The Backlog I feel &lt;em&gt;ok&lt;&#x2F;em&gt; about my media focus, but I think I can do better.
I still find myself starting games I never finish, starting a book on the 1st of the month that&#x27;s barely half way done by the end, and mindlessly scrolling the one app I didn&#x27;t lock down yet-- am I really scrolling Libby?&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-proposal&quot;&gt;The Proposal&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Do One Thing at a Time.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If you start reading a book, watching a show, listening to a podcast, &lt;em&gt;whatever&lt;&#x2F;em&gt;, that&#x27;s the only media you consume until you either complete it or abandon that forever.&lt;&#x2F;p&gt;
&lt;p&gt;Not one &lt;strong&gt;book&lt;&#x2F;strong&gt; at a time, or one &lt;strong&gt;movie&lt;&#x2F;strong&gt; at a time, but one &lt;em&gt;thing&lt;&#x2F;em&gt; at a time, across all media.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Start a movie? You cannot stop half way through and listen to a podcast while you do dishes.&lt;&#x2F;li&gt;
&lt;li&gt;Start a videogame? Git gud or you&#x27;re gonna get really bored.&lt;&#x2F;li&gt;
&lt;li&gt;Start reading a book? Get cozy af because you&#x27;re locked in.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of course you can go about your life eating and sleeping and working, but the only &lt;em&gt;media&lt;&#x2F;em&gt; you can consume is &lt;em&gt;the thing&lt;&#x2F;em&gt; until it is done or you call it quits.&lt;&#x2F;p&gt;
&lt;p&gt;Done is subjective, but you get the idea.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Roll credits on a movie.&lt;&#x2F;li&gt;
&lt;li&gt;Finish the last chapter in a book.&lt;&#x2F;li&gt;
&lt;li&gt;Finish a season of television.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;it-s-not-quite-that-simple&quot;&gt;It&#x27;s not quite that simple&lt;&#x2F;h2&gt;
&lt;p&gt;I mean you totally could just do that, but you&#x27;d spend a lot of time driving in silence because you started playing Elden Ring and it&#x27;s good but you&#x27;re &lt;em&gt;really bad&lt;&#x2F;em&gt; at souls-likes.&lt;&#x2F;p&gt;
&lt;p&gt;And honestly truly doing one thing at a time is like the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Jain_vegetarianism&quot;&gt;Jain vegetarianism&lt;&#x2F;a&gt; of media diets, it&#x27;s the most intense version.&lt;&#x2F;p&gt;
&lt;p&gt;I propose, and will personally strive, for a more moderate version which is going to use the following categories to guide our media decisions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Active Media: (Videogames) media that requires your participation.
&lt;ul&gt;
&lt;li&gt;Solving puzzles, shooting zombies, stuff like that.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Active Visual Media: (Books) media that requires your attention.
&lt;ul&gt;
&lt;li&gt;You don&#x27;t need to solve puzzles, but you do need to flip pages.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Passive Visual Media: (Movies&#x2F;TV&#x2F;Videos) benefits from attention.
&lt;ul&gt;
&lt;li&gt;The media will move on without you, but you should be keeping up.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Passive Media: (Music&#x2F;Podcasts&#x2F;Audiobooks) you can put it on in the background.
&lt;ul&gt;
&lt;li&gt;This is &quot;Doing the Dishes&quot; stuff.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;media-monotasking&#x2F;flow-diagram.jpg&quot; alt=&quot;A diagram showing the decision tree of what media to consume when&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&#x27;m going to call these &quot;Media Moods&quot; because &quot;Media Situations&quot; feels clunky.
You totally &lt;em&gt;can&lt;&#x2F;em&gt; do these based on mood, it&#x27;s just simpler to describe situations that limit what you &lt;em&gt;can&lt;&#x2F;em&gt; do rather than the more fuzzy &lt;em&gt;what you want to do&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;For each of these moods I would pick a single piece of media to engage with.
Any time you are in that mood, you are reading&#x2F;watching&#x2F;listening to that thing, until that thing is done.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;While I am rowing I finish a movie (passive visual) I started yesterday.&lt;&#x2F;li&gt;
&lt;li&gt;Later I am cleaning up the house, so I finish a podcast (passive) I stared that morning.&lt;&#x2F;li&gt;
&lt;li&gt;In the evening I play a puzzle game (active) I have been working on for a few days.&lt;&#x2F;li&gt;
&lt;li&gt;Until I decide my brain is tired and I want to do something else, so I read this month&#x27;s book (active visual).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Yes, I am drawing an arbitrary line between &quot;Active&quot; and &quot;Active Visual&quot; for convenience; you could totally merge those to simplify things even further.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This means that you have &lt;em&gt;some&lt;&#x2F;em&gt; choice of media based on your circumstances, but there is still a prescriptive framework around what you &lt;em&gt;should&lt;&#x2F;em&gt; be doing media-wise to avoid getting easily distracted.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;this-is-not-for-everybody&quot;&gt;This is not for everybody&lt;&#x2F;h2&gt;
&lt;p&gt;It goes without saying, this is a framework for burning down a backlog.
Even more so, it is for people who have very little time to burn that backlog, and they need to squeeze every minute out of their days to make any progress on that project.&lt;&#x2F;p&gt;
&lt;p&gt;If you don&#x27;t have a backlog, or you already have a healthy way of handling your backlog, this is probably not for you.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also not compatible with like... roommates.
You should definitely make an exception to whatever your media backlog dictates if it means having a good time with friends and&#x2F;or family.
Don&#x27;t be weird about it please.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;this-is-a-thing-i-am-trying&quot;&gt;This is a thing I am trying&lt;&#x2F;h2&gt;
&lt;p&gt;It would be awesome if I could say this is something I&#x27;ve been doing for a year and it&#x27;s worked flawlessly -- but no.
This is just a thing I am starting and trying in hopes that it will improve my backlog burn rate.&lt;&#x2F;p&gt;
&lt;p&gt;And if it doesn&#x27;t we&#x27;ll learn something too.
Either way, I&#x27;ll keep you posted.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How I use typst</title>
        <published>2025-07-17T00:00:00+00:00</published>
        <updated>2025-07-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/how-i-use-typst/"/>
        <id>https://elijah.run/blog/how-i-use-typst/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/how-i-use-typst/">&lt;p&gt;This week I re-wrote &lt;a href=&quot;&#x2F;Elijah%20Voigt.pdf&quot;&gt;my resume&lt;&#x2F;a&gt;  in &lt;a href=&quot;https:&#x2F;&#x2F;typst.app&#x2F;&quot;&gt;typst&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;how-i-use-typst&#x2F;old.pdf&quot;&gt;Old&lt;&#x2F;a&gt;:
&lt;img src=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;how-i-use-typst&#x2F;old.png&quot; alt=&quot;old resume&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;how-i-use-typst&#x2F;new.pdf&quot;&gt;New&lt;&#x2F;a&gt;:
&lt;img src=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;how-i-use-typst&#x2F;new.png&quot; alt=&quot;new resume&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Can you tell the difference? No? Excellent!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Since graduating college I don&#x27;t write a lot of LaTeX, but so far I prefer typst!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;anguished-typst-is-not-just-a-better-latex&quot;&gt;😧 typst is not (just) a better LaTeX&lt;&#x2F;h1&gt;
&lt;p&gt;I posted some first impressions on &lt;a href=&quot;https:&#x2F;&#x2F;bsky.app&#x2F;profile&#x2F;elijah.run&quot;&gt;Bluesky&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote class=&quot;bluesky-embed&quot; data-bluesky-uri=&quot;at:&#x2F;&#x2F;did:plc:srziwhupeikb2bcnyndug2ga&#x2F;app.bsky.feed.post&#x2F;3ltx7vsqt3s2m&quot; data-bluesky-cid=&quot;bafyreid2ol6s3bji2jkyiaxnwdgylql7qja72wojpnno5y2eohxahggswu&quot; data-bluesky-embed-color-mode=&quot;system&quot;&gt;&lt;p lang=&quot;en&quot;&gt;LaTeX being compatible with TeX makes it feel like the C++ of typesetting; a rich ecosystem with lots of bloat.
&lt;p&gt;typst not being constrained in that way makes it feel like the Zig of typesetting; smaller ecosystem but a much smoother writing experience.&lt;&#x2F;p&gt;— Elijah Voigt (&lt;a href=&quot;https:&#x2F;&#x2F;bsky.app&#x2F;profile&#x2F;did:plc:srziwhupeikb2bcnyndug2ga?ref_src=embed&quot;&gt;@elijah.run&lt;&#x2F;a&gt;) &lt;a href=&quot;https:&#x2F;&#x2F;bsky.app&#x2F;profile&#x2F;did:plc:srziwhupeikb2bcnyndug2ga&#x2F;post&#x2F;3ltx7vsqt3s2m?ref_src=embed&quot;&gt;July 14, 2025 at 1:25 PM&lt;&#x2F;a&gt;&lt;&#x2F;blockquote&gt;&lt;script async src=&quot;https:&#x2F;&#x2F;embed.bsky.app&#x2F;static&#x2F;embed.js&quot; charset=&quot;utf-8&quot;&gt;&lt;&#x2F;script&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To elaborate: typst doesn&#x27;t feel like an &lt;em&gt;improvement&lt;&#x2F;em&gt; on LaTeX, it feels like a from-the-ground-up typsestter that learns from the past uhh -- wait &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;LaTeX&quot;&gt;LaTeX&lt;&#x2F;a&gt; came out in 1984? and &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;TeX&quot;&gt;TeX&lt;&#x2F;a&gt; came out in 1978?? So yeah it learns from the past 41+ years.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;adult-computer-typst-is-just-programming-for-me&quot;&gt;🧑‍💻 typst is just programming (for me)&lt;&#x2F;h1&gt;
&lt;p&gt;To be fair, so is LaTeX.
If you give me a programming language I&#x27;m gonna program.&lt;&#x2F;p&gt;
&lt;p&gt;The typst docs make it seem like it&#x27;s &lt;code&gt;markdown&lt;&#x2F;code&gt; with functions, which is somewhat true:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typ&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-typ &quot;&gt;&lt;code class=&quot;language-typ&quot; data-lang=&quot;typ&quot;&gt;&lt;span&gt;== this is a title
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;this is a paragraph.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;- this
&lt;&#x2F;span&gt;&lt;span&gt;- is
&lt;&#x2F;span&gt;&lt;span&gt;- a
&lt;&#x2F;span&gt;&lt;span&gt;- list
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But my resume is more... function heavy than advertised.
For example, this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;how-i-use-typst&#x2F;example.png&quot; alt=&quot;example styled section&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Came from this function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typ&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-typ &quot;&gt;&lt;code class=&quot;language-typ&quot; data-lang=&quot;typ&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Function for printing a role
&lt;&#x2F;span&gt;&lt;span&gt;#let role(org: none, location: none, title: none, date: none, description: ntypone) = {
&lt;&#x2F;span&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;  #set text(weight: &amp;quot;bold&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;  #org
&lt;&#x2F;span&gt;&lt;span&gt;  #set text(weight: &amp;quot;regular&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;  (
&lt;&#x2F;span&gt;&lt;span&gt;    #text(13pt, location)
&lt;&#x2F;span&gt;&lt;span&gt;  )
&lt;&#x2F;span&gt;&lt;span&gt;  #h(1fr)
&lt;&#x2F;span&gt;&lt;span&gt;  #set text(weight: &amp;quot;bold&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;  #title
&lt;&#x2F;span&gt;&lt;span&gt;  #set text(weight: &amp;quot;regular&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;  #date
&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;text(12pt, description);
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Invoked like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typ&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-typ &quot;&gt;&lt;code class=&quot;language-typ&quot; data-lang=&quot;typ&quot;&gt;&lt;span&gt;#role(
&lt;&#x2F;span&gt;&lt;span&gt;  org: [CoreOS],
&lt;&#x2F;span&gt;&lt;span&gt;  location: [San Francisco, CA&#x2F;Remote],
&lt;&#x2F;span&gt;&lt;span&gt;  title: [Documentarian],
&lt;&#x2F;span&gt;&lt;span&gt;  date: [09&#x2F;2016 - 05&#x2F;2017],
&lt;&#x2F;span&gt;&lt;span&gt;  description: [
&lt;&#x2F;span&gt;&lt;span&gt;    - #xp([Migration Docs.], [Reviewed, tested, and contributed to public facing Kubernetes developer docs.])
&lt;&#x2F;span&gt;&lt;span&gt;  ]
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The result looks good, but it certainly doesn&#x27;t &quot;feel like markdown&quot;... that&#x27;s OK!
I know how to program and the functions are simple!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typ&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-typ &quot;&gt;&lt;code class=&quot;language-typ&quot; data-lang=&quot;typ&quot;&gt;&lt;span&gt;&#x2F;&#x2F; function definition:
&lt;&#x2F;span&gt;&lt;span&gt;#myfn(a, b, c) = {
&lt;&#x2F;span&gt;&lt;span&gt;  [
&lt;&#x2F;span&gt;&lt;span&gt;    #set foo(bar=&amp;quot;thing&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;    #a
&lt;&#x2F;span&gt;&lt;span&gt;    #set foo(other=&amp;quot;stuff&amp;quot;)
&lt;&#x2F;span&gt;&lt;span&gt;    #b -- #c
&lt;&#x2F;span&gt;&lt;span&gt;  ]
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; called like so:
&lt;&#x2F;span&gt;&lt;span&gt;#myfn([asdf], [abcd123], [hello world])
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; produces:
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; asdf abcd123 -- hello world
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;rabbit2-typst-is-fast&quot;&gt;🐇 typst is fast&lt;&#x2F;h1&gt;
&lt;p&gt;Which is... not surprising.
Not just because it&#x27;s written in Rust and I&#x27;m a voluntary Rust shill -- any new typesetter would probably be an improvement!
Any time you do a full rewrite, and ignore legacy usage, you&#x27;re gonna go sonic-levels of fast.
And again... LaTeX is 41 years old; there&#x27;s a lot of cruft in that ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;LaTeX&#x27;s output looks &lt;em&gt;gorgeous&lt;&#x2F;em&gt; but it is SLOW and BULKY.
To build my old resume I needed:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A 12GB+ docker container.&lt;&#x2F;li&gt;
&lt;li&gt;Bunch of style files I copied from a friend 10 years ago.&lt;&#x2F;li&gt;
&lt;li&gt;A bunch of build phases I frankly did not understand.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This was my Makefile which was &lt;em&gt;as simple as I could get it&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;make&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-make &quot;&gt;&lt;code class=&quot;language-make&quot; data-lang=&quot;make&quot;&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;resume
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;default&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;pdf
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;dvi&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;.tex
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;latex &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;.tex
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;ps&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;dvi
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;DOCKER&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;dvips&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -R -Poutline -t&lt;&#x2F;span&gt;&lt;span&gt; letter &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;.dvi&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt; -o &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;.ps
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;pdf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;ps
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ps2pdf &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;.ps resume.pdf
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ps2pdf &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;.ps &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Elijah Caine McDade Voigt resume.pdf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;ps2pdf &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;.ps &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Elijah Caine M. Voigt resume.pdf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;clean&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.aux
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.log
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.dvi
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.ps
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;veryclean&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.aux
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.log
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.dvi
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.ps
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;rm &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;.pdf
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;shell&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;DOCKER&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;&#x2F;bin&#x2F;sh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What is this &lt;code&gt;dvips&lt;&#x2F;code&gt; program?
What&#x27;s a &lt;code&gt;dvi&lt;&#x2F;code&gt; file?
And &lt;code&gt;.aux&lt;&#x2F;code&gt;??
Why do I need to build a &lt;code&gt;.ps&lt;&#x2F;code&gt; and a &lt;code&gt;.pdf&lt;&#x2F;code&gt;??&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, LaTeX is heavy and (for obvious reasons) typst is relatively light weight.&lt;&#x2F;p&gt;
&lt;p&gt;For comparison here&#x27;s how I build my current resume:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ typst compile resume.typ
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My dependencies are... &lt;code&gt;typst&lt;&#x2F;code&gt; and the &lt;code&gt;FreeMono&lt;&#x2F;code&gt; font.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;monocle-face-closing-thoughts&quot;&gt;🧐 Closing Thoughts&lt;&#x2F;h1&gt;
&lt;p&gt;But like I said, I don&#x27;t write a lot of LaTeX so why re-write my resume -- my only actively maintained LaTeX doc -- in a new typesetter?&lt;&#x2F;p&gt;
&lt;p&gt;Basically: I &lt;em&gt;dread&lt;&#x2F;em&gt; updating my resume &lt;em&gt;because&lt;&#x2F;em&gt; LaTeX is so heavy.
Every time I think to add it or tweak it or god forsake make a style change I find about a dozen reasons &lt;em&gt;not&lt;&#x2F;em&gt; to sink &lt;em&gt;hours&lt;&#x2F;em&gt; into that task.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m still in the honeymoon phase, but I feel a lot more &lt;em&gt;excited&lt;&#x2F;em&gt; to write with typst.
Maybe I&#x27;ll update my resume more than once a year!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rust Ergonomics: Default and From</title>
        <published>2022-05-17T00:00:00+00:00</published>
        <updated>2022-05-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/rust-default-from/"/>
        <id>https://elijah.run/blog/rust-default-from/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/rust-default-from/">&lt;p&gt;I&#x27;ve been writing Rust off and on since 2014 and consistently since 2019
when I got into Rust Game Development. Once I started writing more Rust
code I noticed it wasn&#x27;t just more lines of code, but each part of the
code was more verbose.&lt;&#x2F;p&gt;
&lt;p&gt;Coming from Python where ideas &lt;em&gt;tend&lt;&#x2F;em&gt; to be pretty succinct, Rust forced
you to spell everything out in intense detail. Of course you &lt;em&gt;got&lt;&#x2F;em&gt;
something for that verbosity -- &quot;if it compiles, it probably works&quot; --
but my hands were getting tired. There has to be a better way!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verbose-structs&quot;&gt;Verbose Structs&lt;&#x2F;h2&gt;
&lt;p&gt;There is a better way, but let&#x27;s clarify what the problem &lt;em&gt;is&lt;&#x2F;em&gt; exactly.
Take this example of a real struct from the &lt;a href=&quot;https:&#x2F;&#x2F;bevyengine.org&#x2F;&quot;&gt;bevy game engine&lt;&#x2F;a&gt; &lt;code&gt;PbrBundle&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;PbrBundle &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;MaterialMeshBundle&amp;lt;StandardMaterial&amp;gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s a type-alias to a &lt;code&gt;MaterialMeshBundle&lt;&#x2F;code&gt;.
Let&#x27;s check that out:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;MaterialMeshBundle&amp;lt;M&amp;gt; where
&lt;&#x2F;span&gt;&lt;span&gt;    M: SpecializedMaterial,
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;mesh&lt;&#x2F;span&gt;&lt;span&gt;: Handle&amp;lt;Mesh&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;material&lt;&#x2F;span&gt;&lt;span&gt;: Handle&amp;lt;M&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;transform&lt;&#x2F;span&gt;&lt;span&gt;: Transform,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;global_transform&lt;&#x2F;span&gt;&lt;span&gt;: GlobalTransform,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;visibility&lt;&#x2F;span&gt;&lt;span&gt;: Visibility,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;computed_visibility&lt;&#x2F;span&gt;&lt;span&gt;: ComputedVisibility,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Wow that&#x27;s a fair number of struct members.&lt;&#x2F;p&gt;
&lt;p&gt;If you wanted to create a &lt;code&gt;PbrBundle&lt;&#x2F;code&gt; by hand it would be a &lt;em&gt;tedious&lt;&#x2F;em&gt; process.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_pbr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; PbrBundle {
&lt;&#x2F;span&gt;&lt;span&gt;    mesh: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;get_mesh_handle&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;    material: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;get_material_handle&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;    transform: Transform {
&lt;&#x2F;span&gt;&lt;span&gt;        translation: Vec3::new(),
&lt;&#x2F;span&gt;&lt;span&gt;        rotation: Quat::new(),
&lt;&#x2F;span&gt;&lt;span&gt;        scale: Vec3::new(),
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    global_transform: GlobalTransform {
&lt;&#x2F;span&gt;&lt;span&gt;        translation: Vec3::new(),
&lt;&#x2F;span&gt;&lt;span&gt;        rotation: Quat::new(),
&lt;&#x2F;span&gt;&lt;span&gt;        scale: Vec3::new(),
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    visibility: Visibility {
&lt;&#x2F;span&gt;&lt;span&gt;        is_visibile: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    computed_visibility: ComputedVisibility {
&lt;&#x2F;span&gt;&lt;span&gt;        is_visibile: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Wow my fingers are already tired.&lt;&#x2F;p&gt;
&lt;p&gt;Now, assuming you don&#x27;t know the punchline, you&#x27;re probably thinking:
&lt;em&gt;Just use a constructor!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That solves the use-case where the author of the code has a constructor for my use-case, something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_pbr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;PbrBundle::new(mesh, material); &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Default Transform and Visibilty
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But what if I want a &lt;em&gt;mostly&lt;&#x2F;em&gt; &quot;default&quot; &lt;code&gt;PbrBundle&lt;&#x2F;code&gt;, with say &lt;code&gt;is_visible = false&lt;&#x2F;code&gt;?
Or I want to add a Transform with a custom scale but a default translation and rotation?&lt;&#x2F;p&gt;
&lt;p&gt;Basically, what if I am &lt;em&gt;picky&lt;&#x2F;em&gt; and want the &lt;em&gt;flexibility&lt;&#x2F;em&gt; of struct initialization with the &lt;em&gt;convenience&lt;&#x2F;em&gt; of constructor methods?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;default-fill-in-the-blanks&quot;&gt;Default: Fill in the blanks&lt;&#x2F;h2&gt;
&lt;p&gt;This is totally supported thanks to &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;default&#x2F;trait.Default.html&quot;&gt;Rust&#x27;s &quot;Default&quot; Trait&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The usage is something like this from the previous example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_pbr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; PbrBundle {
&lt;&#x2F;span&gt;&lt;span&gt;    mesh: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;get_mesh_handle&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;    material: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;get_material_bundle&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;    transform: Transform {
&lt;&#x2F;span&gt;&lt;span&gt;        scale: Vec3::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    visibility: Visibilty {
&lt;&#x2F;span&gt;&lt;span&gt;        is_visible: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This example shows creating a &lt;code&gt;PbrBundle&lt;&#x2F;code&gt; with a custom &lt;code&gt;mesh&lt;&#x2F;code&gt;, &lt;code&gt;material&lt;&#x2F;code&gt;, and &lt;code&gt;scale&lt;&#x2F;code&gt;, but everything else is a &quot;Default&quot; value.&lt;&#x2F;p&gt;
&lt;p&gt;While this flexibility is totally possible with constructors, it would require some creativity, maybe something like this?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; pbr_bundle &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;PbrBundle::new(mesh, material)
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with_scale&lt;&#x2F;span&gt;&lt;span&gt;(Vec3::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2.0&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with_visibility&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is fine, but it is a &lt;strong&gt;lot&lt;&#x2F;strong&gt; of toil for the author.
They need to add and maintain a method for each element of their nested struct, document those methods, probably write tests, and all to accomplish the goal of a &quot;Fill in the rest for me&quot; API.&lt;&#x2F;p&gt;
&lt;p&gt;One nice part of &lt;code&gt;Default&lt;&#x2F;code&gt; is it can be automagically added to any struct whose members implement it via &lt;code&gt;#[derive(Default)]&lt;&#x2F;code&gt;.
This means you get that &quot;Fill in the rest for me&quot; interface for free!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;close-but-distinct-types&quot;&gt;Close but Distinct Types&lt;&#x2F;h2&gt;
&lt;p&gt;Another pain-point I found in Rust was converting between similar but distinct types.
Unlike my last language Python, which was &lt;em&gt;very&lt;&#x2F;em&gt; forgiving about types (to a fault), Rust requires very precise type expressions.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take this example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Base Engine Color
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Default, Debug, PartialEq)]
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Color {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;red&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;green&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;blue&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;f32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F;&#x2F; Color for UI elements
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Default, Debug, PartialEq)]
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;UiColor(Color);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F;&#x2F; Just a demo function, not sure if this is useful...
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;color_rotate&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;color&lt;&#x2F;span&gt;&lt;span&gt;: Color) -&amp;gt; Color {
&lt;&#x2F;span&gt;&lt;span&gt;    Color {
&lt;&#x2F;span&gt;&lt;span&gt;        red: color.green,
&lt;&#x2F;span&gt;&lt;span&gt;        green: color.blue,
&lt;&#x2F;span&gt;&lt;span&gt;        blue: color.red,
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Does not compile!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; E0308: mismatched types expected struct `Color`, found struct `UiColor`
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; UiColor(Color {
&lt;&#x2F;span&gt;&lt;span&gt;        red: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.5&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;    });
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;color_rotate&lt;&#x2F;span&gt;&lt;span&gt;(a);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here we have a &lt;code&gt;UiColor&lt;&#x2F;code&gt; struct that wraps our base &lt;code&gt;Color&lt;&#x2F;code&gt; struct.
We want to use a method made for &lt;code&gt;Color&lt;&#x2F;code&gt; values but we get an error that the compiler is expecting a &lt;code&gt;Color&lt;&#x2F;code&gt; but we gave it a &lt;code&gt;UiColor&lt;&#x2F;code&gt;!
Come on Rust, just look inside the box!&lt;&#x2F;p&gt;
&lt;p&gt;We can work around this issue like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; UiColor(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;color_rotate&lt;&#x2F;span&gt;&lt;span&gt;(a.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which passes the inside of &lt;code&gt;a&lt;&#x2F;code&gt; to &lt;code&gt;color_rotate&lt;&#x2F;code&gt; and then wraps the return in a new &lt;code&gt;UiColor&lt;&#x2F;code&gt; struct.
This works, but it&#x27;s hard to read and more importantly it requires a keep our API in our head to write &lt;em&gt;any&lt;&#x2F;em&gt; code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-and-into-simple-type-coercion&quot;&gt;From and &lt;code&gt;into&lt;&#x2F;code&gt;: Simple type coercion&lt;&#x2F;h2&gt;
&lt;p&gt;The solution is to use the &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;convert&#x2F;trait.From.html&quot;&gt;&quot;From&quot;&lt;&#x2F;a&gt; and trait which provides the &lt;code&gt;into()&lt;&#x2F;code&gt; method.&lt;&#x2F;p&gt;
&lt;p&gt;Extending the above example, we can implement &lt;code&gt;From Color -&amp;gt; UiColor&lt;&#x2F;code&gt; and &lt;code&gt;From UiColor -&amp;gt; Color&lt;&#x2F;code&gt; like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;From&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Color&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;UiColor {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;: Color) -&amp;gt; UiColor {
&lt;&#x2F;span&gt;&lt;span&gt;        UiColor(input)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;From&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UiColor&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;Color {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;: UiColor) -&amp;gt; Color {
&lt;&#x2F;span&gt;&lt;span&gt;        input.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately we can&#x27;t do anything like &lt;code&gt;#[derive(From&amp;lt;UiColor&amp;gt;)]&lt;&#x2F;code&gt; (yet?) but implementing these traits is fairly straight forward and &lt;em&gt;very&lt;&#x2F;em&gt; powerful.&lt;&#x2F;p&gt;
&lt;p&gt;Here we can see our &lt;code&gt;main&lt;&#x2F;code&gt; function is fixed with passing assertions.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; UiColor(Color {
&lt;&#x2F;span&gt;&lt;span&gt;        red: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.5&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;    });
&lt;&#x2F;span&gt;&lt;span&gt;    assert_eq!(a, UiColor(Color { red: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.5&lt;&#x2F;span&gt;&lt;span&gt;, green: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;, blue: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0 &lt;&#x2F;span&gt;&lt;span&gt;}));
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; b: UiColor &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;color_rotate&lt;&#x2F;span&gt;&lt;span&gt;(a.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    assert_eq!(b, UiColor(Color { red: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;, green: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;, blue: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.5 &lt;&#x2F;span&gt;&lt;span&gt;}));
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rust was not only able to cast our &lt;code&gt;UiColor&lt;&#x2F;code&gt; to a &lt;code&gt;Color&lt;&#x2F;code&gt; in the call to &lt;code&gt;color_rotate&lt;&#x2F;code&gt; but we were able to coerce the result back to a &lt;code&gt;UiColor&lt;&#x2F;code&gt; by declaring the type of our &lt;code&gt;b&lt;&#x2F;code&gt; variable.&lt;&#x2F;p&gt;
&lt;p&gt;Using &lt;code&gt;From&lt;&#x2F;code&gt; and &lt;code&gt;into()&lt;&#x2F;code&gt; is great because it allows you to ignore the specifics of the types you&#x27;re working with while still getting the benefits of a strong type system.
When you use it enough it can feel like parts of your code are &quot;Duckly&quot; typed, like Python and Ruby which have very ergonomic type interactions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-simple-to-complex&quot;&gt;From Simple to Complex&lt;&#x2F;h2&gt;
&lt;p&gt;Since learning about &lt;code&gt;From&lt;&#x2F;code&gt; started to abuse it to convert simplified types to more complex ones.&lt;&#x2F;p&gt;
&lt;p&gt;Take for example this UI struct in Bevy:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;NodeBundle {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;node&lt;&#x2F;span&gt;&lt;span&gt;: Node,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;style&lt;&#x2F;span&gt;&lt;span&gt;: Style,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;color&lt;&#x2F;span&gt;&lt;span&gt;: UiColor,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: UiImage,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;focus_policy&lt;&#x2F;span&gt;&lt;span&gt;: FocusPolicy,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;transform&lt;&#x2F;span&gt;&lt;span&gt;: Transform,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;global_transform&lt;&#x2F;span&gt;&lt;span&gt;: GlobalTransform,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;visibility&lt;&#x2F;span&gt;&lt;span&gt;: Visibility,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On it&#x27;s own this isn&#x27;t bad, but if you write enough UI code it can get tedious.
Both &lt;code&gt;Node&lt;&#x2F;code&gt; and &lt;code&gt;Style&lt;&#x2F;code&gt; are nested structs that have a lot of complexity -- &lt;code&gt;Style&lt;&#x2F;code&gt; is a struct with 21 members! -- so using &lt;code&gt;Default&lt;&#x2F;code&gt; won&#x27;t cut it here.&lt;&#x2F;p&gt;
&lt;p&gt;Instead I made a &quot;dumbed down&quot; version like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;SimpleNodeBundle {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;position&lt;&#x2F;span&gt;&lt;span&gt;: SimplePosition,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;color&lt;&#x2F;span&gt;&lt;span&gt;: Color,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;size&lt;&#x2F;span&gt;&lt;span&gt;: Vec2,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;SimplePosition {
&lt;&#x2F;span&gt;&lt;span&gt;    BottomLeft,
&lt;&#x2F;span&gt;&lt;span&gt;    BottomRight,
&lt;&#x2F;span&gt;&lt;span&gt;    TopLeft,
&lt;&#x2F;span&gt;&lt;span&gt;    TopRight,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is maybe &lt;em&gt;too&lt;&#x2F;em&gt; simple, but you can add the complexity you need down the line. The important part is that our &lt;code&gt;Simple&lt;&#x2F;code&gt; struct is you know... less complex than what it&#x27;s going to map to.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have a simple struct that we can use to quickly write out some UI elements.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_ui_element &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; SimpleNodeBundle {
&lt;&#x2F;span&gt;&lt;span&gt;    position: SimplePosition::TopRight,
&lt;&#x2F;span&gt;&lt;span&gt;    size: Vec2 { x: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;25.0&lt;&#x2F;span&gt;&lt;span&gt;, y: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;100.0 &lt;&#x2F;span&gt;&lt;span&gt;},
&lt;&#x2F;span&gt;&lt;span&gt;    color: Color::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;RED&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On it&#x27;s own though this is useless.
Bevy doesn&#x27;t know what a &lt;code&gt;SimpleNodeBundle&lt;&#x2F;code&gt; is, we need to convert this to the &quot;lower level&quot; struct it&#x27;s replacing.
We need to cast it up to a Bevy &lt;code&gt;NodeBundle&lt;&#x2F;code&gt; with an implementation of &lt;code&gt;From&amp;lt;SimpleNodeBundle&amp;gt; for NodeBundle&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;From&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;SimpleNodeBundle&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;NodeBundle {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;from(input: SimpleNodeBundle) -&amp;gt; NodeBundle {
&lt;&#x2F;span&gt;&lt;span&gt;        NodeBundle {
&lt;&#x2F;span&gt;&lt;span&gt;            color: UiColor(input.color),
&lt;&#x2F;span&gt;&lt;span&gt;            style: Style {
&lt;&#x2F;span&gt;&lt;span&gt;                position: input.position.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;                size: input.size.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span&gt;(),
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; NodeBundle&amp;#39;s position is a Rect&amp;lt;Val&amp;gt; so we convert SimplePosition to Rect&amp;lt;Val&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;From&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;SimplePosition&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;Rect&amp;lt;Val&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;from(input: SimplePosition) -&amp;gt; Rect&amp;lt;Val&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;SimplePosition::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; input {
&lt;&#x2F;span&gt;&lt;span&gt;            BottomLeft  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Rect {
&lt;&#x2F;span&gt;&lt;span&gt;                bottom: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                left: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;            },
&lt;&#x2F;span&gt;&lt;span&gt;            BottomRight &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Rect {
&lt;&#x2F;span&gt;&lt;span&gt;                bottom: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                right: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;            },
&lt;&#x2F;span&gt;&lt;span&gt;            TopLeft     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Rect {
&lt;&#x2F;span&gt;&lt;span&gt;                top: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                left: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;            },
&lt;&#x2F;span&gt;&lt;span&gt;            TopRight    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; Rect {
&lt;&#x2F;span&gt;&lt;span&gt;                top: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                right: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;percent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default()
&lt;&#x2F;span&gt;&lt;span&gt;            },
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Similarly size is a Size&amp;lt;Val&amp;gt; but we have a Vec2, so we conver to the right type
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;From&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Vec2&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;Size&amp;lt;Val&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;from(input: Vec2) -&amp;gt; Size&amp;lt;Val&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        Size {
&lt;&#x2F;span&gt;&lt;span&gt;            width: Val::Px(input.x),
&lt;&#x2F;span&gt;&lt;span&gt;            height: Val::Px(input.y),
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Putting this all together we get (pseudocode) something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; my_ui_element &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; SimpleNodeBundle {
&lt;&#x2F;span&gt;&lt;span&gt;    position: SimplePosition::TopRight,
&lt;&#x2F;span&gt;&lt;span&gt;    size: Vec2 { x: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;25.0&lt;&#x2F;span&gt;&lt;span&gt;, y: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;100.0 &lt;&#x2F;span&gt;&lt;span&gt;},
&lt;&#x2F;span&gt;&lt;span&gt;    color: Color::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;RED&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;some_bevy_ui_method&lt;&#x2F;span&gt;&lt;span&gt;(my_ui_element.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;into&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Skeptical readers might be thinking &quot;Wow that is awful.
This is so much code just to convert one stuct to another slightly simpler struct&quot;.
You&#x27;re right that it&#x27;s a lot of code, but I promise in practice this is a game changer.
Instead of remembering how to express your ideas to your library of choice every single time, you can express a higher level concept and &lt;code&gt;.into()&lt;&#x2F;code&gt; your framework&#x27;s lower-level structure.
Being able to succinctly express yourself while still getting the flexibility of a strong expressive type system is a killer feature of Rust and the use of these traits.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Many of Rust&#x27;s &quot;pros&quot; are also &quot;cons&quot;.
Memory safety results in frustratingly negotiating with the compiler.
A strong type system with compile-time complexity results in slow (but improving) compile times.&lt;&#x2F;p&gt;
&lt;p&gt;For the purposes of this post it is Rust&#x27;s bias toward being explicit.
Unlike other languages which automagically apply crazy changes to your code, Rust rarely &lt;em&gt;assumes&lt;&#x2F;em&gt; you want magic sprinkled everywhere.
You can opt-in to that magic and all of the compile-time and runtime penalties that come with it, but it won&#x27;t be secretly given to you for you to
opt-out of.&lt;&#x2F;p&gt;
&lt;p&gt;Rust can sprinkle magic on your code, but you have to explicitly call &lt;code&gt;.magic()&lt;&#x2F;code&gt; -- or in our case &lt;code&gt;.into()&lt;&#x2F;code&gt; and &lt;code&gt;.default()&lt;&#x2F;code&gt;.
This is a nice middle ground between tedious code and black magic.
When a language has &lt;em&gt;too much&lt;&#x2F;em&gt; magic it can result in wild performance implications from seemingly small code changes.
While tedious code is just a pain to write, even if it is transparent about it&#x27;s runtime performance.
Here Rust is able to be transparent, you can audit every use of &lt;code&gt;.into()&lt;&#x2F;code&gt; and assess the runtime penalty, while still feeling magical.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Buying a House Part 4: Is this investing?</title>
        <published>2022-01-18T00:00:00+00:00</published>
        <updated>2022-01-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/buying-a-house-04-is-this-investing/"/>
        <id>https://elijah.run/blog/buying-a-house-04-is-this-investing/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/buying-a-house-04-is-this-investing/">&lt;p&gt;&lt;em&gt;This is part 4 of a 4 part series on buying a home&lt;&#x2F;em&gt;.
&lt;em&gt;Check out &lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-01-lets-go-shopping&#x2F;&quot;&gt;part 1&lt;&#x2F;a&gt; for to start from the beginning.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Before buying a house a major talking point used to convince me of the idea was some variation of &quot;It&#x27;s a great investment!&quot; or &quot;You&#x27;re just throwing money away by renting&quot;.
I try to have a healthy level of skepticism about things, especially when counter-arguments aren&#x27;t part of most the usual talking points on a topic.
So let&#x27;s figure out &quot;is buying a house a good investment?&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;houses-are-a-great-investment-origin-story&quot;&gt;&quot;Houses are a great investment&quot; origin story&lt;&#x2F;h2&gt;
&lt;p&gt;Before de-bunking -- or just bunking -- this myth, let&#x27;s ask where it came from.&lt;&#x2F;p&gt;
&lt;p&gt;Hundreds of years ago, when you had to own property to be considered a voting citizen, investing in property was a great idea! Housing was the most affordable asset you could buy that could passively grow in value.&lt;&#x2F;p&gt;
&lt;p&gt;As the years went on this continued to be true.
Housing is a market rarely which declines value, with umm... one big exception, and it can easily be passed on to family, creating generational wealth.&lt;&#x2F;p&gt;
&lt;p&gt;This notion also pre-dates easier market investing tools like the index fund, Vanguard, and Robinhood.
When it wasn&#x27;t really clear how an average individual could get a diversified portfolio of stocks and bonds, a house was a safe investment that was all but guaranteed to increase in value -- and it would protect you from snow and rain and
shit!&lt;&#x2F;p&gt;
&lt;p&gt;So the origin story of this mantra isn&#x27;t &lt;em&gt;false&lt;&#x2F;em&gt;, but it may be outdated.
Let&#x27;s find out.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;meet-finley&quot;&gt;Meet Finley&lt;&#x2F;h2&gt;
&lt;p&gt;For the purposes of this post we will invent a hypothetical protagonist named Finley.
Our fictional mascot was created in a lab to be incredibly average: the most basic curve-fitting person we could find in the the Portland tri-state area.
Finley likes all the Marvel movies, drinks IPAs, and they go on hikes every other weekend.
They also make an average salary, live in an average apartment, and intend to buy an average house.
How convenient for talking about hypotheticals.&lt;&#x2F;p&gt;
&lt;p&gt;Finley lives in Portland, so all of our numbers are for Portland Oregon, USA.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;first-finley-rents-an-apartment&quot;&gt;First Finley rents an apartment&lt;&#x2F;h3&gt;
&lt;p&gt;Finley is currently renting an apartment. On average this is $1250 for the Portland area.
This is roughly equivalent to what you would pay for a mortgage on a 300k house with a 20% (60k) down payment and a 3.0% interest rate (which is only a little optimistic).&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s what I used to cook up those numbers: *
&lt;a href=&quot;https:&#x2F;&#x2F;www.mortgagecalculator.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.mortgagecalculator.org&#x2F;&lt;&#x2F;a&gt; *
&lt;a href=&quot;https:&#x2F;&#x2F;www.realtor.com&#x2F;mortgage&#x2F;rates&#x2F;Portland_OR&quot;&gt;https:&#x2F;&#x2F;www.realtor.com&#x2F;mortgage&#x2F;rates&#x2F;Portland_OR&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;then-finley-buys-a-house&quot;&gt;Then Finley buys a house&lt;&#x2F;h3&gt;
&lt;p&gt;In 2020, when I bought a house, the median house prices ranged from 430k to 500k trending upward.
In the last 12 months from writing this post median home prices have ranged from 469k to 550k with a trend still going up.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.redfin.com&#x2F;city&#x2F;30772&#x2F;OR&#x2F;Portland&#x2F;housing-market&quot;&gt;https:&#x2F;&#x2F;www.redfin.com&#x2F;city&#x2F;30772&#x2F;OR&#x2F;Portland&#x2F;housing-market&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For simplicity let&#x27;s say Finley got a deal and bought a house for 480k with a 3.0% mortgage rate.
Their down-payment is 96k and their monthly mortgage payment is $1,900.&lt;&#x2F;p&gt;
&lt;p&gt;Right off the bat Finley is paying 650 more per month on top of the 96k they had to pay up front.
Let&#x27;s assume Finley is still able to cover this cost since they&#x27;re very frugal and despite cost of living going up 34% they are still spending less than 1&#x2F;3 of their income on living expenses.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-money-works-for-you&quot;&gt;How money works for you&lt;&#x2F;h2&gt;
&lt;p&gt;What has Finley &lt;em&gt;financially&lt;&#x2F;em&gt; gained and lost by buying a house?&lt;&#x2F;p&gt;
&lt;p&gt;Finley has &lt;em&gt;lost&lt;&#x2F;em&gt; the ability to invest a lump sum of 96k on top of an extra 600&#x2F;month which could be going toward a range of investments.
Assuming Finley would have invested this in a stock market index we expect this to have increased in value by about 10% year over year given historical trends.
To put numbers to these claims: 96k alone would have appreciated in value to 1,600,000 over 30 years, the duration of most home loans.
If we add the additional 600&#x2F;month we would have about 2,860,000 after 30 years.&lt;&#x2F;p&gt;
&lt;p&gt;(these are very rough calculations using this python code)&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;600 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;12  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Annual investable income
&lt;&#x2F;span&gt;&lt;span&gt;s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;96000     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Starting seed fund
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;30&lt;&#x2F;span&gt;&lt;span&gt;):  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Collect 30 years
&lt;&#x2F;span&gt;&lt;span&gt;  s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.1           &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Grow by 10% for the year
&lt;&#x2F;span&gt;&lt;span&gt;  s &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+= &lt;&#x2F;span&gt;&lt;span&gt;a             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Add money saved by renting
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(this is a very rough approximation of collecting interest over 30 years)&lt;&#x2F;p&gt;
&lt;p&gt;Note this doesn&#x27;t mean he are guaranteed to have 2.9 million at the end of 30 years; some of those gains would be diminished by inflation, rent would go up, and the market could have a down-turn at the 30 year mark.
Plus, Finley would probably spend more as they get older (called &quot;lifestyle inflation&quot;) resulting in diminished invest-able funds -- but they would also probably get cost of living raises over time, so this should all come out in the wash.&lt;&#x2F;p&gt;
&lt;p&gt;But a house would &lt;em&gt;also&lt;&#x2F;em&gt; grow in value right?
This is tricky to calculate because we&#x27;re in a weird housing market right now -- don&#x27;t
call it a bubble -- but let&#x27;s take the last 10 years at face value.
In 2011 the median Portland house was ~260k, and today it is ~550k.
This is a 111% return over 10 years, or 7.82% annually.&lt;&#x2F;p&gt;
&lt;p&gt;So if Finley sold their house after 10 years they would make a profit of ~290k.&lt;&#x2F;p&gt;
&lt;p&gt;I neglected to calculate what Finely&#x27;s index fund strategy would return after only 10 years, so let&#x27;s do that now.
Using the above code, but limiting it to just 10 years instead of 30, we get a ~363k total which does beat the housing investment by a fair margin.
&lt;a href=&quot;https:&#x2F;&#x2F;www.calculator.net&#x2F;roi-calculator.html?beginbalance=259000&amp;amp;endbalance=550000&amp;amp;investmenttime=date&amp;amp;investmentlength=2.5&amp;amp;beginbalanceday=08%2F01%2F2011&amp;amp;endbalanceday=08%2F01%2F2021&amp;amp;ctype=1&amp;amp;x=69&amp;amp;y=36&#x2F;&quot;&gt;citation needed&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note that I am omitting all of the nickles and dimes that add up on both sides.
Capital gains tax makes your index fund strategy less appealing.
Home ownership means you are on the hook to fix anything that breaks, pay property tax, and there are fees associated with buying and selling a home -- plus the cost of the loan which we didn&#x27;t touch on at all!
At the same time, all the money Finley was paying in rent really was being flushed away and not appreciating in value, which is a shame.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;elijah-just-tell-me-if-it-s-good-or-bad&quot;&gt;Elijah, just tell me if it&#x27;s good or bad&lt;&#x2F;h2&gt;
&lt;p&gt;A house is not a great investment, but that&#x27;s not the point.&lt;&#x2F;p&gt;
&lt;p&gt;I didn&#x27;t buy a house because it was a good investment, I bought a house because I wanted more space and it penciled out to about the same monthly cost as my super expensive bougie central-Portland apartment.
I am glad that my house will re-coop some cost when I decide to move out, and I do like the stability of home ownership; I don&#x27;t need to worry about rent going up, or getting evicted because my landlord wants to demolish the building for something else, etc.&lt;&#x2F;p&gt;
&lt;p&gt;So many variables go into the &quot;is this a good investment&quot; question.
If you need to stretch yourself thin, or you already have debt, or what the monthly cost is -- all of these and more contribute to the viability of buying a house.
If your monthly housing costs wouldn&#x27;t go up, it&#x27;s probably a solid move.&lt;&#x2F;p&gt;
&lt;p&gt;Home ownership is not perfect, it&#x27;s not a great investment, but it is an OK use of your money if you can afford it.
It&#x27;s financially sound if you can make it work, comfortably, but it&#x27;s not your only option.
Being frugal and renting an affordable apartment allows you to make other &quot;better&quot; investments, if that&#x27;s all you&#x27;re min-maxing for.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t regret buying a house (yet?) but I would be just as happy if I was renting a house, or still living in an apartment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-more-soap-box&quot;&gt;One more soap-box&lt;&#x2F;h2&gt;
&lt;p&gt;Side note: we need to build more housing.
Portland passed a bill recently allowing more dense housing.
If I had more money I would throw money at building triplex housing in Portland.&lt;&#x2F;p&gt;
&lt;p&gt;For too many of my 20-something peers the problem is not &quot;If I want to buy a house&quot; but &quot;When can I afford to buy a house?&quot;.
There is a bit of a market boom right now, but with more housing the market should settle down.
In a perfect world anybody would be able to buy property if they want.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Thank you for reading this fourth and final installment of my housing series.
Now go out a buy a house!&lt;&#x2F;p&gt;
&lt;p&gt;Lol, just kidding.
Go do more research you crazy kid.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Buying a House Part 3: Renovation Station!</title>
        <published>2022-01-04T00:00:00+00:00</published>
        <updated>2022-01-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/buying-a-house-03-renovation-station/"/>
        <id>https://elijah.run/blog/buying-a-house-03-renovation-station/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/buying-a-house-03-renovation-station/">&lt;p&gt;&lt;em&gt;This is part 3 of a 4 part series on buying a home&lt;&#x2F;em&gt;.
&lt;em&gt;Check out &lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-01-lets-go-shopping&#x2F;&quot;&gt;part 1&lt;&#x2F;a&gt; for to start from the beginning.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Congratulations!
You slogged through finding, trying to buy, and then successfully buying a house.
Give yourself a pat on the back because that is an impressive feat you&#x27;ve accomplished.&lt;&#x2F;p&gt;
&lt;p&gt;This post is more of a personal post than the others covering the renovations we&#x27;ve made to our house in the first year.
I hope it helps illustrate some of the pros (and cons) of being able to do whatever the heck you want when you own the place.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;let-s-fuck-up-this-yard&quot;&gt;Let&#x27;s fuck up this yard&lt;&#x2F;h2&gt;
&lt;p&gt;The best part of our house has been the back yard.
I&#x27;m writing this post from my standing desk on my back patio, our doggo loves playing fetch in the yard, and we even started a garden.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;patiooooo&quot;&gt;Patiooooo&lt;&#x2F;h3&gt;
&lt;p&gt;Our first project was to build a stone patio.
Not some half-assed &quot;throw some rocks on the ground and call it good&quot; thing, but some real HGTV quality shit.&lt;&#x2F;p&gt;
&lt;p&gt;Lucy of course did all of the research, planning, and purchasing of materials.
I moved a bunch of rocks.&lt;&#x2F;p&gt;
&lt;p&gt;Before we could build the patio we had to dig 7&quot; of dirt out from the ground, which is non-trivial.
We invited some friends, bought Thai food, and got to work in late October.&lt;&#x2F;p&gt;
&lt;p&gt;Fun fact: 7&quot; of dirt for a 10&quot;x16&quot; hole is a shit-ton of dirt.
We eventually had to rent one of those big metal waste disposal bins you usually see in front of houses or other construction sites.
Of course then we had to move the dirt a second time from piles in our yard to the bin, but then it was gone for good.&lt;&#x2F;p&gt;
&lt;p&gt;Once we dug out the dirt we were able to fill it back in with rocks (pebbles) then smaller rocks (sand) and finally pavers, which is what the industry calls short cube rocks -- not to be confused with bricks.&lt;&#x2F;p&gt;
&lt;p&gt;The hardest part was definitely making everything flat.
The pavers are big squares, which I though would be forgiving if the underlying sand and gravel wasn&#x27;t flat, but wow I was wrong.
Eventually I found my groove and got very zen about making the sand flat.
We used used a 10&#x27; 2x4 and dragged it across our layer of sand in a variety of patterns until eventually it was &quot;flat enough&quot;.
In retrospect it was kinda fun.
Very calming once you submit to the process.&lt;&#x2F;p&gt;
&lt;p&gt;Finally we put the pavers down, filled the cracks with polymeric sand (which is just &quot;concrete lite&quot;), and sealed that bitch up.&lt;&#x2F;p&gt;
&lt;p&gt;The whole project took a few weeks and cost about 1k for materials.&lt;&#x2F;p&gt;
&lt;p&gt;We almost gave up at the end when we realized making things flat was way harder than expected.
The quote to get the project finished, which was 90% done, was around 5k which gave us heart-burn so we stubbornly finished it ourselves.
So it turns out we saved ~5k by doing this project ourselves.&lt;&#x2F;p&gt;
&lt;p&gt;After this I&#x27;m game to do any home project myself as long as it doesn&#x27;t involve electricity and plumbing in the walls.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;baby-you-re-a-fiiiireee-pit&quot;&gt;Baby you&#x27;re a fiiiireee-pit&lt;&#x2F;h3&gt;
&lt;p&gt;A comparatively small project was our fire pit.
This was just a fire ring with some bricks stacked on the outside.
Very safe, very simple.&lt;&#x2F;p&gt;
&lt;p&gt;Honestly it was nice to get a quick win.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;big-ass-raised-bed&quot;&gt;Big ass raised bed&lt;&#x2F;h3&gt;
&lt;p&gt;We also built a big ass raised bed.
It&#x27;s 4&#x27;x12&#x27; and it gets a &lt;em&gt;lot&lt;&#x2F;em&gt; of sun.
Also a quick win.&lt;&#x2F;p&gt;
&lt;p&gt;Everything feels like a quick win after building that fucking patio.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-hvac-who-this&quot;&gt;New HVAC, who this?&lt;&#x2F;h2&gt;
&lt;p&gt;In December ancient gas furnace ran out of diesel, resulting in not having heat... funny how that works.
This is usually trivial to solve: you call a company and they fill your gas tank and charge you a few hundo.
With gas in the tank your heat comes back on.&lt;&#x2F;p&gt;
&lt;p&gt;Multiple people talked about how great the furnace we had was.
It was installed with the house, so it was at least 70 years old and it did work well.
The heat that came out of the vents was super hot, but it also ran on gasoline in a tank in our basement.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m sure the carbon footprint of my home&#x27;s gas heating is negligible when compared to the carbon footprint of every flight I take, but Lucy and I decided if we &lt;em&gt;could&lt;&#x2F;em&gt; get rid of it we &lt;em&gt;should&lt;&#x2F;em&gt;.
We did some research on alternatives and decided an electric Heat-Pump would be a good alternative.
It would provide us with heat &lt;em&gt;and&lt;&#x2F;em&gt; cooling, and wouldn&#x27;t run on diesel; the only downside is it&#x27;d be expensive.&lt;&#x2F;p&gt;
&lt;p&gt;A few things:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;A Heat-Pump is a heating and cooling system that operates on similar physics to a refrigerator (taking warm air and turning it into cool air, and the inverse).&lt;&#x2F;li&gt;
&lt;li&gt;The Heat-Pump has an outdoor unit, you&#x27;ve definitely seen them outside some homes.
Usually it&#x27;s a metal box about 3&quot; cubed with a fan.&lt;&#x2F;li&gt;
&lt;li&gt;They don&#x27;t tell you that&#x27;s just the &lt;em&gt;outdoor&lt;&#x2F;em&gt; part of the Heat-Pump, there is also a huge freaking indoor unit that converts chemical energy into warm&#x2F;cool air that gets pumped around your house.&lt;&#x2F;li&gt;
&lt;li&gt;Heat-pumps are fully electric so no gas!&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;So that&#x27;s how a Heat-Pump works.
A few stars aligned for this to work out:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Our house already has vents that the oil furnace used to heat the house.
This means we can easily heat&#x2F;cool the entire house with one indoor unit.&lt;&#x2F;li&gt;
&lt;li&gt;We had some extra cash we didn&#x27;t end up needing for our down-payment, so we were able to pay in cash saving us a lot in interest payments for the Heat-Pump (like 10%!).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;We could have made it work without those happy coincidences; they make in-wall Heat-Pumps that heat&#x2F;cool one or two rooms, and we could have financed if we were strapped for cash, or we could have just kept the old gas furnace.
But we &lt;em&gt;were&lt;&#x2F;em&gt; able to upgrade our central-air because 6 months later Portland had a 118℉  heat wave and another 100℉+ heat wave the day before our wedding!
Both of which we barely worried about because we were fortunate enough to have AC.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;life-after-renting&quot;&gt;Life after renting&lt;&#x2F;h2&gt;
&lt;p&gt;I hope this post showed some of the awesome pros of home ownership, like being able to add a patio, with some healthy cons, like having to spend 12k on a new furnace.
We were able to get rid of the gas guzzling heating system in favor of a full-electric system.
We were able to build a patio, add a raised bed, fuck up the yard, without asking anybody for permission.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s a lot of work, and a lot of money sometimes, but it is empowering to be able to &lt;em&gt;own&lt;&#x2F;em&gt; your house.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;In the next post we&#x27;ll throw all this soft &quot;american dream&quot; and
&quot;empowered to change&quot; stuff out the window and figure out if this is a
good investment!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Buying a House Part 2: Show Me The Money!</title>
        <published>2021-12-21T00:00:00+00:00</published>
        <updated>2021-12-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/buying-a-house-02-show-me-the-money/"/>
        <id>https://elijah.run/blog/buying-a-house-02-show-me-the-money/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/buying-a-house-02-show-me-the-money/">&lt;p&gt;&lt;em&gt;This is part 2 of a 4 part series on buying a home&lt;&#x2F;em&gt;.
&lt;em&gt;Check out &lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-01-lets-go-shopping&#x2F;&quot;&gt;part 1&lt;&#x2F;a&gt; for to start from the beginning.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this post we will talk about everything that happens between getting an offer accepted on a house and your move-in day.
How exciting!
Let&#x27;s get started.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;so-you-got-an-offer-accepted&quot;&gt;So you got an offer accepted&lt;&#x2F;h2&gt;
&lt;p&gt;You slogged through the home-buying process, your heart was broken in 12 pieces when you barely didn&#x27;t get &quot;the one&quot; and then &quot;the other one&quot; and finally &quot;the real one&quot;, but you powered through and now you have an offer accepted.&lt;&#x2F;p&gt;
&lt;p&gt;Great, you&#x27;re half way done!
Just kidding, this part is much easier, but it is time consuming.&lt;&#x2F;p&gt;
&lt;p&gt;Now in theory you can skip all these steps with a shit-ton of money and taking a shot of unnecessary risk.
I mean you can pay in cash for a house &lt;em&gt;and&lt;&#x2F;em&gt; waive home inspections to expedite the home-buying process.
I only have one anecdote of this happening, and the guy who told it to me was a prick, so I&#x27;m pretty sure it&#x27;s fake news.
The only reason you would pay in cash is to avoid paying mortgage fees and to close the deal faster.
The only reason you would waive inspections is to make close on the house faster if you don&#x27;t care or really trust the current owner.
Mortgage rates are bonkers low right now, and most people aren&#x27;t in &lt;em&gt;that much&lt;&#x2F;em&gt; of a rush to close on their house, so again: fake news.
For normal people with a normal amount of debt and a sane income we do things the way I&#x27;m about to describe.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Steps down from soap-box&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now that your offer is accepted you have a 30 day clock.
At the end of those 30 days you will hopefully have a house.
Very cool.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;inspections&quot;&gt;Inspections&lt;&#x2F;h2&gt;
&lt;p&gt;The first step is to schedule home inspections.
Your realtor should do this.
You will schedule a standard home inspection, but you can also request special inspections if you are concerned.
For example we tested for Radon and buried oil tanks, because both of those are shitty things in Portland.
These inspections are one of the few fees paid by the buyer because you as the buyer can be as picky as you want about the
inspections.&lt;&#x2F;p&gt;
&lt;p&gt;Once the inspections happen you&#x27;ll do a walk-through.
Often this is the &lt;em&gt;second time you have seen the house in person&lt;&#x2F;em&gt;, which I just find hilarious.
The inspector should walk you through the house and tell you literally everything wrong with the house that they can find.
They might also mention any concerns they have based on the listing&#x27;s disclosures and the year the house was built&#x2F;renovated.
The inspector shouldn&#x27;t have any horse in this race, they&#x27;re getting paid weather the deal falls through or not, so they should be pretty matter-of-fact.
This means they might tell you some scary shit like &quot;This ceiling is probably asbestos, don&#x27;t touch it until you get that tested&quot;, this is just because you need to know everything that might be a deal breaker before the next step.&lt;&#x2F;p&gt;
&lt;p&gt;Once the walk-through is complete your inspector will write up an inspection report and send it to you and your realtor for you to review and keep.
This is a very long, very boring, and very important document.
Keep a copy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;negotiations&quot;&gt;Negotiations&lt;&#x2F;h2&gt;
&lt;p&gt;Now that you know everything about the house:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Disclosures given in the house listing.&lt;&#x2F;li&gt;
&lt;li&gt;Inspection results.&lt;&#x2F;li&gt;
&lt;li&gt;You&#x27;ve been inside like... twice.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can enter the negotiation phase fully informed.
Negotiations are not done in a board room -- I wish -- they&#x27;re done asynchronously by the seller and buyer&#x27;s realtors.&lt;&#x2F;p&gt;
&lt;p&gt;You sit down &lt;strong&gt;with your realtor&lt;&#x2F;strong&gt; and go over the inspection results.
If your realtor is good they&#x27;ll basically do the negotiation for you, reviewing what the plan is before locking it in.&lt;&#x2F;p&gt;
&lt;p&gt;For example, our realtor said the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The pipes are clogged with baby wipes or something, that can take 7k to fix so let&#x27;s ask to knock off 7k.&lt;&#x2F;li&gt;
&lt;li&gt;The garage door is busted, let&#x27;s ask to take 5k off for that.&lt;&#x2F;li&gt;
&lt;li&gt;Some other stuff got knocked off but I don&#x27;t remember it a year later.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We figure out how much to ask for by basically looking up how much it would reasonably cost to fix broken shit.
If your roof was caving in you would be able to ask to take a lot, if a stair was busted that would probably be less.&lt;&#x2F;p&gt;
&lt;p&gt;You can&#x27;t get away with asking for price reductions for &lt;em&gt;aesthetic&lt;&#x2F;em&gt; differences, like you wish the house had more outlets, but you could ask to get the price knocked if the electrical was unsafe.&lt;&#x2F;p&gt;
&lt;p&gt;Your realtor should then write this up and send it to the seller&#x27;s realtor who will respond with a counter.
Sometimes they will choose to fix broken things themselves or they may drop the price for a given request.
In our case the owner dropped the price a bit, around 3k, and spent her own money to fix clogged pipes, which cost a few thousand.&lt;&#x2F;p&gt;
&lt;p&gt;In the negotiation the seller has an incentive to keep the final price fairly high while the buyer has an incentive to get the price as low as possible.
This means sellers might find more expensive quotes and the buyer might find cheaper quotes for repair costs.
But both parties have an incentive to complete the sale of the house.&lt;&#x2F;p&gt;
&lt;p&gt;If a seller refuses to negotiate on the price of the house, the buyer at this point has the option to pull out of the deal.
The buyer will most likely get their Earnest Money back because they found something out about the house after the offer was accepted which the buyer refused to fix or decrease the price for.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;but-what-does-the-bank-think-it-s-worth&quot;&gt;But what does the bank think it&#x27;s worth?&lt;&#x2F;h2&gt;
&lt;p&gt;After negotiating on a price the bank gets involved again.
It takes the bank under a week to, given the home inspection plus their piles of data, determine what they think it&#x27;s worth.
This has very little to do with what you thought it was worth and it is what the bank is willing to cover in the form of a home loan.&lt;&#x2F;p&gt;
&lt;p&gt;If the bank decides the house is worth &lt;em&gt;more&lt;&#x2F;em&gt; than the final offer you&#x27;re golden.
You get a loan for the negotiated price and it&#x27;ll be 100% covered by the bank.&lt;&#x2F;p&gt;
&lt;p&gt;For example: If the final offer is 100k and the bank decides the house is worth 105k, you need to do the normal 20% down payment, and then you get an 80k loan for the rest.&lt;&#x2F;p&gt;
&lt;p&gt;... But if the bank decides the house is worth &lt;em&gt;less&lt;&#x2F;em&gt; than the final offer you&#x27;re some amount of fucked.
You need to pay the difference out of pocket, or pull out of the deal.&lt;&#x2F;p&gt;
&lt;p&gt;For example: If the final offer is 100k but the bank decides the house is worth 60k, you need to cover 20k down payment, plus the 20k difference on the remaining cost.
100k - 20k = 80k ideal loan.
80k - 20k = 60k what the bank will actually loan you.&lt;&#x2F;p&gt;
&lt;p&gt;Note, I&#x27;m using 100k as a round number for math examples.
This is not some cruel joke, it&#x27;s just easier numbers.
Most houses we looked at were between 350k and 600k.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;side-note-why-do-we-need-down-payments&quot;&gt;Side note, why do we need down payments?&lt;&#x2F;h3&gt;
&lt;p&gt;Wait, why do we have down payments?
It&#x27;s complicated, but I &lt;em&gt;think&lt;&#x2F;em&gt; it&#x27;s a collection of reasons:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The more you pay up front, the less monthly payments you have.
20% up front is a good way to reduce your monthly payments from the get-go.&lt;&#x2F;li&gt;
&lt;li&gt;Credit worthiness or some bullshit.
Banks want to make sure you have skin in the game, so before you can get approved for a loan you need to prove you have 20%+ of the cost of the house for them to cover the other 80%.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That&#x27;s my best bet.
Ask a realtor or your local economist or banker or something; they&#x27;ll probably have a better answer.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Once the bank settles on a price you can close on the house.
You&#x27;ll get a real loan for the final price (minus the difference you&#x27;ve paid in cash).
Finally, 30 days (ish) after getting your offer accepted you&#x27;ll walk into a title company, go over a stack of papers with a professional, sign a bunch of those papers, and walk out the proud owner of a house.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-now&quot;&gt;What now?&lt;&#x2F;h2&gt;
&lt;p&gt;We had to wait a few weeks after closing to actually move in.
The previous owner needed the funds from closing to close on her own house, but that ended up going faster than expected so we only had to stay at my parents house (#privilege #safetynet) for two weeks.&lt;&#x2F;p&gt;
&lt;p&gt;Your realtor should give you some keys for the new house.
I suggest throwing those out once you&#x27;re moved in and replace the locks -- even in a nice neighborhood, you have no idea who has the old keys.&lt;&#x2F;p&gt;
&lt;p&gt;Rent a moving van and bribe your friends, or hire some movers if you&#x27;re smart, and enjoy your beautiful house!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Wait, is this pipe supposed to be leaking?
In the next post we&#x27;ll talk about home renovations!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Dynamic Dispatch in Python</title>
        <published>2021-09-02T00:00:00+00:00</published>
        <updated>2021-09-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/python-dynamic-dispatch/"/>
        <id>https://elijah.run/blog/python-dynamic-dispatch/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/python-dynamic-dispatch/">&lt;p&gt;🦝 Hey want tO see a nEat PYtHoN triCK?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;hiya &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;format&lt;&#x2F;span&gt;&lt;span&gt;(name))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt;()[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;](&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Spongebob&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;🐮 Oh cool, does that use the string &lt;code&gt;&quot;f&quot;&lt;&#x2F;code&gt; to find--&lt;&#x2F;p&gt;
&lt;p&gt;🦝 DoEs It FiNd ThE fUnCtIoN &lt;code&gt;&quot;f&quot;&lt;&#x2F;code&gt; aNd CaLl iT?? yEaH It DoEs.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ python script.py
&lt;&#x2F;span&gt;&lt;span&gt;hiya Spongebob
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;🐮 Oh that&#x27;s neat. I didn&#x27;t know you could do that with Python--&lt;&#x2F;p&gt;
&lt;p&gt;🦝 whaTEveR i dON&#x27;t cArE wHaT YOU tHinK.&lt;&#x2F;p&gt;
&lt;p&gt;🐮 You asked me --&lt;&#x2F;p&gt;
&lt;p&gt;🦝 I sAiD sHuT uP. i&#x27;M dOiNg HoT gIrL sHiT.&lt;&#x2F;p&gt;
&lt;p&gt;🐮 Are you ok? You&#x27;re yelling a lot about Python again--&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# shut up
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;test_patrick&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span&gt;: TestContext):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# do thing
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;test_crabs&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;context&lt;&#x2F;span&gt;&lt;span&gt;: TestContext):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# do other thing
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;context &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;TestContext&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;tests &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;locals&lt;&#x2F;span&gt;&lt;span&gt;():
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;t.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;startswith&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;test_&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;        tests.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span&gt;(t)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;test &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;tests:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(context)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;🐮 Oh so you could...&lt;&#x2F;p&gt;
&lt;p&gt;🦝 ...&lt;&#x2F;p&gt;
&lt;p&gt;🐮 Are you going to interrupt me?&lt;&#x2F;p&gt;
&lt;p&gt;🦝 Not yet.&lt;&#x2F;p&gt;
&lt;p&gt;🐮 Ok... you could search your scope and find a bunch of functions with a name and common interface--&lt;&#x2F;p&gt;
&lt;p&gt;🦝 AND CALL THEM! DYNAMIC DISPATCH!!&lt;&#x2F;p&gt;
&lt;p&gt;🐮 That&#x27;s nice.&lt;&#x2F;p&gt;
&lt;p&gt;🦝 YEAH IT IS COOL!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Buying a House Part 1: Let&#x27;s Go Shopping!</title>
        <published>2021-08-26T00:00:00+00:00</published>
        <updated>2021-08-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/buying-a-house-01-lets-go-shopping/"/>
        <id>https://elijah.run/blog/buying-a-house-01-lets-go-shopping/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/buying-a-house-01-lets-go-shopping/">&lt;p&gt;So you&#x27;re interested in buying a house eh?
Well boy howdy do I have a series of blog posts for you.
This four part series will equip you, a first-time home buyer, with a bunch of knowledge I wish I had before starting my journey to buying a home.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the road-map:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-01-lets-go-shopping&#x2F;&quot;&gt;Part 1: 🛒 Let&#x27;s Go Shopping!&lt;&#x2F;a&gt; in which we start looking for houses.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-02-show-me-the-money&#x2F;&quot;&gt;Part 2: 💸 Show Me the Money!&lt;&#x2F;a&gt; in which we buy a freaking house.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-03-renovation-station&#x2F;&quot;&gt;Part 3: 👷 Renovation Station.&lt;&#x2F;a&gt; in which we live in the freaking house.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-04-is-this-investing&#x2F;&quot;&gt;Part 4: 📈 Is This Investing?&lt;&#x2F;a&gt; where we figure out if we made a huge financial mistake (or achievement!)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;hey-quick-disclaimer&quot;&gt;Hey, quick disclaimer&lt;&#x2F;h2&gt;
&lt;p&gt;Some things I &lt;strong&gt;can&lt;&#x2F;strong&gt; claim to be an expert on: Docker, Linux, why my dog is making that face, etc.
But with home-buying I am at best a novice, so please take everything you read here with a grain of salt.&lt;&#x2F;p&gt;
&lt;p&gt;I am just one lowly home owner in his mid-20s who bought a house during a pandemic.
I got here through a bunch of privilege, support, luck, and the modest amount amount of hard work &lt;em&gt;required&lt;&#x2F;em&gt; to live a wonderful mortgage-filled life.&lt;&#x2F;p&gt;
&lt;p&gt;I am not a financial advisor, realtor, none of that stuff.
I encourage you to do independent research, check my work, etc.
Don&#x27;t make any decisions based purely on this series.
Please use it as one of many sources in your research before buying a house.&lt;&#x2F;p&gt;
&lt;p&gt;Okay, &lt;strong&gt;now&lt;&#x2F;strong&gt; we can get started.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;so-um-why-do-you-want-to-buy-a-house&quot;&gt;So um, why do you want to buy a house?&lt;&#x2F;h2&gt;
&lt;p&gt;Before diving into the home buying process, let&#x27;s ask an annoyingly
simple (but annoyingly effective) question: &quot;why?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s a million reasons to want to buy a house.
A few that come to mind are&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;You want more space or a yard.&lt;&#x2F;li&gt;
&lt;li&gt;You want an investment.&lt;&#x2F;li&gt;
&lt;li&gt;You want to be in a residential neighborhood.&lt;&#x2F;li&gt;
&lt;li&gt;You want to fulfill the American Dream™.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Now none of these &lt;em&gt;require&lt;&#x2F;em&gt; you to buy a house.
You could rent a house to get more space, invest in high yield assets to make passive income, etc. but a house tends to check &lt;strong&gt;all&lt;&#x2F;strong&gt; these boxes.&lt;&#x2F;p&gt;
&lt;p&gt;My fiance (now wife) and I we were living in a small apartment before buying a house.
This apartment was perfect pre-COVID.
It was a 10-20 minutes walking commute to work, centrally located, and big enough to sleep, cook meals, and rest while being young 20-somethings living our best lives.&lt;&#x2F;p&gt;
&lt;p&gt;When COVID hit we though we could muddle through in the apartment, but around the 2 month mark we thought:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hmm, this isn&#x27;t gonna be the &quot;Come on Morty.
Just two weeks, we&#x27;ll be in and out.
Just a little pandemic to spice things up.&quot; thing that we thought this would be...&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We looked for house rentals, but while there were hundreds of houses for sale there were almost no houses rentals available in the Portland area. I was always resistant to buying a house, but after realizing it was a reasonable financial decision we got started.&lt;&#x2F;p&gt;
&lt;p&gt;This is where our home buying journey begins.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;let-s-triage&quot;&gt;Let&#x27;s triage&lt;&#x2F;h2&gt;
&lt;p&gt;Before buying a house, or even visiting a house, you should go to sites like Zillow and Redfin to get a lay of the land.
They both have basically the same home listings, so choose whichever site has a better interface for you.
This goes without saying though; you found this obscure blog post so you&#x27;re probably deeply familiar with all the different home buying sites.
I promise this series will start saying less &quot;yeah duh&quot; stuff in the next section.&lt;&#x2F;p&gt;
&lt;p&gt;We knew roughly what neighborhoods we wanted to live in: East Portland with a bias toward the Tabor neighborhoods. This made it quick to narrow
our search and skip the existential question &quot;where in the world do I want to live?&quot; I&#x27;m sure some people confront.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;money-talk&quot;&gt;Money talk&lt;&#x2F;h2&gt;
&lt;p&gt;Once you have a feel for the housing market in your target locations, check in with your finances.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-big-wad-of-cash&quot;&gt;A big wad of cash&lt;&#x2F;h3&gt;
&lt;p&gt;Buying your soon-to-be house will require a down-payment.
This means you&#x27;ll need a very big pile of money &lt;em&gt;very soon&lt;&#x2F;em&gt;.
Figure out what your liquid assets (savings, non-retirement investment accounts, dubious favors you can call in) talley up to.
This is the max you could use for a down-payment.&lt;&#x2F;p&gt;
&lt;p&gt;Down payments tend to be 20% of the purchase price of the house, and houses are hundreds of thousands of dollars, so... yeah that&#x27;s a lot.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If you have 20k in usable assets, you can afford a down payment on a 100k house.&lt;&#x2F;li&gt;
&lt;li&gt;84k usable assets? 420k house.&lt;&#x2F;li&gt;
&lt;li&gt;13.8k usable assets? 69k house.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Nice.&lt;&#x2F;p&gt;
&lt;p&gt;This sets an upper-limit on which houses you can afford.
Hopefully this upper-limit lines up with median home prices in your target neighborhoods.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-smaller-monthly-wad-of-cash&quot;&gt;A smaller monthly wad of cash&lt;&#x2F;h3&gt;
&lt;p&gt;You also need to consider the monthly cost of your potential home.
Ideally you only spend up to 30% of your monthly income on living expenses.
This means your house (with utilities) costs no more than 30% of what you take home.
Some of you may be laughing at this because it is in fact an outdated metric that has not kept up with inflating home prices.
Don&#x27;t worry, we&#x27;ll cover how terrible home prices are in a later installment.&lt;&#x2F;p&gt;
&lt;p&gt;The 30% rule says:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If you take home 2k&#x2F;month (roughly a 30k&#x2F;year salary after taxes) your
housing should cost no more than 600&#x2F;month.&lt;&#x2F;li&gt;
&lt;li&gt;5833&#x2F;month (100k salary) take-home? 1750 housing expenses.&lt;&#x2F;li&gt;
&lt;li&gt;11452&#x2F;month (200k salary) take-home? 3435 housing expenses.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But what does that translate to for home prices?
You don&#x27;t pay for the whole house up front (the bank does that).
Instead you pay for it in monthly installments with interest -- which is hard for me to intuit.
Skipping some prelude:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If your house is 100k, you put up a 20k down payment, and you acquire a 30 year loan with 4% interest, your monthly payment will be ~587.&lt;&#x2F;li&gt;
&lt;li&gt;200k house, 40k down, 4% interest 30yr loan? ~1070.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;With these numbers, as the price of the house goes up the monthly payments go up sub-linearly.
This means so a 400k house is a little less than 2000&#x2F;month, ec.&lt;&#x2F;p&gt;
&lt;p&gt;I have no idea how to calculate these numbers by hand, I always use a calculator... &lt;a href=&quot;https:&#x2F;&#x2F;www.zillow.com&#x2F;mortgage-calculator&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.zillow.com&#x2F;mortgage-calculator&#x2F;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Once you have established you can afford both the down-payment and monthly payments now we can start shopping!&lt;&#x2F;p&gt;
&lt;p&gt;If prices in your target neighborhood are out of reach, explore other candidates; neighborhoods near your targets, or even the &#x27;burbs.
Also if you just like shopping for homes for the kick of it, because shopping is fun, power to you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;get-yourself-a-realtor&quot;&gt;Get yourself a realtor&lt;&#x2F;h2&gt;
&lt;p&gt;A realtor is like a lawyer.
You never &lt;em&gt;want&lt;&#x2F;em&gt; one, but they are incredible necessary for some of life&#x27;s biggest shit.&lt;&#x2F;p&gt;
&lt;p&gt;We were #blessed to have a family friend that was an active realtor; her name is Mary.&lt;&#x2F;p&gt;
&lt;p&gt;The relationship we had with our realtor was like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Every week around Tuesday we would send her a list of houses we wanted to see.
Between 5-10 houses every week.&lt;&#x2F;li&gt;
&lt;li&gt;Occasionally she would also find a house she thought we would be interested in.&lt;&#x2F;li&gt;
&lt;li&gt;The first week she picked about half the houses to get a feel for what we were interested in, and we brought some we found on our own.&lt;&#x2F;li&gt;
&lt;li&gt;She would drive us around to these houses, because we refuse to buy a car and she is &lt;em&gt;very&lt;&#x2F;em&gt; nice.&lt;&#x2F;li&gt;
&lt;li&gt;Mary would schedule a time for us to visit the house, around 30 minutes per house, during this time we were the only ones in the homes.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;As a card-carrying realtor Mary had special privileges not given to us normies, and information not found on public sites.
For example:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Mary had a list of things disclosed about the house like &quot;It&#x27;s very full of asbestos&quot; or &quot;It&#x27;s full of radon&quot; or &quot;The roof caved in last year, just fixed&quot;.
Info you would want to know before putting an offer on a house.&lt;&#x2F;li&gt;
&lt;li&gt;She also had access to some cloak-and-dagger shit that let her into all of the houses on the market.
Ever seen a lock-box on a for-sale house?
She could open that lock-box and get the key out with an app on her phone.&lt;&#x2F;li&gt;
&lt;li&gt;She also knew how to fill out the copious forms needed to put an offer on a house, but we&#x27;ll get to that in the next post.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;so-many-houses&quot;&gt;So. Many. Houses.&lt;&#x2F;h2&gt;
&lt;p&gt;In total we were house shopping for about 5 weeks.
We averaged visiting 10 houses per week, doing 1 to 2 trips per week and visiting 6 houses per trip.&lt;&#x2F;p&gt;
&lt;p&gt;We saw a lot of houses.
Some great houses in safe boring neighborhoods far from where we wanted to live.
Some terrible houses that people kept calling &quot;fixer-uppers&quot; like they were in the pocket of big shitty house.&lt;&#x2F;p&gt;
&lt;p&gt;A lot of houses that were great except for like... one really important thing.
Some houses had a great location but were too small.
Or the house was the perfect size but too far from our target location.
Or the price and size were good but the neighbors were burning a literal pile of trash and they were like... very good at it, implying this wasn&#x27;t a one-off thing.&lt;&#x2F;p&gt;
&lt;p&gt;My point is, there were a lot of houses.
A lot that were good, many more that were non-starters.&lt;&#x2F;p&gt;
&lt;p&gt;The first week or two was basically a mulligan.
So many houses are so bad you start to think &lt;em&gt;all&lt;&#x2F;em&gt; houses are bad and you trick yourself into settling.
DO NOT SETTLE.
This is a huge freaking purchase, grind it out and you will find a house you like.
It might be at the upper end of your budget, or it might be a &lt;em&gt;little bit of a fixer upper&lt;&#x2F;em&gt;, but you&#x27;ll know the perfect house when you find it.
And you will &lt;em&gt;definitely&lt;&#x2F;em&gt; know when it&#x27;s &lt;em&gt;not&lt;&#x2F;em&gt; the right house.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-on-your-knees-and-asking-the-bank-for-a-pre-approval&quot;&gt;Getting on your knees and asking the bank for a pre-approval&lt;&#x2F;h2&gt;
&lt;p&gt;At this point in the story we haven&#x27;t bought any houses yet, but before you are allowed to &lt;em&gt;think&lt;&#x2F;em&gt; about buying a house you need to get a bank to say &quot;Yeah they&#x27;re good for it&quot;.
This requires asking a bank pretty please, giving them like 3 years of financial, employment, and credit records.
If you&#x27;re buying this with a partner they need to do the same thing.&lt;&#x2F;p&gt;
&lt;p&gt;In our case we tried to get a super cheap loan but we were told our offer might get rejected if we didn&#x27;t have a &quot;local loan&quot; meaning a loan provided by a local Oregon company -- what year is it 1980?
In the end all of our loan options were super cheap, even the local ones, so we shrugged and told ourselves the cheapest loan probably had a bunch of closing fees that would basically cancel out the higher mortgage rate.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;em&gt;fun fact&lt;&#x2F;em&gt; about the loan process is that you get pre-approved for a loan up to some amount, which is used to put an offer on a house
Once the offer is accepted you get the &lt;em&gt;real&lt;&#x2F;em&gt; loan for whatever the final loan amount ends up being.
But we&#x27;re getting ahead of ourselves.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-offer-process&quot;&gt;The offer process&lt;&#x2F;h2&gt;
&lt;p&gt;At some point you&#x27;ll make an offer on a house.
This might &lt;em&gt;sound&lt;&#x2F;em&gt; like we&#x27;re buying a house, but trust me there are a lot more offers on houses than there are sales on houses.&lt;&#x2F;p&gt;
&lt;p&gt;When you put in an offer on a house you basically roll for initiative and if you get a Nat-20 it gets accepted.
You should still treat every offer as if it were to be accepted, because you can roll a Nat-20 on a persuasion check with a rat just as often as slaying a dragon.
Offers are accepted and rejected basically at random, but each one is important and should be treated as &quot;the one&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;When putting an offer on a house you fill out a bunch of complicated legal-ese forms with your realtor.
Taking your pre-approval you decide on an offer up to your pre-approval limit.
In Portland right now we need to offer &lt;em&gt;way more&lt;&#x2F;em&gt; than the asking price which is bullshit and I hate
it.&lt;&#x2F;p&gt;
&lt;p&gt;You also fill out a bunch of details like when you want the sale to be complete (30 days), weather you&#x27;re planning on doing inspections (yes), and how much money you can put up &lt;em&gt;before your down payment&lt;&#x2F;em&gt;.
That pre-down-payment is called Earnest Money and it&#x27;s often between 2k and 10k, it counts toward your down payment, and it can be refunded if the deal falls through.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;it-s-a-marathon-pace-yourself&quot;&gt;It&#x27;s a marathon, pace yourself&lt;&#x2F;h2&gt;
&lt;p&gt;Lucy went into this expecting that buying a house was like buying anything else.
You find what you like, offer a fair (or listed) price, and boom you get it.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately housing is not like buying a phone, or basically anything else most people spend money on.
In Portland at least supply does not match demand, so prices are not only higher than they ought to be, but the prices are also &lt;em&gt;full of lies&lt;&#x2F;em&gt;.
The asking price is often 10% below the final price -- if you&#x27;re lucky!
Plus your offer on a house may be rejected for mysterious reasons.
More than once we were asked to re-submit an offer and to give our &quot;highest and best&quot; offer whatever the fuck that means.&lt;&#x2F;p&gt;
&lt;p&gt;Be prepared to visit at &lt;strong&gt;dozens&lt;&#x2F;strong&gt; of houses.
Be prepared to make an offer on multiple houses.
You will have your heart broken when you find the perfect house, just to have it swiped out of your hands by a bank, somebody paying all in cash, somebody waiving inspections, or just some jerk that got an offer in half an hour before you did -- that bastard.&lt;&#x2F;p&gt;
&lt;p&gt;Take your time.
This is a big purchase.
It will pay off.
It will get better.
Your patience will be rewarded.&lt;&#x2F;p&gt;
&lt;p&gt;Good luck.
See you in the &lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;buying-a-house-02-show-me-the-money&#x2F;&quot;&gt;part 2&lt;&#x2F;a&gt; where we get to buy a freaking house!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Nuggit: Manually change your default branch name</title>
        <published>2021-07-07T00:00:00+00:00</published>
        <updated>2021-07-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/git-main-branch/"/>
        <id>https://elijah.run/blog/git-main-branch/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/git-main-branch/">&lt;p&gt;So I was on my laptop running an ancient release of Linux called Fedora 30 -- so old COVID wasn&#x27;t even a twinkle in a bat&#x27;s eye when it was released.&lt;&#x2F;p&gt;
&lt;p&gt;On this ancient OS I&#x27;m have &lt;code&gt;git 2.21.3&lt;&#x2F;code&gt; which is like 13 versions behind.
I ask yum -- err &lt;em&gt;dnf&lt;&#x2F;em&gt; -- if there is an upgrade and it&#x27;s like &quot;nope&quot;.
Nothing makes me feel older than software.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve gotten into the habit of naming my default branches &lt;code&gt;main&lt;&#x2F;code&gt; instead of &lt;code&gt;master&lt;&#x2F;code&gt; because every time I say &quot;master&quot; I need to take a shower.
I&#x27;m pretty sure the latest git names the default branch &lt;code&gt;main&lt;&#x2F;code&gt; out of the box, but git from April 2019 was not aware of problematic language choices.&lt;&#x2F;p&gt;
&lt;p&gt;So as one does I&#x27;m starting a new repo and I decide before updating &lt;code&gt;git&lt;&#x2F;code&gt;, which is gonna require like 3 Fedora upgrades, I&#x27;m just going to rename the branch.
I know I&#x27;ll get woke-git if I upgrade Fedora, but I want to write this post first so we&#x27;re gonna find a workaround.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;[branch:master]$ git branch -m main
&lt;&#x2F;span&gt;&lt;span&gt;error: refname refs&#x2F;heads&#x2F;master not found
&lt;&#x2F;span&gt;&lt;span&gt;fatal: Branch rename failed
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hmm.
So on a bare repo you can&#x27;t rename the starting branch because there&#x27;s no objects in the repo... or something like that &lt;em&gt;waves hands&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Umm... I guess we&#x27;ll go spelunking into the &lt;code&gt;.git&lt;&#x2F;code&gt; directory to see if we can manually force our &lt;code&gt;main&lt;&#x2F;code&gt; branch naming.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;[branch:master]$ cd .git
&lt;&#x2F;span&gt;&lt;span&gt;[.git]$ tree -F
&lt;&#x2F;span&gt;&lt;span&gt;.
&lt;&#x2F;span&gt;&lt;span&gt;├── branches&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;├── config
&lt;&#x2F;span&gt;&lt;span&gt;├── description
&lt;&#x2F;span&gt;&lt;span&gt;├── HEAD
&lt;&#x2F;span&gt;&lt;span&gt;├── hooks&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── A bunch of sample scripts
&lt;&#x2F;span&gt;&lt;span&gt;├── info&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;│   └── exclude
&lt;&#x2F;span&gt;&lt;span&gt;├── objects&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;│   ├── info&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;│   └── pack&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;└── refs&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    ├── heads&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    └── tags&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Well unsurprisingly we have a bunch of empty directories and some sample scripts.&lt;&#x2F;p&gt;
&lt;p&gt;The only files that &lt;em&gt;might&lt;&#x2F;em&gt; be worth looking at are &lt;code&gt;config&lt;&#x2F;code&gt;, &lt;code&gt;description&lt;&#x2F;code&gt;, and &lt;code&gt;HEAD&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;&#x2F;&#x2F; config
&lt;&#x2F;span&gt;&lt;span&gt;[core]
&lt;&#x2F;span&gt;&lt;span&gt;    repositoryformatversion = 0
&lt;&#x2F;span&gt;&lt;span&gt;    filemode = true
&lt;&#x2F;span&gt;&lt;span&gt;    bare = false
&lt;&#x2F;span&gt;&lt;span&gt;    logallrefupdates = true
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This seems to be config options for this repo, none of which mention branch naming so it&#x27;s a skip for me.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;&#x2F;&#x2F; description
&lt;&#x2F;span&gt;&lt;span&gt;Unnamed repository; edit this file &amp;#39;description&amp;#39; to name the repository.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I had no idea this feature existed.
I have never seen it be used -- but fun facts!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;&#x2F;&#x2F; HEAD
&lt;&#x2F;span&gt;&lt;span&gt;ref: refs&#x2F;heads&#x2F;master
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the money shot. Let&#x27;s change that bad boy to &lt;code&gt;refs&#x2F;heads&#x2F;main&lt;&#x2F;code&gt; and see if my magical git prompt picks it up:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;[.git]$ cd ..&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;[branch:main]$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Heyo!
There you have it. How to manually change the name of your main branch in a fresh git repo.&lt;&#x2F;p&gt;
&lt;p&gt;Sanity check, this won&#x27;t fuck up if we commit right?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ cargo init .
&lt;&#x2F;span&gt;&lt;span&gt;$ git add . &amp;amp;&amp;amp; git commit -m &amp;quot;initial commit&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;[main (root-commit) ebecbee] initial commit
&lt;&#x2F;span&gt;&lt;span&gt; 3 files changed, 12 insertions(+)
&lt;&#x2F;span&gt;&lt;span&gt; create mode 100644 .gitignore
&lt;&#x2F;span&gt;&lt;span&gt; create mode 100644 Cargo.toml
&lt;&#x2F;span&gt;&lt;span&gt; create mode 100644 src&#x2F;main.rs
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;note&quot;&gt;Note...&lt;&#x2F;h2&gt;
&lt;p&gt;After anxiously upgrading to Fedora 34 I confirmed that git fixed a lot of this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;[pop@lappy foo]$ git init
&lt;&#x2F;span&gt;&lt;span&gt;hint: Using &amp;#39;master&amp;#39; as the name for the initial branch. This default branch name
&lt;&#x2F;span&gt;&lt;span&gt;hint: is subject to change. To configure the initial branch name to use in all
&lt;&#x2F;span&gt;&lt;span&gt;hint: of your new repositories, which will suppress this warning, call:
&lt;&#x2F;span&gt;&lt;span&gt;hint:
&lt;&#x2F;span&gt;&lt;span&gt;hint:   git config --global init.defaultBranch &amp;lt;name&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;hint:
&lt;&#x2F;span&gt;&lt;span&gt;hint: Names commonly chosen instead of &amp;#39;master&amp;#39; are &amp;#39;main&amp;#39;, &amp;#39;trunk&amp;#39; and
&lt;&#x2F;span&gt;&lt;span&gt;hint: &amp;#39;development&amp;#39;. The just-created branch can be renamed via this command:
&lt;&#x2F;span&gt;&lt;span&gt;hint:
&lt;&#x2F;span&gt;&lt;span&gt;hint:   git branch -m &amp;lt;name&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And yes, &lt;code&gt;git branch -m &amp;lt;name&amp;gt;&lt;&#x2F;code&gt; does work on an empty repo.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Circular Imports</title>
        <published>2021-01-31T00:00:00+00:00</published>
        <updated>2021-01-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/circular-imports/"/>
        <id>https://elijah.run/blog/circular-imports/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/circular-imports/">&lt;p&gt;Don&#x27;t you hate when you&#x27;re writing a python program and you get hit with one of these?&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;Traceback (most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;a.py&amp;quot;, line 1, in &amp;lt;module&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    from b import g
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&#x2F;home&#x2F;pop&#x2F;Projects&#x2F;src&#x2F;localhost&#x2F;circular&#x2F;b.py&amp;quot;, line 1, in &amp;lt;module&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    from a import f
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&#x2F;home&#x2F;pop&#x2F;Projects&#x2F;src&#x2F;localhost&#x2F;circular&#x2F;a.py&amp;quot;, line 1, in &amp;lt;module&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    from b import g
&lt;&#x2F;span&gt;&lt;span&gt;ImportError: cannot import name &amp;#39;g&amp;#39; from partially initialized module &amp;#39;b&amp;#39; (most likely due to a circular import) (&#x2F;home&#x2F;pop&#x2F;Projects&#x2F;src&#x2F;localhost&#x2F;circular&#x2F;b.py)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What a drag.&lt;&#x2F;p&gt;
&lt;p&gt;Circular imports are of course the literal devel in programming, but in a Godel Escher Bach sort of way they are all around us.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;welcome-to-my-ted-talk&quot;&gt;welcome to my ted talk&lt;&#x2F;h2&gt;
&lt;p&gt;There are a lot of problems in the world that everybody agrees are problems&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but we can sometimes disagree about what the solution is.&lt;&#x2F;p&gt;
&lt;p&gt;Many of these problems stem can be thought of as emergent properties of other phenomena.&lt;&#x2F;p&gt;
&lt;p&gt;Take for example, plastic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fuck-plastic&quot;&gt;fuck plastic&lt;&#x2F;h2&gt;
&lt;p&gt;Remember the good old days in America when women tended to the house while PTSD ridden white men worked a 40 minute drive away and the ethnically, racially, sexually, abally discriminated minorities were repressed?&lt;&#x2F;p&gt;
&lt;p&gt;Well something that actually was pretty sweet was milk delivery.&lt;&#x2F;p&gt;
&lt;p&gt;Milk, delivered regularly in reusable glass bottles had incredibly ecological benefits compared with how we get milk&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; today.&lt;&#x2F;p&gt;
&lt;p&gt;Deliveries are an incredibly efficient means of distriuting goods&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and re-using glass bottles requires far less energy than say, melting a bottle down or worse creating a plastic single-use bottle.&lt;&#x2F;p&gt;
&lt;p&gt;I really want to focus on the glass bottles because they are &lt;em&gt;so&lt;&#x2F;em&gt; efficient, why did we ever stop?&lt;&#x2F;p&gt;
&lt;p&gt;Lobbying.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-plastics-import-lobbying&quot;&gt;from plastics import lobbying&lt;&#x2F;h2&gt;
&lt;p&gt;That&#x27;s right: lobbying, not the free market, gave us the fucking horrific amount of single-use plastic we have today.&lt;&#x2F;p&gt;
&lt;p&gt;For sure there are a million things we need to cut the fuck out if we want this planet to be anything close to what we were born into in 100 years, but plastics are worth spending a few hundred words.&lt;&#x2F;p&gt;
&lt;p&gt;The plastics industry spent millions&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; lobbying to allow the use of single use plastics instead of reusable containers.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of identifying the inevitable crisis of too much fucking plastic and shutting that shit down, governments across the world wer just like &quot;yeah this is cool, pour up my dude&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Congress, given no external input, very well could have legislated against the use of single-use plastics, but because they were convinced... with money... otherwise here we are in a world full of single use plastics, and just like a virus it&#x27;s spread so far that it feels impossible to slow it&#x27;s spread.&lt;&#x2F;p&gt;
&lt;p&gt;So clearly we need to stop lobbying.
We need to think of some clever way to prevent corruptable government officials from being bought off to vote against the interests of their constituents, their country, and future generations...&lt;&#x2F;p&gt;
&lt;p&gt;Well that&#x27;s clearly impossible.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s dig deeper.
What causes lobbying?&lt;&#x2F;p&gt;
&lt;p&gt;Profit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-lobbying-import-profit&quot;&gt;from lobbying import profit&lt;&#x2F;h2&gt;
&lt;p&gt;It is clear that profit is the reason lobbying exists.&lt;&#x2F;p&gt;
&lt;p&gt;Some lobbying is good. If you own a farm and you hear about legislation that will like... just straight up dump a bunch of nuclear waste on your property, you&#x27;re probably going to knock on some doors and grease some palms to prevent that from happening.&lt;&#x2F;p&gt;
&lt;p&gt;Arithmetically it makes sense that lobbying is tied to profit.
If a piece of legislation is projected to decrease profits by 30 million USD, you&#x27;re probably willing to spend 2 million USD to prevent it from going through.&lt;&#x2F;p&gt;
&lt;p&gt;Lobbying, like swordfishing&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, is a targeted, and therefore monetarily effective, way to influence change.&lt;&#x2F;p&gt;
&lt;p&gt;Maximizing profit has a lot of other problems&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; like supressing wages despite productivity going up, and cock-blocking public alternatives to private services like healthcare... Where was I?&lt;&#x2F;p&gt;
&lt;p&gt;Oh right, so this begs the question, where does profit come from?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-profit-import&quot;&gt;from profit import ???&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;soapbox-intensifies&quot;&gt;soapbox intensifies&lt;&#x2F;h2&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;All &lt;em&gt;good faith actors&lt;&#x2F;em&gt; actors agree are a problem.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Yes, also mylks.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Citation needed?&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;... &lt;em&gt;sigh&lt;&#x2F;em&gt; citation needed.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;The internet phishing scam not the oceanic activity.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;... citation... needed...?&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Let&#x27;s Build a Game with Rust</title>
        <published>2020-11-13T00:00:00+00:00</published>
        <updated>2020-11-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/seagl-2020-lets-build-a-game-with-rust/"/>
        <id>https://elijah.run/blog/seagl-2020-lets-build-a-game-with-rust/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/seagl-2020-lets-build-a-game-with-rust/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This is the outline for a talk I gave at the Seattle GNU Linux
conference (SeaGL) 2020. Once the video is posted I will link it here.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;The code for this post can be found at https:&#x2F;&#x2F;github.com&#x2F;pop&#x2F;lets-make-games-with-rust.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Like many of you, I really like games.
I enjoy playing games, talking about games, and a few times I&#x27;ve even tried making games.
I enjoy making games for a few reasons:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Games are an interesting technical challenge.&lt;&#x2F;li&gt;
&lt;li&gt;They are a flexible artistic outlet.&lt;&#x2F;li&gt;
&lt;li&gt;I don&#x27;t make games in my day-job (yay hobbies).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I&#x27;m also interested in this programming language called Rust!
You might have heard of it.
Rust is a maturing systems programming language which aims to be performant, reliable, and productive.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Performant in that it often goes head to head with C and C++ in benchmarks.&lt;&#x2F;li&gt;
&lt;li&gt;Reliable in that it refuses to compile memory unsafe code.&lt;&#x2F;li&gt;
&lt;li&gt;Productive because it includes &quot;zero cost abstractions&quot; (link &lt;code&gt;filter&lt;&#x2F;code&gt; and &lt;code&gt;map&lt;&#x2F;code&gt;) and awesome tooling.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The community is pretty good too!&lt;&#x2F;p&gt;
&lt;p&gt;This post is about bringing those two interests together.
Let&#x27;s learn how to build a videogame with the Rust programming language.&lt;&#x2F;p&gt;
&lt;div class=&quot;warning&quot;&gt;
    &lt;span class=&quot;warning-title&quot;&gt;
        Warning
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;warning-body&quot;&gt;
        &lt;p&gt;This post is for folks who have a passing familiarity with Rust.
If Rust is new to you, you get a little confused.&lt;&#x2F;p&gt;
&lt;p&gt;You&#x27;re a smart cookie though, I&#x27;m sure you&#x27;ll keep up.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;making-games-entities-components-systems-gear&quot;&gt;Making Games: Entities, Components, Systems ⚙️&lt;&#x2F;h2&gt;
&lt;p&gt;Games are an incredibly fun and flexible type of project to work on.&lt;&#x2F;p&gt;
&lt;p&gt;At it&#x27;s core, all games need a &quot;game loop&quot;:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Process input&lt;&#x2F;li&gt;
&lt;li&gt;Transforms state&lt;&#x2F;li&gt;
&lt;li&gt;Display new state&lt;&#x2F;li&gt;
&lt;li&gt;Repeat&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Outside of that, the possibilities are endless.
But while the &lt;em&gt;possibilities&lt;&#x2F;em&gt; are endless, there are a few &lt;em&gt;patterns&lt;&#x2F;em&gt; that lots of folks seem to gravitate toward.&lt;&#x2F;p&gt;
&lt;p&gt;You could write a whole book on game programming patterns (and somebody has, links at the bottom).
Today we&#x27;re going to talk about one popular pattern: &lt;strong&gt;ECS: Entity Component System&lt;&#x2F;strong&gt;.
Here&#x27;s what that looks like:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;components&quot;&gt;Components&lt;&#x2F;h3&gt;
&lt;p&gt;Pieces of data mixed, matched, and queried on.&lt;&#x2F;p&gt;
&lt;p&gt;Example: Some components needed to simulate physics might be &quot;Mass&quot;, &quot;Movable&quot;, and &quot;Friction&quot;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;entities&quot;&gt;Entities&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A Unique ID associated with a collection of Components.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Example: Potted plant you can break have the following components:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Sprite(&quot;&#x2F;path&#x2F;to&#x2F;plant.png&quot;)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Mass(6.8)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Movable(True)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Location((2, 5, 2))&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Each of these components are reusable. Instead of creating a &quot;PottedPlant&quot; class in code, we can define each entity in a config file like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;potted-plant.txt:
&lt;&#x2F;span&gt;&lt;span&gt;Sprite &#x2F;path&#x2F;to&#x2F;plant.png
&lt;&#x2F;span&gt;&lt;span&gt;Mass 6.8
&lt;&#x2F;span&gt;&lt;span&gt;Movable True
&lt;&#x2F;span&gt;&lt;span&gt;Location 2 5 2
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This makes our engine much more reusable and separates our content from our logic.&lt;&#x2F;p&gt;
&lt;p&gt;But how do we use these components?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;systems&quot;&gt;Systems&lt;&#x2F;h3&gt;
&lt;p&gt;Functions that operate on entities with specific components.&lt;&#x2F;p&gt;
&lt;p&gt;A System queries for all entities with a specific subset of components and does some transformation on it.&lt;&#x2F;p&gt;
&lt;p&gt;Example: a system that applies fire damage to an entity might look like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;entities_on_fire = entities.query(on_fire=True, health &amp;gt; 0)
&lt;&#x2F;span&gt;&lt;span&gt;for entity in entities_on_fire:
&lt;&#x2F;span&gt;&lt;span&gt;    entity.health -= 5
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is nice compared with a classes-based approach where we would need to manage inheritance to manually make sure everything interacted
correctly.
Here we define systems based on what features an entity has.
The resulting systems and components interact with eachother in interesting and potentially unexpected ways.&lt;&#x2F;p&gt;
&lt;p&gt;ECS is a popular pattern for creating interactive games and simulations.
Engines like Unity have some ECS patterns built in, and almost every big game engine uses ECS in some way.&lt;&#x2F;p&gt;
&lt;p&gt;Of course ECS isn&#x27;t a silver bullet, but for this blog post it&#x27;s good enough.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tools-of-the-trade-c-and-c-hammer-pick&quot;&gt;Tools of the Trade: C and C++ ⚒️&lt;&#x2F;h2&gt;
&lt;p&gt;C and C++ are very popular languages in games programming.
They are defacto in the industry and many large engines, both internal and licensed engines, are written in C++.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not here to bash on C and C++, but it can be useful to point out why you would bother using Rust if the norm is C++.&lt;&#x2F;p&gt;
&lt;p&gt;The usual arguments in favor of Rust go a little something like this:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Rust is memory safe; in Rust it is very difficult to reference freed memory, mutate memory in two threads, and dereference a null pointer.&lt;&#x2F;li&gt;
&lt;li&gt;Rust is expressive; a lot of functional-programming language features exist in Rust without the usual run-time cost of those languages.&lt;&#x2F;li&gt;
&lt;li&gt;Rust doesn&#x27;t have any of the C&#x2F;C++ legacy baggage but &lt;em&gt;can&lt;&#x2F;em&gt; inter-operate with C&#x2F;C++ codebases.&lt;&#x2F;li&gt;
&lt;li&gt;Rust has a kick-ass community and an ecosystem of battle-tested and safe code.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So why does this all matter for games? I think of it it like this: Any project when it gets sufficiently complex benefits from Rust.
Rust, by preventing a whole class of memory bugs, makes it easier to maintain a complex codebase over time.
It might not be life or death, or as mission critical as security software, but completely avoiding null-pointer bugs, at essentially no performance cost, sounds like a huge weight off my shoulders.&lt;&#x2F;p&gt;
&lt;p&gt;Games are by their nature huge and sprawling codebases.
Many bugs in games are caught by a compiler, but even more errors would be caught by the Rust borrow-checker.
And being able to use some of the nice functional-programming features would be nice too.&lt;&#x2F;p&gt;
&lt;p&gt;Of course Rust is a relatively new language so your mileage may vary.
If I ran a big game studio I don&#x27;t think I would throw out my C++ code and start fresh with Rust, but I would definitely put some research and development into it for new projects (said the Rust fanboy).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rusty-games-hello-amethyst-gem&quot;&gt;Rusty Games: Hello Amethyst 💎&lt;&#x2F;h2&gt;
&lt;p&gt;Writing games in a safe, expressive, not C&#x2F;C++ language sounds great; where do I start?&lt;&#x2F;p&gt;
&lt;p&gt;You could write a game from scratch, but there are engines written in Rust you can use today!
Some of these focus on ease of use, some are for 2D games, some focus on compiling for the web.
Most of these engines require you to write Rust, as opposed to using a GUI, but even that is changing.&lt;&#x2F;p&gt;
&lt;p&gt;For a comprehensive list check out &lt;a href=&quot;https:&#x2F;&#x2F;www.arewegameyet.rs&quot;&gt;https:&#x2F;&#x2F;www.arewegameyet.rs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You could write this talk for almost any Rust Game Engine, but my personal favorite is Amethyst, so we&#x27;ll use that.
Amethyst has a solid API, very active community, and is a good mix of flexible, convenient, and powerful.&lt;&#x2F;p&gt;
&lt;p&gt;Amethyst checks off a few other boxes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Implements an ECS runtime. Register Components, create Entities, and run Systems in Amethyst.&lt;&#x2F;li&gt;
&lt;li&gt;Data driven design. Almost all data in Amethyst can be read in from a Config file.&lt;&#x2F;li&gt;
&lt;li&gt;Apache + MIT licensed. Free as in speech is always nice.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;step-0-join-the-cargo-cult&quot;&gt;Step 0: Join the Cargo Cult&lt;&#x2F;h3&gt;
&lt;p&gt;In this step we&#x27;re going to get Rust setup and create a &quot;hello world&quot; Rust project.&lt;&#x2F;p&gt;
&lt;p&gt;If you haven&#x27;t already, setup your Rust toolchain and start a Rust project.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;rustup&lt;&#x2F;code&gt;, the Rust toolchain manager.&lt;&#x2F;li&gt;
&lt;li&gt;Run &lt;code&gt;rustup toolchain install stable&lt;&#x2F;code&gt; to install the latest stable Rust.&lt;&#x2F;li&gt;
&lt;li&gt;Run &lt;code&gt;cargo new seagl-game&lt;&#x2F;code&gt; to create a &quot;hello world&quot; Rust application.&lt;&#x2F;li&gt;
&lt;li&gt;Navigate to the new &lt;code&gt;seagl-game&lt;&#x2F;code&gt; folder.
Add this to the end of our project&#x27;s metadata file, &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;# Cargo.toml
&lt;&#x2F;span&gt;&lt;span&gt;[dependencies.amethyst]
&lt;&#x2F;span&gt;&lt;span&gt;version = &amp;quot;0.15.1&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;features = [&amp;quot;vulkan&amp;quot;]  # &amp;quot;metal&amp;quot; on MacOS
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Run &lt;code&gt;cargo build&lt;&#x2F;code&gt; to build and cache our dependencies.
You should see a &lt;strong&gt;bunch&lt;&#x2F;strong&gt; of output like this:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ cargo build
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;Compiling either v1.6.1
&lt;&#x2F;span&gt;&lt;span&gt;Compiling gimli v0.23.0
&lt;&#x2F;span&gt;&lt;span&gt;Compiling adler v0.2.3
&lt;&#x2F;span&gt;&lt;span&gt;Compiling object v0.22.0
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we have a &quot;hello world&quot; Rust project we can start building on.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;step-1-draw-a-window-triangular-ruler&quot;&gt;Step 1: Draw a Window 📐&lt;&#x2F;h3&gt;
&lt;p&gt;Before we run, we need to walk.
And before we walk we crawl.
And before we crawl we draw a window.
This is, of course, a little harder than just asking your computer &quot;Please draw me a window&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;First we need to add a bunch of imports to our project:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;amethyst::{
&lt;&#x2F;span&gt;&lt;span&gt;    assets::{AssetStorage, Loader},
&lt;&#x2F;span&gt;&lt;span&gt;    core::{
&lt;&#x2F;span&gt;&lt;span&gt;        timing::Time,
&lt;&#x2F;span&gt;&lt;span&gt;        transform::{Transform, TransformBundle},
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    derive::SystemDesc,
&lt;&#x2F;span&gt;&lt;span&gt;    ecs::{
&lt;&#x2F;span&gt;&lt;span&gt;        Component, DenseVecStorage, Entities, Join, Read, ReadStorage, System, SystemData,
&lt;&#x2F;span&gt;&lt;span&gt;        WriteStorage,
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    input::{InputBundle, InputHandler, StringBindings},
&lt;&#x2F;span&gt;&lt;span&gt;    prelude::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    renderer::{
&lt;&#x2F;span&gt;&lt;span&gt;        plugins::{RenderFlat2D, RenderToWindow},
&lt;&#x2F;span&gt;&lt;span&gt;        types::DefaultBackend,
&lt;&#x2F;span&gt;&lt;span&gt;        Camera, ImageFormat, RenderingBundle, SpriteRender, SpriteSheet, SpriteSheetFormat,
&lt;&#x2F;span&gt;&lt;span&gt;        Texture,
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    utils::application_root_dir,
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is every dependency we will need for the entire project, so if &lt;code&gt;cargo build|run&lt;&#x2F;code&gt; complains about unused dependencies, don&#x27;t worry... we&#x27;ll get there.&lt;&#x2F;p&gt;
&lt;p&gt;Here we are including a few useful&lt;&#x2F;p&gt;
&lt;p&gt;Then we need to add some boiler-plate to our &lt;code&gt;main&lt;&#x2F;code&gt; function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; This is necessary to make Rust&amp;#39;s type-checker happy
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Our main function technically returns an Amethyst Result
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; It can either return an Amethyst error or a unit value
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; amethyst::&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;()&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Not required, but a logger very useful
&lt;&#x2F;span&gt;&lt;span&gt;    amethyst::start_logger(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Default&lt;&#x2F;span&gt;&lt;span&gt;::default());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Declare some useful variables used to tell Amethyst where our asset files and config files live
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; app_root &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;application_root_dir&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; assets_dir &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; app_root.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;assets&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; display_config_path &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; app_root.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;display.ron&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Declare a renderer bundle
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Amethyst adds this collection of 2D Render systems to our game&amp;#39;s runtime
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; renderer &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;RenderingBundle::&amp;lt;DefaultBackend&amp;gt;::new()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with_plugin&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;            RenderToWindow::from_config_path(display_config_path)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;?
&lt;&#x2F;span&gt;&lt;span&gt;                .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with_clear&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1.00&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.33&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.00&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;]),
&lt;&#x2F;span&gt;&lt;span&gt;        ).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with_plugin&lt;&#x2F;span&gt;&lt;span&gt;(RenderFlat2D::default());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Build the game&amp;#39;s systems
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; game_data &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;GameDataBuilder::default()
&lt;&#x2F;span&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with_bundle&lt;&#x2F;span&gt;&lt;span&gt;(renderer)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Build our application, which includes our game data, where our assets live, and our starting state
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; game &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Application::new(assets_dir, SeaglState, game_data)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Run the game!
&lt;&#x2F;span&gt;&lt;span&gt;    game.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Nothing bad happened, so return `()`
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Ok&lt;&#x2F;span&gt;&lt;span&gt;(())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That won&#x27;t compile because we haven&#x27;t defined our &lt;code&gt;SeaglState&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ cargo run
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;error[E0425]: cannot find value `SeaglState` in this scope
&lt;&#x2F;span&gt;&lt;span&gt;  --&amp;gt; src&#x2F;main.rs:17:49
&lt;&#x2F;span&gt;&lt;span&gt;   |
&lt;&#x2F;span&gt;&lt;span&gt;30 |     let mut game = Application::new(assets_dir, SeaglState, game_data)?;
&lt;&#x2F;span&gt;&lt;span&gt;   |                                                 ^^^^^^^^^^ not found in this scope
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s add &lt;code&gt;SeaglState&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; States can store values, but for now we can use a unit-struct
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;SeaglState;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; We get a working state for free by rubber-stamping the &amp;quot;SimpleState&amp;quot; struct onto our SeaglState
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; We will implement our own logic for handling state start-up in the next step
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;SimpleState &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;SeaglState { }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We will add some methods to &lt;code&gt;SeaglState&lt;&#x2F;code&gt; later, but for now this makes Rust and Amethyst happy enough to compile.&lt;&#x2F;p&gt;
&lt;p&gt;But if we run our code we get a wonderfully cryptic error message:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Compiling seagl-talk v0.1.0 (&#x2F;home&#x2F;pop&#x2F;seagl-talk)
&lt;&#x2F;span&gt;&lt;span&gt; Finished dev [unoptimized + debuginfo] target(s) in 24.81s
&lt;&#x2F;span&gt;&lt;span&gt;  Running `target&#x2F;debug&#x2F;seagl-talk`
&lt;&#x2F;span&gt;&lt;span&gt;Error: Error { inner: Inner { source: None, backtrace: None, error: File(Os { code: 2, kind: NotFound, message: &amp;quot;No such file or directory&amp;quot; }) } }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We get errors like this when we have an unhandled exception in our code.
In our &lt;code&gt;main&lt;&#x2F;code&gt; function, that is any place where we call a function with a &lt;code&gt;?&lt;&#x2F;code&gt;, e.g., &lt;code&gt;foo(...)?;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;TLDT (Too Long Didn&#x27;t Troubleshoot) this is because we haven&#x27;t created our display config file!&lt;&#x2F;p&gt;
&lt;p&gt;Add a new file &lt;code&gt;display.ron&lt;&#x2F;code&gt; in a new folder called &lt;code&gt;config&#x2F;&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; config&#x2F;display.ron
&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    title: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;SeaGL!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    dimensions: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;500&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;500&lt;&#x2F;span&gt;&lt;span&gt;)),
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now when we &lt;code&gt;cargo run&lt;&#x2F;code&gt; we should get a wonderful orange window:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;seagl-2020&#x2F;blank-window.png&quot; alt=&quot;It worked! We drew a window.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;step-2-draw-a-seagl-dove&quot;&gt;Step 2: Draw a SeaGL 🕊️&lt;&#x2F;h3&gt;
&lt;p&gt;Alas, we have a window but no game! Let&#x27;s draw our first character to the screen.&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;Did you know that SeaGL&#x27;s mascot is named Patch?
https:&#x2F;&#x2F;seagl.org&#x2F;news&#x2F;2020&#x2F;09&#x2F;10&#x2F;naming-contest.html&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;First we&#x27;ll create a Component for our Seagl.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Default)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Seagl;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;Component &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;Seagl {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;Storage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;DenseVecStorage&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we&#x27;ll create a Seagl entity.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;SimpleState &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;SeaglState {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;on_start&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;mut &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;: StateData&amp;lt;GameData&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; transform &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Transform::default();
&lt;&#x2F;span&gt;&lt;span&gt;        transform.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;set_translation_xyz&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;50.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;50.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; seagl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Seagl::default();
&lt;&#x2F;span&gt;&lt;span&gt;        data.world
&lt;&#x2F;span&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;create_entity&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;(seagl)
&lt;&#x2F;span&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;(transform)
&lt;&#x2F;span&gt;&lt;span&gt;            .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a good start, but our Seagl is a spriteless ghost!&lt;&#x2F;p&gt;
&lt;div class=&quot;warning&quot;&gt;
    &lt;span class=&quot;warning-title&quot;&gt;
        Warning
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;warning-body&quot;&gt;
        &lt;p&gt;Seagull ghosts are terrifying.
Add a sprite!&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;First we need to load the spritesheet into memory.
Add this in our &lt;em&gt;on_start&lt;&#x2F;em&gt; function above where we added the seagl:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; sprite_sheet_handle &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; loader &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; data.world.read_resource::&amp;lt;Loader&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; texture_storage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; data.world.read_resource::&amp;lt;AssetStorage&amp;lt;Texture&amp;gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; texture_handle &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; loader.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;texture&#x2F;spritesheet.png&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ImageFormat::default(),
&lt;&#x2F;span&gt;&lt;span&gt;        (),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;texture_storage,
&lt;&#x2F;span&gt;&lt;span&gt;    );
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; sprite_sheet_store &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; data.world.read_resource::&amp;lt;AssetStorage&amp;lt;SpriteSheet&amp;gt;&amp;gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    loader.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;load&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;texture&#x2F;spritesheet.ron&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        SpriteSheetFormat(texture_handle),
&lt;&#x2F;span&gt;&lt;span&gt;        (),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;sprite_sheet_store,
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;span&gt;};
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then modify our Seagl entity like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;++ main.rs
&lt;&#x2F;span&gt;&lt;span&gt;@@ impl SimpleState for SeaglState
&lt;&#x2F;span&gt;&lt;span&gt;@@ fn on_start(...)
&lt;&#x2F;span&gt;&lt;span&gt;  let mut transform = Transform::default();
&lt;&#x2F;span&gt;&lt;span&gt;  transform.set_translation_xyz(50.0, 50.0, 0.0);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+ let sprite = SpriteRender::new(sprite_sheet_handle.clone(), 0);
&lt;&#x2F;span&gt;&lt;span&gt;  let seagl = Seagl::default();
&lt;&#x2F;span&gt;&lt;span&gt;  data.world
&lt;&#x2F;span&gt;&lt;span&gt;      .create_entity()
&lt;&#x2F;span&gt;&lt;span&gt;      .with(seagl)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+     .with(sprite)
&lt;&#x2F;span&gt;&lt;span&gt;      .with(transform)
&lt;&#x2F;span&gt;&lt;span&gt;      .build();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s see.
We created a Seagl entity. Let&#x27;s try running this thing:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ cargo run
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;thread &amp;#39;main&amp;#39; panicked at &amp;#39;Tried to fetch resource of type `MaskedStorage&amp;lt;Seagl&amp;gt;`[^1] from the `World`, but the resource does not exist.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;You may ensure the resource exists through one of the following methods:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;* Inserting it when the world is created: `world.insert(..)`.
&lt;&#x2F;span&gt;&lt;span&gt;* If the resource implements `Default`, include it in a system&amp;#39;s `SystemData`, and ensure the system is registered in the dispatcher.
&lt;&#x2F;span&gt;&lt;span&gt;* If the resource does not implement `Default`, insert it in the world during `System::setup`.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hmm.
It seems like our &lt;code&gt;Seagl&lt;&#x2F;code&gt; Component isn&#x27;t registered with Amethyst.
This happens implicitly when we add a system that uses our component, but until we write a System, we&#x27;ll have to explicitly register our Component with Amethyst.&lt;&#x2F;p&gt;
&lt;p&gt;Add this toward the top of our &lt;code&gt;on_start&lt;&#x2F;code&gt; method:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;data.world.register::&amp;lt;Seagl&amp;gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s try running again:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ cargo run
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;Error { inner: Inner { source: Some(Error { inner: Inner { source: None, backtrace: None,
&lt;&#x2F;span&gt;&lt;span&gt;error: Os { code: 2, kind: NotFound, message: &amp;quot;No such file or directory&amp;quot; } } }), backtrace: None,
&lt;&#x2F;span&gt;&lt;span&gt;error: StringError(&amp;quot;Failed to fetch metadata for \&amp;quot;&#x2F;home&#x2F;pop&#x2F;seagl-talk&#x2F;assets&#x2F;texture&#x2F;spritesheet.ron\&amp;quot;&amp;quot;) } }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ah, a different runtime error.
This time we forgot to add our spritesheet image and spritesheet config file.
Lets add those.&lt;&#x2F;p&gt;
&lt;p&gt;Add this code to a file in &lt;code&gt;assets&#x2F;texture&#x2F;spritesheet.ron&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; assets&#x2F;texture&#x2F;spritesheet.ron
&lt;&#x2F;span&gt;&lt;span&gt;List((
&lt;&#x2F;span&gt;&lt;span&gt;    texture_width: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;32&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    texture_height: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    sprites: [
&lt;&#x2F;span&gt;&lt;span&gt;        ( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Seagl
&lt;&#x2F;span&gt;&lt;span&gt;            x: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            y: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            width: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            height: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ),
&lt;&#x2F;span&gt;&lt;span&gt;        ( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; Burger
&lt;&#x2F;span&gt;&lt;span&gt;            x: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            y: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            width: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            height: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ),
&lt;&#x2F;span&gt;&lt;span&gt;    ],
&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And save this image to &lt;code&gt;assets&#x2F;texture&#x2F;spritesheet.png&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;seagl-2020&#x2F;spritesheet.png&quot; alt=&quot;Seagl and Burger. 32x16. Pixel on LCD.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now if we run &lt;code&gt;cargo run&lt;&#x2F;code&gt; we get the same blank orange window.
This happened because we forgot to add a Camera to the scene!&lt;&#x2F;p&gt;
&lt;p&gt;Add this to the end of our &lt;code&gt;on_start&lt;&#x2F;code&gt; function:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; transform &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Transform::default();
&lt;&#x2F;span&gt;&lt;span&gt;transform.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;set_translation_xyz&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;50.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;50.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;data.world
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;create_entity&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;(Camera::standard_2d(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;100.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;100.0&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;(transform)
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;seagl-2020&#x2F;window-with-seagl.png&quot; alt=&quot;That&amp;#39;s a nice looking Seagl there...&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;It&#x27;s so beautifull...&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;h3 id=&quot;step-3-move-around-horse-racing&quot;&gt;Step 3: Move Around 🏇&lt;&#x2F;h3&gt;
&lt;p&gt;Thinking back to our ECS discussion, we have two of the three ingredients: an Entity, some Components, but no Systems!&lt;&#x2F;p&gt;
&lt;p&gt;First, we need to create a System struct and implement &lt;code&gt;System&lt;&#x2F;code&gt; on it.&lt;&#x2F;p&gt;
&lt;p&gt;Our System&#x27;s run function looks like this in psuedocode:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;for every seagl that can move:
&lt;&#x2F;span&gt;&lt;span&gt;    If the user input was to move horizontal:
&lt;&#x2F;span&gt;&lt;span&gt;        Move the seagl horizontally
&lt;&#x2F;span&gt;&lt;span&gt;    If the user input was to move vertical:
&lt;&#x2F;span&gt;&lt;span&gt;        Move the seagl vertically
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This doesn&#x27;t look &lt;em&gt;exactly&lt;&#x2F;em&gt; the same in Rust, but it&#x27;s pretty close.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(SystemDesc)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;MoveSystem;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; System&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;MoveSystem {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;SystemData &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        WriteStorage&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;, Transform&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ReadStorage&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;, Seagl&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        Read&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;, Time&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        Read&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;, InputHandler&amp;lt;StringBindings&amp;gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    );
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;mut &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;mut transforms&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;seagls&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;time&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;): &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;Self::&lt;&#x2F;span&gt;&lt;span&gt;SystemData) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; speed: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;f32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;50.0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(_seagl, transform) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;seagls, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;mut&lt;&#x2F;span&gt;&lt;span&gt; transforms).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(horizontal) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; input.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;axis_value&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;horizontal&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;                transform.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;prepend_translation_x&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;                    horizontal &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; time.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;delta_seconds&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; speed  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;f32
&lt;&#x2F;span&gt;&lt;span&gt;                );
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            };
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(vertical) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; input.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;axis_value&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;vertical&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;                transform.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;prepend_translation_y&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;                    vertical &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; time.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;delta_seconds&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; speed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;f32
&lt;&#x2F;span&gt;&lt;span&gt;                );
&lt;&#x2F;span&gt;&lt;span&gt;            };
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We declare a &lt;code&gt;SystemData&lt;&#x2F;code&gt; type which is a tuple of components.
The &lt;code&gt;Transform&lt;&#x2F;code&gt; component will be modified, so we require it as &lt;code&gt;mut&lt;&#x2F;code&gt;, but everything else is &lt;code&gt;Read&lt;&#x2F;code&gt; for stuff that Amethyst provides and &lt;code&gt;ReadStorage&lt;&#x2F;code&gt; for things we created.&lt;&#x2F;p&gt;
&lt;p&gt;We loop over every entity with the &lt;code&gt;Seagl&lt;&#x2F;code&gt; and &lt;code&gt;Transform&lt;&#x2F;code&gt; components, then we match against any user input:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If we had &quot;vertical&quot; input, move the entity on the x axis.&lt;&#x2F;li&gt;
&lt;li&gt;If we had &quot;horizontal&quot; input, move the entity on the y axis.&lt;&#x2F;li&gt;
&lt;li&gt;We don&#x27;t need to explicitly say &quot;move left&quot;&#x2F;&quot;move right&quot; because the horizontal&#x2F;vertical inputs can be positive or negative.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Next we need to register this system with out game.
Because we are using Inputs we also need to register the inputs bundle with the game.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ main.rs
&lt;&#x2F;span&gt;&lt;span&gt;@@ fn main() -&amp;gt; amethyst::Result&amp;lt;()&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;     )
&lt;&#x2F;span&gt;&lt;span&gt;     .with_plugin(RenderFlat2D::default());
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    let bindings_path = app_root.join(&amp;quot;config&amp;quot;).join(&amp;quot;bindings.ron&amp;quot;);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    let inputs = InputBundle::&amp;lt;StringBindings&amp;gt;::new().with_bindings_from_file(bindings_path)?;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span&gt;     let game_data = GameDataBuilder::default()
&lt;&#x2F;span&gt;&lt;span&gt;         .with_bundle(transform)?
&lt;&#x2F;span&gt;&lt;span&gt;         .with_bundle(renderer)?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        .with_bundle(inputs)?
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        .with(MoveSystem, &amp;quot;move_system&amp;quot;, &amp;amp;[&amp;quot;input_system&amp;quot;]);
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;     let mut game = Application::new(assets_dir, SeaglState, game_data)?;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We have a dependency on the &lt;code&gt;input_system&lt;&#x2F;code&gt;, so Amethyst will ensure that system runs before &lt;code&gt;move_system&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Next we need to create a config file for our movement bindings.
Instead of hard-coding &quot;Up arrow means move up, down arrow means down&quot; we put that in config files:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; config&#x2F;bindings.ron
&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    axes: {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;horizontal&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: Emulated(pos: Key(Right), neg: Key(Left)),
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;vertical&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: Emulated(pos: Key(Up), neg: Key(Down)),
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    actions: {},
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;![It moves!](&#x2F;images&#x2F;seagl-2020&#x2F;SeaGL-move.gif&quot; class=&quot;align-center)&lt;&#x2F;p&gt;
&lt;p&gt;This is a good start, but you&#x27;ll notice the Seagl doesn&#x27;t turn left and right, this &lt;em&gt;totally&lt;&#x2F;em&gt; breaks my suspension of disbelief so we&#x27;re gonna need to fix that in our &lt;code&gt;run&lt;&#x2F;code&gt; method:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;diff --git a&#x2F;src&#x2F;main.rs b&#x2F;src&#x2F;main.rs
&lt;&#x2F;span&gt;&lt;span&gt;@@ impl&amp;lt;&amp;#39;s&amp;gt; System&amp;lt;&amp;#39;s&amp;gt; for MoveSystem
&lt;&#x2F;span&gt;&lt;span&gt;@@ run(...)
&lt;&#x2F;span&gt;&lt;span&gt;  if let Some(vertical) = input.axis_value(&amp;quot;vertical&amp;quot;) {
&lt;&#x2F;span&gt;&lt;span&gt;      transform.prepend_translation_x(
&lt;&#x2F;span&gt;&lt;span&gt;        horizontal * time.delta_seconds() * speed  as f32
&lt;&#x2F;span&gt;&lt;span&gt;      );
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+     if horizontal &amp;gt; 0.0 {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+       transform.set_rotation_y_axis(std::f32::consts::PI);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+     }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+     if horizontal &amp;lt; 0.0 {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+       transform.set_rotation_y_axis(0.0);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+     }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;span&gt;  if let Some(vertical) = input.axis_value(&amp;quot;vertical&amp;quot;) {
&lt;&#x2F;span&gt;&lt;span&gt;      transform.prepend_translation_y(
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In our &quot;horizontal&quot; check we added:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If the input was greater than 0, flip our sprite on the Y axis.&lt;&#x2F;li&gt;
&lt;li&gt;If the input was less than 0, reset our sprite on the Y axis.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This makes it look like our Seagl is facing the direction they&#x27;re moving which should help boost our Metacritic score when we publish this at the end of the blogpost.&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;We rotate by PI because our 2D sprite is in the 3D world and we&#x27;re rotating it in radians.&lt;&#x2F;p&gt;
&lt;p&gt;Do you ever feel like a 2D sprite in a 3D world? I know I do...&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;seagl-2020&#x2F;SeaGL-move-look.gif&quot; alt=&quot;It moves!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;step-4-eat-some-food-hamburger&quot;&gt;Step 4: Eat some food! 🍔&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;m sure we could all get &lt;em&gt;minutes&lt;&#x2F;em&gt; of fun out of moving our seagl around the screen, but this game could really use something else... Something tastier.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s add burgers.&lt;&#x2F;p&gt;
&lt;p&gt;This will require us to do everything we just did, again:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Add a Food Compnent.&lt;&#x2F;li&gt;
&lt;li&gt;Create a Burger entity with the food component.&lt;&#x2F;li&gt;
&lt;li&gt;Add an Eat system.&lt;&#x2F;li&gt;
&lt;li&gt;Register our Eat system with the game.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;First we need to add a food Component.&lt;&#x2F;p&gt;
&lt;p&gt;Add this component anywhere that feels right:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Default)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;Food;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;Component &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;Food {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;Storage &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;DenseVecStorage&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;Self&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s structurally identical to our Seagl, but with a different &lt;code&gt;struct&lt;&#x2F;code&gt; it&#x27;s a totally different component.&lt;&#x2F;p&gt;
&lt;p&gt;With a Food component we can add our Burger entity.
Add this code to our &lt;code&gt;on_setup&lt;&#x2F;code&gt; function at the end:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; burger_sprite &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;SpriteRender::new(sprite_sheet_handle.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;clone&lt;&#x2F;span&gt;&lt;span&gt;(), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; transform &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Transform::default();
&lt;&#x2F;span&gt;&lt;span&gt;transform.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;set_translation_xyz&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;75.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;75.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;data.world
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;create_entity&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;(Food::default())
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;(burger_sprite)
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;(transform)
&lt;&#x2F;span&gt;&lt;span&gt;    .&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;build&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We create an entity spawning it at the point (75, 75, -1).&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;We spawn the burger at &lt;code&gt;z=-1&lt;&#x2F;code&gt; to ensure the Seagl sprite is closer to
the camera and thus is drawn on top of the burger.&lt;&#x2F;p&gt;
&lt;p&gt;Have you ever seen a Seagull &lt;em&gt;behind&lt;&#x2F;em&gt; a burger? That&#x27;s ridiculous.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;A few exercises left to the reader:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;How would you spawn multiple burgers?&lt;&#x2F;li&gt;
&lt;li&gt;How would you re-spawn burgers when one is eaten?&lt;&#x2F;li&gt;
&lt;li&gt;How would you keep track of how many burgers were eaten?&lt;&#x2F;li&gt;
&lt;li&gt;How would you display the number of burgers eaten?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I&#x27;ve only covered enough in this post to answer the first two.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;And finally an &quot;eat&quot; system.&lt;&#x2F;p&gt;
&lt;p&gt;This system&#x27;s pseudocode looks like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;For each seagl with a location:
&lt;&#x2F;span&gt;&lt;span&gt;    For each Food with a location:
&lt;&#x2F;span&gt;&lt;span&gt;        If the Seagl overlaps with the Food:
&lt;&#x2F;span&gt;&lt;span&gt;            Destory that food
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a bit of a hack.
If this were a real game we would keep track of how many burgers the Seagl ate, but for this demo, we&#x27;ll be lazy:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span&gt;EatSystem;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; System&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;EatSystem {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;SystemData &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;        ReadStorage&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;, Transform&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ReadStorage&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;, Seagl&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        ReadStorage&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;, Food&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;        Entities&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;#39;s&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    );
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;mut &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, (&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;transforms&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;seagls&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;foods&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;entities&lt;&#x2F;span&gt;&lt;span&gt;): &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;Self::&lt;&#x2F;span&gt;&lt;span&gt;SystemData) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(_seagl, seagl_pos) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;seagls, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;transforms).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(_food, food_pos, entity) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;foods, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;transforms, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;entities).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&#x2F;&#x2F; https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Games&#x2F;Techniques&#x2F;2D_collision_detection
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(seagl_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; food_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;5.0&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&amp;amp;
&lt;&#x2F;span&gt;&lt;span&gt;                   (seagl_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8.0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; food_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().x) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&amp;amp;
&lt;&#x2F;span&gt;&lt;span&gt;                   (seagl_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().y &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; food_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().y &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;4.0&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;amp;&amp;amp;
&lt;&#x2F;span&gt;&lt;span&gt;                   (seagl_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().y &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8.0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; food_pos.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;translation&lt;&#x2F;span&gt;&lt;span&gt;().y)
&lt;&#x2F;span&gt;&lt;span&gt;                {
&lt;&#x2F;span&gt;&lt;span&gt;                    entities.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;delete&lt;&#x2F;span&gt;&lt;span&gt;(entity).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;                }
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And last but not least, we need to register this system with our game:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ main.rs
&lt;&#x2F;span&gt;&lt;span&gt;@@ fn main() -&amp;gt; amethyst::Result&amp;lt;()&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;     let game_data = GameDataBuilder::default()
&lt;&#x2F;span&gt;&lt;span&gt;         .with_bundle(transform)?
&lt;&#x2F;span&gt;&lt;span&gt;         .with_bundle(renderer)?
&lt;&#x2F;span&gt;&lt;span&gt;         .with_bundle(inputs)?
&lt;&#x2F;span&gt;&lt;span&gt;         .with(MoveSystem, &amp;quot;move_system&amp;quot;, &amp;amp;[&amp;quot;input_system&amp;quot;])
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        .with(EatSystem, &amp;quot;eat_system&amp;quot;, &amp;amp;[&amp;quot;move_system&amp;quot;]);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;seagl-2020&#x2F;SeaGL-move-look-burger.gif&quot;
class=&quot;align-center&quot; alt=&quot;It moves!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;We did it. We made a lil&#x27; game. It had a Seagl and a burger. And we had
fun making it.&lt;&#x2F;p&gt;
&lt;p&gt;I wouldn&#x27;t say it&#x27;s &lt;em&gt;easy&lt;&#x2F;em&gt; to make games in Rust, but we are &lt;em&gt;very far&lt;&#x2F;em&gt;
from having to write games from scratch.&lt;&#x2F;p&gt;
&lt;p&gt;If this post piqued your interest I hope you check out &lt;a href=&quot;https:&#x2F;&#x2F;arewegameyet.rs&quot;&gt;https:&#x2F;&#x2F;arewegameyet.rs&lt;&#x2F;a&gt; to learn more about the Rust Games ecosystem, and &lt;a href=&quot;https:&#x2F;&#x2F;amethyst.rs&quot;&gt;https:&#x2F;&#x2F;amethyst.rs&lt;&#x2F;a&gt; to learn more about this budding Game Engine.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;SeaGL conference website: &lt;a href=&quot;https:&#x2F;&#x2F;seagl.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;seagl.org&#x2F;&lt;&#x2F;a&gt; (You should go if you&#x27;re in the Pacific Northwest)&lt;&#x2F;li&gt;
&lt;li&gt;The code for this post is avaliable at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pop&#x2F;lets-make-games-with-rust&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;pop&#x2F;lets-make-games-with-rust&lt;&#x2F;a&gt;. I even tagged each step so you can see exactly what we added!&lt;&#x2F;li&gt;
&lt;li&gt;Rust Language: &lt;a href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Are We Game Yet?: &lt;a href=&quot;https:&#x2F;&#x2F;arewegameyet.rs&#x2F;&quot;&gt;https:&#x2F;&#x2F;arewegameyet.rs&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Amethyst Game Engine website: &lt;a href=&quot;https:&#x2F;&#x2F;amethyst.rs&#x2F;&quot;&gt;https:&#x2F;&#x2F;amethyst.rs&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Amethyst Game Engine book has a great introduction and overview: &lt;a href=&quot;https:&#x2F;&#x2F;book.amethyst.rs&#x2F;stable&#x2F;&quot;&gt;https:&#x2F;&#x2F;book.amethyst.rs&#x2F;stable&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Bevy Game Engine is an interesting iteration on Game Engines in Rust: &lt;a href=&quot;https:&#x2F;&#x2F;bevyengine.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;bevyengine.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;My Source that C++ is the defacto language in the games industry: &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;rX0ItVEVjHc&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;rX0ItVEVjHc&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Game Programming Patterns is an awesome book with a free &amp;amp; legal copy online: &lt;a href=&quot;https:&#x2F;&#x2F;gameprogrammingpatterns.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;gameprogrammingpatterns.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;rustup&lt;&#x2F;code&gt; homepage for installation instructions: &lt;a href=&quot;https:&#x2F;&#x2F;rustup.rs&#x2F;&quot;&gt;https:&#x2F;&#x2F;rustup.rs&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Kubernetes as an external service proxy</title>
        <published>2018-10-13T00:00:00+00:00</published>
        <updated>2018-10-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/kubernetes-as-an-external-service-proxy/"/>
        <id>https://elijah.run/blog/kubernetes-as-an-external-service-proxy/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/kubernetes-as-an-external-service-proxy/">&lt;p&gt;Say you have a firewall restriction that creates the following situation:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;App1 cannot communicate directly with App2.&lt;&#x2F;li&gt;
&lt;li&gt;App1 and App2 can both talk to a Kubernets cluster.&lt;&#x2F;li&gt;
&lt;li&gt;Neither app is hosted on the Kubernetes cluster.&lt;&#x2F;li&gt;
&lt;li&gt;How can you get messages between App1 and App2?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The way the problem is stated makes it pretty obvious that the solution &lt;em&gt;involves&lt;&#x2F;em&gt; using a Kubernetes cluster, but how exactly?&lt;&#x2F;p&gt;
&lt;p&gt;The naive solution might be to spin up a container which acts as a proxy; Nginx comes to mind.
This would definitely work, but I am exceedingly lazy and don&#x27;t want to learn how to configure Nginx.
In fact, the solution I came to doesn&#x27;t involve running any new pods!&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the code.
Below I&#x27;ll explain what&#x27;s happening here and why it works.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Endpoints
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;myapp-proxy
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;subsets&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;addresses&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ip&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;2.3.4.5k &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# App2&amp;#39;s address
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;port&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8080 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# App2&amp;#39;s service port
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Service
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;myapp-proxy
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;LoadBalancer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;loadBalancerSourceRanges&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;1.2.3.4&#x2F;32&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# App1&amp;#39;s address
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;protocol&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;TCP
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;port&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;80 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Redirect traffic hitting 80 to the app&amp;#39;s service port
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;targetPort&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8080
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Ingress
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;restaurant-proxy
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;rules&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;host&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;myapp-proxy.somehost.net
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;http&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;paths&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;backend&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;serviceName&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;myapp-proxy
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;servicePort&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;80
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;endpoints&quot;&gt;Endpoints&lt;&#x2F;h2&gt;
&lt;p&gt;Endpoints are the Kubernetes abstraction for IPs+Ports running the same application.
It&#x27;s how you group together N instances of an app into one pool.&lt;&#x2F;p&gt;
&lt;p&gt;Under the hood Endpoints get created as a pre-requisite for every Service you deploy.
You don&#x27;t usually need to deal with these directly as they are created implicitly whenever a Deployment gets applied.&lt;&#x2F;p&gt;
&lt;p&gt;By manually creating an endpoint we have imported our non-kubernetes app into Kubernetes.
That means we can do Kubernetes things with it like expose it via a Service or even put it behind an Ingress Pretty neat!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;service&quot;&gt;Service&lt;&#x2F;h2&gt;
&lt;p&gt;Services are how we expose an endpoint to the world.
Most cloud providers will give you a public IP address for a service and load balance across all of that service&#x27;s endpoints.&lt;&#x2F;p&gt;
&lt;p&gt;This is as far as we need to proxy traffic between our two Apps.
App1 makes a request to whatever IP Kubernetes gets for the &lt;code&gt;myapp-proxy&lt;&#x2F;code&gt; Service and relays it to the &lt;code&gt;myapp-proxy&lt;&#x2F;code&gt; endpoint, which ultimately routes the traffic to App2.
What&#x27;s really cool is that the endpoint that &lt;strong&gt;is&lt;&#x2F;strong&gt; App2 can be an self-hosted Virtual Machine, as long as the IP doesn&#x27;t change this proxy will continue to work.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ingress&quot;&gt;Ingress&lt;&#x2F;h2&gt;
&lt;p&gt;Ingresses are my favorite part of Kubernetes.
They&#x27;re very convenient, incredibly powerful, and they work like... over half the time.&lt;&#x2F;p&gt;
&lt;p&gt;While not strictly necessary, this Ingress gives us some nice-to-haves.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Gives us an easy to manage host name via something like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes-incubator&#x2F;external-dns&quot;&gt;External DNS&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Could be extended to terminate SSL, again &quot;for free&quot;, with something like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jetstack&#x2F;cert-manager&quot;&gt;Cert Manager&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So that&#x27;s how we use Kubernetes to manage services (lower-case &#x27;s&#x27;) which aren&#x27;t running in Pods.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Dynamic Attributes in Chef</title>
        <published>2018-06-23T00:00:00+00:00</published>
        <updated>2018-06-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/chef-dynamic-attributes/"/>
        <id>https://elijah.run/blog/chef-dynamic-attributes/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/chef-dynamic-attributes/">&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;&#x2F;h2&gt;
&lt;p&gt;You are trying to set a node attribute in a resource block but it isn&#x27;t working.&lt;&#x2F;p&gt;
&lt;p&gt;For example you have the following code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;ruby_block &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  block &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# some ruby
&lt;&#x2F;span&gt;&lt;span&gt;    node.override[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;  action &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;:run
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; node[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;  notifies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;:run&lt;&#x2F;span&gt;&lt;span&gt;, some_resource[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;  notifies &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;:run&lt;&#x2F;span&gt;&lt;span&gt;, other_resource[whatever]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even though you&#x27;re setting &lt;code&gt;node[&#x27;var&#x27;]&lt;&#x2F;code&gt;, &lt;code&gt;other_resource[whatever]&lt;&#x2F;code&gt; is getting notified to &lt;code&gt;:run&lt;&#x2F;code&gt;.
What gives?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;&#x2F;h2&gt;
&lt;p&gt;To jump ahead, because you&#x27;re skimming this post for the answer, you&#x27;re going to want to do something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# go-go-gadget diffs
&lt;&#x2F;span&gt;&lt;span&gt;# Chef Version 13.5.8
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ruby_block &amp;#39;foo&amp;#39; do
&lt;&#x2F;span&gt;&lt;span&gt;    block do
&lt;&#x2F;span&gt;&lt;span&gt;      # some ruby
&lt;&#x2F;span&gt;&lt;span&gt;      node.override[&amp;#39;var&amp;#39;] = &amp;#39;value&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;    end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-   action :run
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+   action :nothing
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;- end
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+ end.run_action(:run)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;if node[&amp;#39;var&amp;#39;] == &amp;#39;value&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;  notifies :run, some_resource[name]
&lt;&#x2F;span&gt;&lt;span&gt;else
&lt;&#x2F;span&gt;&lt;span&gt;  notifies :run, other_resource[whatever]
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Basically you want to execute the &lt;code&gt;ruby_block&lt;&#x2F;code&gt; that sets your attribute &lt;strong&gt;now&lt;&#x2F;strong&gt; so the rest of your code can consume the value either later in the compilation phase or during the execution phase of the Chef run.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-why-did-that-work&quot;&gt;How&#x2F;why did that work?&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;ve read his far you&#x27;re actually reading.
Welcome to the post!
Let&#x27;s begin.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s dig into &lt;em&gt;exactly&lt;&#x2F;em&gt; what my problem was, because sometimes examples aren&#x27;t good enough.
You know... for fun.&lt;&#x2F;p&gt;
&lt;p&gt;I was trying to trigger an application upgrade based on the current installed version.
I was &lt;em&gt;not&lt;&#x2F;em&gt; installing a package-manager-managed package&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; so I couldn&#x27;t just pin the version a &lt;code&gt;yum&lt;&#x2F;code&gt; resource, I had to do this kludge of a solution.&lt;&#x2F;p&gt;
&lt;p&gt;So for me &lt;code&gt;some_resource[name]&lt;&#x2F;code&gt; was downloading the latest version of the app (a &lt;code&gt;.tar.gz2&lt;&#x2F;code&gt; file from GitHub) and &lt;code&gt;other_resource[whatever]&lt;&#x2F;code&gt; was a no-op. The as part of the package download I unconditionally trigger a &lt;code&gt;:delayed&lt;&#x2F;code&gt; service restart.
Chef was &#x27;upgrading&#x27; and restarting my app every thirty minutes which broke core functionality.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shit-i-tried-before-stumbling-upon-the-solution&quot;&gt;Shit I tried before stumbling upon the solution&lt;&#x2F;h2&gt;
&lt;p&gt;I tried a bunch of things, but they can all kinda be summed up in this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;# yay more diffs
&lt;&#x2F;span&gt;&lt;span&gt;  ruby_block &amp;#39;foo&amp;#39; do
&lt;&#x2F;span&gt;&lt;span&gt;    block do
&lt;&#x2F;span&gt;&lt;span&gt;      # some ruby
&lt;&#x2F;span&gt;&lt;span&gt;      node.override[&amp;#39;var&amp;#39;] = &amp;#39;value&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;    end
&lt;&#x2F;span&gt;&lt;span&gt;    notifies :create, &amp;#39;tar[my-app]&amp;#39;, :immediately # Triggers tar[my-app] to run now
&lt;&#x2F;span&gt;&lt;span&gt;  end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;- if node[&amp;#39;var&amp;#39;] == &amp;#39;value&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-   notify :run, some_resource[name]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;- else
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-   notify :run, other_resource[whatever]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;- end
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  tar &amp;#39;my-app&amp;#39; do
&lt;&#x2F;span&gt;&lt;span&gt;    action  :nothing # Unless triggered this does nothing
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+   only_if { node[&amp;#39;var&amp;#39;] == &amp;#39;value&amp;#39; } # This should also do nothing if this isn&amp;#39;t true
&lt;&#x2F;span&gt;&lt;span&gt;    # The rest of the resource block
&lt;&#x2F;span&gt;&lt;span&gt;  end
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which ultimately didn&#x27;t work either.&lt;&#x2F;p&gt;
&lt;p&gt;I... I have no idea why this didn&#x27;t work.&lt;&#x2F;p&gt;
&lt;p&gt;Something something Chef is complicated.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-the-solution-works-and-the-other-stuff-didn-t&quot;&gt;Why the solution works (and the other stuff didn&#x27;t)&lt;&#x2F;h2&gt;
&lt;p&gt;The reason my ultimate solution &lt;em&gt;did&lt;&#x2F;em&gt; work is best summed up by this quote from the &lt;a href=&quot;https:&#x2F;&#x2F;docs.chef.io&#x2F;resource_common.html#run-action&quot;&gt;Chef Docs&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use &lt;code&gt;.run_action(:some_action)&lt;&#x2F;code&gt; at the end of a resource block to run
the specified action during the compile phase.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;My original code (read: broken code) was running the &lt;code&gt;if&lt;&#x2F;code&gt; block during the compilation phase (happens earlier) and running the &lt;code&gt;ruby_block&lt;&#x2F;code&gt; in the execution phase (happens later).
By telling it to run my &lt;code&gt;ruby_block&lt;&#x2F;code&gt; during the compilation phase we were ensuring it happened before the &lt;code&gt;if&lt;&#x2F;code&gt; block, and in a way running it like you would &#x27;expect&#x27; a script to run.&lt;&#x2F;p&gt;
&lt;p&gt;It ain&#x27;t idiomatic but it gets the job done.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errata&quot;&gt;Errata&lt;&#x2F;h2&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Say that three times fast.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;The service was in question was Prometheus.
When Chef ran every 30 minutes, it killed the Prometheus process and thus killed all of our pending alerts.
TLDR we didn&#x27;t get any alerts that took more than 30 minutes to trigger We also &lt;em&gt;kept&lt;&#x2F;em&gt; getting alerts that should taken a few hours to re-notify.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>I. Fucking. Graduated.</title>
        <published>2017-12-12T00:00:00+00:00</published>
        <updated>2017-12-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/graduation/"/>
        <id>https://elijah.run/blog/graduation/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/graduation/">&lt;p&gt;Today I checked my grades for the last time.
I can safely say that I have &lt;strong&gt;finally&lt;&#x2F;strong&gt; gotten a gorramn undergraduate degree in Computer Science, with a minor in Mathematics, from Oregon State University.[^1]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I hear that this happens on the reg&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; but I&#x27;m sure that every single person who &lt;em&gt;actually graduates&lt;&#x2F;em&gt; feels amazing when they do.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s not amazing because graduation is a Herculean feat.
I know I&#x27;m not a 60 year old grandmother who dreamt of getting a college degree for 45 years and finally scraped together the cash and time in retirement.
I&#x27;m also not a refugee that escaped a war-torn country for an education and a better life.
I&#x27;m just another white dude that checked all the boxes.&lt;&#x2F;p&gt;
&lt;p&gt;It wasn&#x27;t hard for me. I just had to put my head down and do the work.
But it did take a long ass time.&lt;&#x2F;p&gt;
&lt;p&gt;Honestly my story is exactly like &lt;em&gt;most&lt;&#x2F;em&gt; college graduation stories.
I went to kindergarten, then elementary school, then middle school, then high school, then college, and now life.
I plugged away at school, did what I needed to pass my classes, stressed and lamented, studied hard and eventually the system said &quot;Cool.You&#x27;re done.&quot; Along the way I learned how to &quot;play the game&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, albeit a bit late compared to a lot of my peers.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m thankful to be in a field which doesn&#x27;t require a masters or PHD to get a jorb.
Heck my field doesn&#x27;t really require the degree I got; a surprising number of my friends got well paying jobs sans-degree.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m also thankful to graduate without debt.
This came from some kickass parents + grandparents, some work during school, and some bad stuff that happened which ended up paying for abou half of my tuition.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m thankful to graduate with wonderful friends, a job, and some passions which make my work-related decisions simple and profitable.&lt;&#x2F;p&gt;
&lt;p&gt;Last, I&#x27;m thankful to be &lt;em&gt;done&lt;&#x2F;em&gt;. Now I can finally focus on &lt;em&gt;learning&lt;&#x2F;em&gt;, my real passion.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m gonna have a &lt;a href=&quot;https:&#x2F;&#x2F;10barrel.com&#x2F;beer&#x2F;crush-cucumber-sour&#x2F;&quot;&gt;Cucumber Sour&lt;&#x2F;a&gt; and celebrate.
Thanks for reading.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;I don&#x27;t claim to have the best sources, but at least it&#x27;s not Yahoo Answers: &lt;a href=&quot;https:&#x2F;&#x2F;www.reference.com&#x2F;education&#x2F;many-people-graduate-college-year-8b0ccf821050d39e&quot;&gt;https:&#x2F;&#x2F;www.reference.com&#x2F;education&#x2F;many-people-graduate-college-year-8b0ccf821050d39e&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Go beavs.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;I&#x27;m 99% sure I graduated.
Something horribly kafkaesque might still happen, but fuckit.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;This is shorthand for tips and tricks to get through school.&lt;&#x2F;p&gt;
&lt;p&gt;School isn&#x27;t really focused on making sure you &lt;em&gt;learned&lt;&#x2F;em&gt;, it&#x27;s mostly designed to make sure you can pass tests.
Once you figure this out you can focus on learning for the test instead of trying to grok the material.
I believe the kids call it a &quot;life hack&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Not that you shouldn&#x27;t try to grok the material, that just happens to take &lt;em&gt;way&lt;&#x2F;em&gt; longer than test-based learning.
So if you want a personal life, learn for the test; if you want a PHD, learn for the material.&lt;&#x2F;p&gt;
&lt;p&gt;I didn&#x27;t figure this system out until about Junior year of High School, too late to apply this zen skill to the ACT and SAT, but it was useful in college.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Independent Crypto Conclusion</title>
        <published>2017-11-27T00:00:00+00:00</published>
        <updated>2017-11-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/independent-crypto-conclusion/"/>
        <id>https://elijah.run/blog/independent-crypto-conclusion/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/independent-crypto-conclusion/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This is a part of a series of blog posts I wrote for an Independent Study on cryptography at Oregon State University.
To read all of the posts, check out the &#x27;Independent Crypto&#x27; tag.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Wait, is it over already? It feels like we just started! Those 10 weeks always fly by, and this term was no exception.&lt;&#x2F;p&gt;
&lt;p&gt;Independent Crypto has been a thrill, an honor, and of course immensely educational.
It&#x27;s been a blast to say the least.
The weekly check-ins with my mentor &lt;a href=&quot;http:&#x2F;&#x2F;web.engr.oregonstate.edu&#x2F;~rosulekm&#x2F;&quot;&gt;Mike Rosulek&lt;&#x2F;a&gt;, forcing myself to engage with academic papers and online lectures, and finally having complex topics like Garbled Circuits and Elliptic Curves &quot;make sense&quot;, it was all very enjoyable.
I am very fortunate to have been given the opportunity to both create this course and take it.
Excited as I was before it began, it turned out even better than I could have hoped.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s reflect on the some of the things we learned...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;elliptic-curve-cryptography&quot;&gt;Elliptic Curve Cryptography&lt;&#x2F;h2&gt;
&lt;p&gt;We learned that Elliptic Curves look like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;ecc-1.png&quot; alt=&quot;A straight forward ECC.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;and this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;ecc-3.png&quot; alt=&quot;ECC with the line L illustrated&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We also learned that you can implement a version of the Diffie-hellman key exchange protocol by &quot;adding&quot; points on an Elliptic Curve over a finite field.&lt;&#x2F;p&gt;
&lt;p&gt;We also learned that despite how weird Elliptic Curve Cryptography sounds when you describe it, it can be used in very secure and efficient crypto.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;memory-hard-functions&quot;&gt;Memory Hard Functions&lt;&#x2F;h2&gt;
&lt;p&gt;We learned that Memory Hard Functions (MHFs) are a solution to the arms race that is hash-cracking hardware.
Importantly, it relies on the fact that while there are specialized hashing processors, there is no specialized RAM for the same task (or any task really).&lt;&#x2F;p&gt;
&lt;p&gt;The goal of an MHF is to make it as hard (or harder) for an adversary to compute a given hash as it was for you, assuming you&#x27;re running on non-specialized hardware and they have specialized hash-cracking hardware.&lt;&#x2F;p&gt;
&lt;p&gt;We learned that there are two types of MHF&#x27;s: data-dependent and data-independent.
Data-dependent MFHs (dMHFs) have predictable memory usage patterns so they may be susceptible to cache-timing attacks.
Data-independent MHFs (iMHFs) are not susceptible to this attack as their memory patterns are not predictable.
While there are dMHFs in the wild, like scrypt which performs exceptionally well, there are not any any proven iMHFs in use.&lt;&#x2F;p&gt;
&lt;p&gt;We also learned that this is what it looks like to &quot;Pebble an iMHF Directed Acyclic Graph&quot;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;dag-animated.gif&quot; alt=&quot;Animated DAG traversal.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We also learned that the way to attack an iMHF is by performing a breadth-first search on the graph, then once you hit a wall, fill in the
necessary nodes (pebbles) until you can compute the next node.
Much of the active research into iMHFs is in figuring out the best graphs, or types of graphs, to combat these kinds of feather&#x2F;balloon attacks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;garbled-circuits&quot;&gt;Garbled Circuits&lt;&#x2F;h2&gt;
&lt;p&gt;We learned that Garbled Circuits are a way of achieved two-party secure function evaluation.&lt;&#x2F;p&gt;
&lt;p&gt;Alice and Bob agree on a circuit (program) to garble.
One party encrypts the circuit by encrypting each logic-gate.
Both parties obfuscate their inputs and evaluate the garbled circuit.
This gives both parties the result of the original program without either party knowing the exact inputs.&lt;&#x2F;p&gt;
&lt;p&gt;This isn&#x27;t a fool-proof security measure.
Sometimes it is good to ask the party garbling said circuits to create a few extras.
The evaluating party opens some of them to make sure they&#x27;re on the up-and-up.
The other party evaluates the remaining circuits and verifies that the outputs are consistent.&lt;&#x2F;p&gt;
&lt;p&gt;We also learned that this game is surprisingly fun for only having &lt;strong&gt;four levels&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;iframe src=&quot;&#x2F;garbled-circuits-game.html&quot; height=&quot;400px&quot; width=&quot;100%&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;Permalink: &lt;a href=&quot;http:&#x2F;&#x2F;elijah.run&#x2F;garbled-circuits-game.html&quot;&gt;http:&#x2F;&#x2F;elijah.run&#x2F;garbled-circuits-game.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;remote-timing-attacks&quot;&gt;Remote Timing Attacks&lt;&#x2F;h2&gt;
&lt;p&gt;And now for something completely different!
We broke from the math and theory to focus on a problem involving real tangible bits!&lt;&#x2F;p&gt;
&lt;p&gt;Based on response timing differences an adversary can sometimes determine private information &lt;strong&gt;like your OpenSSL Private Keys&lt;&#x2F;strong&gt;.
This is scary, but the problem has mostly been fixed and now there are standards the crypto community follows to write code which is secure against these attacks.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re writing crypto and you know what you&#x27;re doing, make sure you&#x27;re using the defacto constant-time libraries for bit-wise comparisons, mathematical operations, and pretty much anything involving secrets.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;miscellaneous&quot;&gt;Miscellaneous&lt;&#x2F;h2&gt;
&lt;p&gt;I personally gained a lot from this course.
I wrote annotated bibliographies, read academic papers, implemented a remote timing attack, and made a fun little game which was totally relevant and 100% not just an excuse to play around making games.&lt;&#x2F;p&gt;
&lt;p&gt;Despite sinking hours into this course I barely scratched the surface of every topic.
I&#x27;ve got &lt;em&gt;loads&lt;&#x2F;em&gt; more I could cover if I was inclined to do so.
I&#x27;m not saying I&#x27;m &lt;em&gt;going&lt;&#x2F;em&gt; to get a graduate degree, but if it&#x27;s anything like this I&#x27;d be up for it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Remote Timing Attacks</title>
        <published>2017-11-20T00:00:00+00:00</published>
        <updated>2017-11-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/remote-timing-attacks/"/>
        <id>https://elijah.run/blog/remote-timing-attacks/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/remote-timing-attacks/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This is a part of a series of blog posts I wrote for an Independent
Study on cryptography at Oregon State University. To read all of the
posts, check out the &#x27;Independent Crypto&#x27; tag.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Fade in.&lt;&#x2F;p&gt;
&lt;p&gt;It is 2002.&lt;&#x2F;p&gt;
&lt;p&gt;You are a Linux system administrator.
You and thousands of other admins are running OpenSSL on you battle tested Linux servers.
You trust that your data is transfered securely from host to host because... why wouldn&#x27;t it be?!
OpenSSL makes things secure.
Duh.&lt;&#x2F;p&gt;
&lt;p&gt;A few months into running that server you figure out that your private keys have been compromised!
They were stolen somehow but you can&#x27;t figure out what happened.
You check the logs to see if somebody hacked into your system, but nothing obvious catches your eye.&lt;&#x2F;p&gt;
&lt;p&gt;Combing through the logs you do see an IP address that tried (and failed) hundreds of thousands of times to authenticate with your OpenSSL server. It attempted authentication over and over and failed relentlessly until suddenly, after about two days, it stopped.
Weird.&lt;&#x2F;p&gt;
&lt;p&gt;A year later you read an academic paper from Stanford.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
It clicks.
You&#x27;ve you&#x27;ve been Remote Timing Attacked!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;definition&quot;&gt;Definition&lt;&#x2F;h2&gt;
&lt;p&gt;Remote Timing Attacks are a special brand of Side Channel Attack where adversaries use differences in response times to determine private information.
Creepy I know.&lt;&#x2F;p&gt;
&lt;p&gt;A lot of code and Statistics&lt;sup&gt;TM&lt;&#x2F;sup&gt; goes into figuring out secret information based on this, but let&#x27;s start small.
Take the following comparison which lives in a hypothetical SSL library:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;length&lt;&#x2F;span&gt;&lt;span&gt;(recieved_key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PRIVATE_KEY_LENGTH&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;KeyLengthError
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;recieved_key &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span&gt;expected_key:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;Thing
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;UnknownKeyError
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This might seem innocent enough but as it turns out this leaks information!
The &lt;code&gt;==&lt;&#x2F;code&gt; operator does not &lt;em&gt;always&lt;&#x2F;em&gt; take the same amount of time to return a response.
In fact, this operator tends to compare two inputs bit-by-bit.
When it finds a difference it short-circuits and returns True or False.
If &lt;code&gt;recieved_key&lt;&#x2F;code&gt; shares the first N bits with &lt;code&gt;expected_key&lt;&#x2F;code&gt;, the program will return slightly sooner than if they only shared the first N-1 bits.&lt;&#x2F;p&gt;
&lt;p&gt;What&#x27;s the timing difference if it&#x27;s just returning one or two cycles earlier; does it really matter?
As it turns out, there is &lt;em&gt;enough&lt;&#x2F;em&gt; of a difference to break security and enable an adversary to decrypt entire private keys!&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This is put well by an article on chosenplaintext.ca:&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now, it may not seem significant that an attacker can see how many bytes of their key were a match, but it can actually be &lt;strong&gt;fatal&lt;&#x2F;strong&gt; to security.
The attacker can crack the first byte of the key by trying all 256 possibilities, and observing which one caused the comparison to take longer.
Now, armed with the first byte, they can do the same with the second byte, and the third, and so on, until they have recovered the entire key.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;With a lot of patience an adversary can recover secret information from an OpenSSL processes on the same host OS, an OpenSSL processes on a Virtual Machine on the same host OS, and even an OpenSSL on a separate host processes across a network.
It gets harder (read: more time consuming) to hack the farther away adversary, but they&#x27;re all possible with sufficient patience, compute power, and Statistics&lt;sup&gt;TM&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;oh-god-fix-it-please&quot;&gt;Oh god fix it please&lt;&#x2F;h2&gt;
&lt;p&gt;Clam down!
We&#x27;ve come a long way since 2003 when this was proven to be a viable attack.
Most SSL libraries have fixed this vulnerability so you&#x27;re fine as long as you updated in the past decade.&lt;&#x2F;p&gt;
&lt;p&gt;If you &lt;em&gt;haven&#x27;t&lt;&#x2F;em&gt; updated in the past decade... burn that server.
Even the silicon atoms are compromised. It&#x27;s not even worth trying a fresh install.
The thing is just too far gone, start fresh.
Goodnight, sweet prince.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;constant-time-algorithms&quot;&gt;Constant-time Algorithms&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;How did the crypto libraries solve this problem?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Constant-time Algorithms&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Oh fancy, tell me more.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Constant-time Algorithms are a way of implementing an algorithm in a way that always takes the same amount of time to compute regardless of the input.&lt;&#x2F;p&gt;
&lt;p&gt;Specifically, these perform in constant-time while processing &lt;em&gt;secret&lt;&#x2F;em&gt; information.
This distinction means processing a secret key &lt;em&gt;always&lt;&#x2F;em&gt; takes N cycles while checking that a configuration file is correctly formatted might take a M cycles or maybe M+5.&lt;&#x2F;p&gt;
&lt;p&gt;There are a lot of coding practices to be aware of in crypto which help us to avoid leaking information for Remote Timing Attacks.
Let&#x27;s go over a few.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;limit-conditionals-on-secrets&quot;&gt;Limit conditionals on secrets&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Avoid conditioning on secret information to avoid (among other things)
CPU branch predictions.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Take this code for example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;usually_true:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;do_usual_thing&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Path A
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;do_weird_thing&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Path B
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The CPU eventually will recognize that Path A is going to happen more than Path B so it will try to optimize for that path, making the &quot;usual thing&quot; faster.
This makes sense from a CPU designer standpoint&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but it leaks information about which branch is being taken.
When the &quot;unusual thing&quot; happens the CPU has to backpedal before continuing, which takes a notable amount of time.
This backpedaling gives an adversary enough information to craft an attack the path they&#x27;re on and extrapolate secret information based on that path-awareness.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;This type of attack (conditioning on private information) is explored in the Constant Time Algorithm example and Remote Timing Attack demo near the end of the post.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;division-multiplication-tricky-stuff&quot;&gt;Division&#x2F;Multiplication: tricky stuff&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Multiplication is not always constant-time.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Take this piece of code.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;t1_a = current_time
&lt;&#x2F;span&gt;&lt;span&gt;small_number_a * small_number_b
&lt;&#x2F;span&gt;&lt;span&gt;t2_a = current_time
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;t1_b = current_time
&lt;&#x2F;span&gt;&lt;span&gt;big_number_a * big_number_b
&lt;&#x2F;span&gt;&lt;span&gt;t2_b = current_time
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;assert(t2_a - t1_a == t2_b - t1_b)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Believe it or not, even though the first and second blocks are just multiplying two numbers together they can take different amounts of time depending on your CPU and compiler.&lt;&#x2F;p&gt;
&lt;p&gt;This is triggered by some CPUs just not being equipped to handle large numbers, so they have to perform the large number multiplication in software.
Other CPUs optimize for small numbers since those get handled more frequently than large numbers.
These are pretty old hardware limitations, and the issue has mostly been resolved in newer 64-bit CPUs.
That said... you know... still something to lookout for.&lt;&#x2F;p&gt;
&lt;p&gt;The same goes for division. Many CPUs don&#x27;t have hardware support for division so the compiler needs to handle the operation in software.&lt;&#x2F;p&gt;
&lt;p&gt;TLDR: the same piece of code which is constant-time on one architecture (X86_64) might not be constant-time on another piece of hardware (x86_32 for example).&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compilers-and-undefined-behavior&quot;&gt;Compilers and undefined behavior&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Watch out for compiler&#x27;s &quot;undefined behavior&quot;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The C programming language, and &lt;em&gt;most&lt;&#x2F;em&gt; programming languages, have a formal specification of some kind.
This formal specification gives the programmer a good idea about what their code will do when they compile and run it.&lt;&#x2F;p&gt;
&lt;p&gt;For example if I wrote the following C:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;10 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;20
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;it &lt;em&gt;should&lt;&#x2F;em&gt; run and return &lt;code&gt;30&lt;&#x2F;code&gt;, because the specification tells us that the &lt;code&gt;+&lt;&#x2F;code&gt; operator adds two numbers and &lt;code&gt;return&lt;&#x2F;code&gt; returns a given value from a function.
It also says that &lt;code&gt;main&lt;&#x2F;code&gt; returns a given integer as the exit status.&lt;&#x2F;p&gt;
&lt;p&gt;If I ran that code and it returned &lt;code&gt;-1&lt;&#x2F;code&gt; I&#x27;d be very confused; that breaks specification!
Compiler authors know this and follow the specification of the C language very carefully to make sure specified inputs produce specified outputs.&lt;&#x2F;p&gt;
&lt;p&gt;But what about behavior the specification &lt;em&gt;doesn&#x27;t&lt;&#x2F;em&gt; mention?&lt;&#x2F;p&gt;
&lt;p&gt;Take for instance this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;int &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;fprintf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;214748300 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;214745000&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This might not be explicitly covered by the specification because it&#x27;s pretty weird.
214748300 and 214745000 are close to the signed integer maximum, so when multiplied together what happens?
Will the program print an unsigned integer value of 4611686014132420609 or does it return a signed integer which has overflowed but is still signed?&lt;&#x2F;p&gt;
&lt;p&gt;This kind headache is called Undefined Behavior and it basically means the compiler, or rather the compiler&#x27;s authors, &lt;em&gt;choose&lt;&#x2F;em&gt; which behavior they think is best because the language spec didn&#x27;t say what should happen.&lt;&#x2F;p&gt;
&lt;p&gt;Another side effect hinted at is that while you can be confident what the end behavior of your code will be you can&#x27;t predict how that behavior is achieved.
This didn&#x27;t used to be an issue when C compilers were just 1:1 mapping your C loops and functions to sane assembly.
Fortunately compilers have gotten much better at producing fast and efficient executables.
&lt;strong&gt;Unfortunately&lt;&#x2F;strong&gt;, we aren&#x27;t easily able to predict the runtime of our code because our compilers are liable to pour some black-magic voodoo on any and all binaries it produces.&lt;&#x2F;p&gt;
&lt;p&gt;These points are condensed really well by the BearSSL website:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The C programming language is defined to run in an abstract machine under the &quot;as if&quot; rule, so the compiler is free to translate your code in any sequence of instructions that yield the expected result, with execution time not being part of the observable elements that must be preserved.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Even though we know that a function will always &lt;em&gt;work&lt;&#x2F;em&gt;, the C language (and compiler spec) doesn&#x27;t care about &lt;em&gt;how&lt;&#x2F;em&gt; it gets done.&lt;&#x2F;p&gt;
&lt;p&gt;When you&#x27;re trying to write crypto code this can feel like you&#x27;re a parent telling your kid to clean their room.
They&#x27;ll make it look clean, but they just shoved everything under the bed.
Technically they did what you wanted, the room looks cleaner, but they missed the point.
Something about building character in constant-time.&lt;&#x2F;p&gt;
&lt;p&gt;So what do we do? We need to trick the compiler.&lt;&#x2F;p&gt;
&lt;p&gt;There are a handful of tricks to&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; to get the compiler to (a) avoid
unknown behavior and (b) enforce a specific assembly output.
These are tricks include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Using a bit-wise operations instead of the equivalent mathematical operation.&lt;&#x2F;li&gt;
&lt;li&gt;Mark important &lt;em&gt;secret&lt;&#x2F;em&gt; variables as volatile.&lt;&#x2F;li&gt;
&lt;li&gt;Manually zero out important &lt;em&gt;secret filled&lt;&#x2F;em&gt; memory.&lt;&#x2F;li&gt;
&lt;li&gt;Use multiple sources of entropy; as many as you can get your hands on.&lt;&#x2F;li&gt;
&lt;li&gt;Read the output assembly and become a Jedi.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;These are very high-level solutions to some of the problems, solutions I&#x27;m only going to hand-wavily describe, but honestly that&#x27;s because I don&#x27;t really grok the solutions and don&#x27;t want to lead you astray.
Check out the end of this post for further reading by really smart people that get paid to do this stuff.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-can-t-i-just&quot;&gt;&quot;Why can&#x27;t I just...&quot;&lt;&#x2F;h2&gt;
&lt;p&gt;Just &lt;em&gt;wait&lt;&#x2F;em&gt;? If only.&lt;&#x2F;p&gt;
&lt;p&gt;So the first thought I had (and every other crypto novice has) is something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;do time sensitive operation
&lt;&#x2F;span&gt;&lt;span&gt;sleep N seconds
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This doesn&#x27;t work because this just shifts the amount of time it takes to do an operation, literally &lt;em&gt;just&lt;&#x2F;em&gt; making your crypto take longer.
Then the &lt;em&gt;second&lt;&#x2F;em&gt; thought I and every other crypto novice has is something like:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;record start time
&lt;&#x2F;span&gt;&lt;span&gt;do time sensitive operation
&lt;&#x2F;span&gt;&lt;span&gt;record end time
&lt;&#x2F;span&gt;&lt;span&gt;sleep (expected time - elapsed time) seconds
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is &lt;em&gt;better&lt;&#x2F;em&gt; but you&#x27;ll never &lt;em&gt;nail&lt;&#x2F;em&gt; the expected time.
It&#x27;ll either be too long or too short This means that either some amount of information is leaked, when &lt;code&gt;expected time&lt;&#x2F;code&gt; is too short, or the crypto is needlessly slow, which is just a silly compromise.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#7&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We &lt;em&gt;can&lt;&#x2F;em&gt; make it algorithmically secure without this &lt;code&gt;sleep&lt;&#x2F;code&gt; hack, so we &lt;em&gt;will&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;practical-solutions-to-timing-attacks&quot;&gt;Practical Solutions to Timing Attacks&lt;&#x2F;h2&gt;
&lt;p&gt;If you&#x27;re implementing crypto, STOP.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re implementing crypto and you know what you&#x27;re doing, your language of choice &lt;em&gt;probably&lt;&#x2F;em&gt; has a constant-time library which implements some primitives that you can take advantage of for simple tasks like comparisons. Those can be found at the end of this post in Errata. &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#CTLibs&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After looking into constant-time-ifying your code, do some reading and testing!
There have been a lot of developments in analyzing program constant-time-ness and much of this work is Open Source!
These are implemented using a lot of Statistics&lt;sup&gt;TM&lt;&#x2F;sup&gt;, code inspection, and even Valgrind.[^8][^9]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#10&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
If you&#x27;re really concerned that &lt;em&gt;Your Crypto Library&lt;&#x2F;em&gt; isn&#x27;t secure against Remote Timing Attacks, take one of those tools on a test drive and see what happens.
It&#x27;s pretty likely that you&#x27;ll find a &lt;em&gt;notable&lt;&#x2F;em&gt; timing difference based on different inputs and you&#x27;ll probably need to make changes for your library to be secure against timing attacks.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s for the greater good. Because of your contributions the crypto community is even stronger.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-crazy-idea-constant-time-language-spec&quot;&gt;A crazy idea: constant time language spec&lt;&#x2F;h3&gt;
&lt;p&gt;My crazy idea, for my &lt;em&gt;very&lt;&#x2F;em&gt; hypothetical grad-school studies would be to implement a Constant-time &lt;em&gt;compiler&lt;&#x2F;em&gt; and&#x2F;or &lt;em&gt;language&lt;&#x2F;em&gt;.
This would perform transformations to your code in an attempt to make it constant-time or warning you when your code isn&#x27;t going to run in constant-time when it ought to.&lt;&#x2F;p&gt;
&lt;p&gt;Of course this would take a very long time, and honestly I haven&#x27;t thought it through entirely, but I imagine something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;regular code
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;ct {
&lt;&#x2F;span&gt;&lt;span&gt;    thing that needs to be constant-time.
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;regular code
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Where you tell the compiler &quot;This needs to be constant-time&quot;.
The compiler does it&#x27;s best to convert loops and statements into constant-time and when it&#x27;s done it tells you if it was able to convert your code into constant-time execution or not.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s probably overkill; you don&#x27;t usually just willy-nilly write constant-time code.
That said, just like C and Python help produce less error prone code than writing straight Assembly, so too might a constant-time language help produce code that hits less of the tricky pitfalls of implementing Constant-time algorithms.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;constant-time-algorithm-example&quot;&gt;Constant-time Algorithm example&lt;&#x2F;h2&gt;
&lt;p&gt;Take our code block from the beginning, the one that did the leaky comparison.
That takes different amounts of time when processing a given key against a known private key.
How would we write &lt;em&gt;that&lt;&#x2F;em&gt; in constant-time?&lt;&#x2F;p&gt;
&lt;p&gt;Something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Short circuit based on user input, does not leak private information
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;length&lt;&#x2F;span&gt;&lt;span&gt;(recieved_key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PRIVATE_KEY_LENGTH&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;KeyLengthError
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;recvied_bits  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(recieved_key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Taken to be constant-time
&lt;&#x2F;span&gt;&lt;span&gt;expected_bits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(expected_key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Taken to be constant-time
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Thing
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PRIVATE_KEY_LENGTH&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;recieved_bits[i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!= &lt;&#x2F;span&gt;&lt;span&gt;expected_bits[i]:
&lt;&#x2F;span&gt;&lt;span&gt;        ret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;KeyLengthError &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# This sets the output, but the loop does not break
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;ret
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is similar to our original code but it does a few things differently:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;We convert our keys to a variable which can be operated on bit-wise.&lt;&#x2F;li&gt;
&lt;li&gt;We manually compare each bit of the inputs. This is what the &lt;code&gt;==&lt;&#x2F;code&gt; operator does, but instead of returning when we get a difference we essentially set a switch. &lt;code&gt;ret = Error&lt;&#x2F;code&gt; from &lt;code&gt;ret = Thing&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Outside of the loop we return our response after processing all of our bits.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Behaviorally this is almost identical to our original code, but it does not return earlier or later depending on the user&#x27;s input.&lt;&#x2F;p&gt;
&lt;p&gt;Yet another implementation avoids the direct comparison:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Short circuit based on user input, does not leak private information
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;length&lt;&#x2F;span&gt;&lt;span&gt;(recieved_key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PRIVATE_KEY_LENGTH&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;KeyLengthError
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;recvied_bits  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(recieved_key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Taken to be constant-time
&lt;&#x2F;span&gt;&lt;span&gt;expected_bits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;(expected_key) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Taken to be constant-time
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;matching_bits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;_ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PRIVATE_KEY_LENGTH&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    matching_bits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;xor&lt;&#x2F;span&gt;&lt;span&gt;(recieved_bits[i], expected_bits[i]))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;matching_bits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;PRIVATE_KEY_LENGTH&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;thing
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span&gt;KeyLengthError
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;remote-timing-attack-demo&quot;&gt;Remote Timing Attack demo&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Examples are fine, but what about a demo!
You said this was a real threat!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;True, I did say that... so we&#x27;ll do a small demonstration.&lt;&#x2F;p&gt;
&lt;p&gt;Below is a bit of Python code that checks a user&#x27;s input against some hard-coded secret.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# secret.py
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;time &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;sleep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Used to exaggerate time difference.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;sys &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;argv   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Used to read user input.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;is_equal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;Custom `==` operator&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Fail if the strings aren&amp;#39;t the right length
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;(a) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;(b):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;False
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;(a)):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Short-circuit if the strings don&amp;#39;t match
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;a[i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;!= &lt;&#x2F;span&gt;&lt;span&gt;b[i]:
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;False
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0.15&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# This exaggerates it just enough for our purposes
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;True
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Hard-coded secret globals FOR DEMONSTRATIONS ONLY
&lt;&#x2F;span&gt;&lt;span&gt;secret &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;l33t&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# This is python for &amp;quot;If someone uses you as a script, do this&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;__name__ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;__main__&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# The user got it right!
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;is_equal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;(argv[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;]), secret):
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;You got the secret!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# The user got it wrong
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Try again!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# The user forgot to enter a guess.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;except &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;IndexError&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Usage: python secret.py yourguess&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;The secret may consist of characters in [a-z0-9] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;\
&lt;&#x2F;span&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;and is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt; characters long.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;format&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;(secret)))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The thing that makes the above code particularly useful for our purposes is that it exaggerates the time it takes to evaluate the &lt;code&gt;is_equal&lt;&#x2F;code&gt; function.
Think of this as the &#x27;backpedaling&#x27; the CPU does... turned up to 11. Most important &lt;em&gt;for the author&lt;&#x2F;em&gt; we don&#x27;t need to use Statistics&lt;sup&gt;TM&lt;&#x2F;sup&gt; to figure the secret, evaluating each input multiple times and collecting&#x2F;processing that timing data, it already takes about one magnitude longer to evaluate a matching letter than it does to evaluate a non-matching letter.&lt;&#x2F;p&gt;
&lt;p&gt;Next we&#x27;ve got the attack code.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# attack.py
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;time &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;time &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Used to get a timing difference.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;ascii_lowercase &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# All lowercase characters
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;string &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;digits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# All digits as strings
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;subprocess &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;call &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# used to exec a secret.py
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;from &lt;&#x2F;span&gt;&lt;span&gt;os &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;import &lt;&#x2F;span&gt;&lt;span&gt;devnull  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Suppress output of secret.py
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;current     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;list&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;aaaa&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Initial guess
&lt;&#x2F;span&gt;&lt;span&gt;characters  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;ascii_lowercase&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt;digits &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# All possible characters in the secret
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# We know the string is the same length as our initial guess
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;(current)):
&lt;&#x2F;span&gt;&lt;span&gt;    guess_times &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Keep track of execution times
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;characters:
&lt;&#x2F;span&gt;&lt;span&gt;        current[i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Swap the current letter with the current guess
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Uncomment the following line for fun debug output
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# print(&amp;#39;Making guess {}&amp;#39;.format(&amp;#39;&amp;#39;.join(current)))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Execute `secret.py` and time it
&lt;&#x2F;span&gt;&lt;span&gt;        start &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;time&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;        a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;call&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;python&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;secret.py&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(current)], &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(devnull, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;wb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;))
&lt;&#x2F;span&gt;&lt;span&gt;        end   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;time&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Add that time to the list
&lt;&#x2F;span&gt;&lt;span&gt;        guess_times.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span&gt;(end&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;start)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Uncomment the following line for fun debug output
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# print(&amp;#39;max {} min {}&amp;#39;.format(max(guess_times), min(guess_times)))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# This is a hackey-looking way of getting the outlier time.
&lt;&#x2F;span&gt;&lt;span&gt;    current[i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;characters[guess_times.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;index&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;max&lt;&#x2F;span&gt;&lt;span&gt;(guess_times))]
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;character &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt; is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;format&lt;&#x2F;span&gt;&lt;span&gt;(i, current[i]))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Uncomment the following line for fun debug output
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# print(guess_times.index(max(guess_times)))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Final guess is &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;format&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;join&lt;&#x2F;span&gt;&lt;span&gt;(current)))
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s a bit convoluted in parts but if you stare at it for a while and read the enlightening comments you should see why this gets the right answer.&lt;&#x2F;p&gt;
&lt;p&gt;I encourage you to copy that code into two files, &lt;code&gt;secret.py&lt;&#x2F;code&gt; and &lt;code&gt;attack.py&lt;&#x2F;code&gt; and run it like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ time python attack.py
&lt;&#x2F;span&gt;&lt;span&gt;character 0 is l
&lt;&#x2F;span&gt;&lt;span&gt;character 1 is 3
&lt;&#x2F;span&gt;&lt;span&gt;character 2 is 3
&lt;&#x2F;span&gt;&lt;span&gt;character 3 is t
&lt;&#x2F;span&gt;&lt;span&gt;Final guess is l33t
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;real  0m35.176s
&lt;&#x2F;span&gt;&lt;span&gt;user  0m1.300s
&lt;&#x2F;span&gt;&lt;span&gt;sys 0m0.485s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ python secret.py l33t
&lt;&#x2F;span&gt;&lt;span&gt;You got the secret!
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You&#x27;ll need a working Python installation and probably a shell of some kind.
I&#x27;m on CentOS Linux but any *nix system will &lt;em&gt;probably&lt;&#x2F;em&gt; work.
With some fiddling you can probably get it to work on Windows ;-)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This isn&#x27;t a real threat! You exaggerated the problem!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Hush now.
It demonstrates the principles of the attack.
Besides, the post is over.
We&#x27;ve only got time for the conclusion and then you&#x27;re off to bed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;constant-time-blogpost&quot;&gt;Constant-time blogpost&lt;&#x2F;h2&gt;
&lt;p&gt;This topic has been a break from the theory&#x2F;math-heavy term thus far.
Honestly I&#x27;m jazzed about it.&lt;&#x2F;p&gt;
&lt;p&gt;We learned that something as small as a comparison (a &lt;em&gt;comparison&lt;&#x2F;em&gt;!) can leak information to an adversary.
Your algorithm might be secure, but if you&#x27;re not careful you can leak information in the most menial code.&lt;&#x2F;p&gt;
&lt;p&gt;This isn&#x27;t a lost cause.
We don&#x27;t need to throw this &lt;em&gt;security&lt;&#x2F;em&gt; thing out the window.
If we&#x27;re aware of the gotchas we can craft code that solves these problems.
It&#x27;s hard work but the peace of mind should make it worth it.&lt;&#x2F;p&gt;
&lt;p&gt;Learning about this seemingly obscure (&lt;em&gt;terrifying&lt;&#x2F;em&gt;) exploit in algorithmically secure code is just the kind of headache I enjoy in Computer Science.
Although I don&#x27;t feel like I did Remote Timing Attacks justice, I could probably spend weeks on it, I had to call it quits.
I could keep working on this for &lt;em&gt;another 10 weeks&lt;&#x2F;em&gt;, but it&#x27;s over.
Just walk away.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;annotated-bibliography&quot;&gt;Annotated Bibliography&lt;&#x2F;h2&gt;
&lt;p&gt;BearSSL[^11]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#12&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
: BearSSL is a project which aims to make an architecture-independent constant-time implementation of various Crypto Libraries, largely mirroring compatibility with OpenSSL and related Open Source crypro libraries.
Not only is the project interesting but a handful of blogposts and analysis are posted on the website covering topics like how to implement RSA in constant-time to the compatibility of various CPU models with assumptions about constant-time operations (e.g., multiplication).&lt;&#x2F;p&gt;
&lt;p&gt;Remote Timing Attacks are Practical&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#13&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
: This paper was very easy to read for an academic article and covered the creation of various timing attacks in practical conditions (e.g., hacking an RSA private key across a network).&lt;&#x2F;p&gt;
&lt;p&gt;Beginner focused blogs[^14]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#15&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
: These were two blogposts which laid out what timing attack, why they were viable, and how you can avoid them.
Protip: never assume a library you&#x27;re using is constant-time.&lt;&#x2F;p&gt;
&lt;p&gt;Adam Langley&#x27;s blog[^16]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#17&quot;&gt;13&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
: Adam Langley has great Intermediate-level blogposts about the Lucky13 attack and analyzing code for constant-time execution.
These aren&#x27;t for the weak of heart, but are much more accessible than a lot of academic articles on similar topics.&lt;&#x2F;p&gt;
&lt;p&gt;CryptoCoding.net Coding Rules&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#18&quot;&gt;14&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
: This wiki outlines some common pitfalls when writing constant-time code and how to avoid it.
It assumes you&#x27;re writing C code, but many of the principles carry to more exotic languages.&lt;&#x2F;p&gt;
&lt;p&gt;Constant Time Testing Papers[^19]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#20&quot;&gt;15&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
: These academic papers outline tools developed for studying how constant-time a program is and analyzes various programs with these tools.
They&#x27;re a great (surprisingly recent) survey of this topic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errata&quot;&gt;Errata&lt;&#x2F;h2&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;CTLibs&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;crypto&#x2F;subtle&#x2F;&quot;&gt;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;crypto&#x2F;subtle&#x2F;&lt;&#x2F;a&gt; -
&lt;a href=&quot;https:&#x2F;&#x2F;cryptography.io&#x2F;en&#x2F;latest&#x2F;hazmat&#x2F;primitives&#x2F;constant-time&#x2F;&quot;&gt;https:&#x2F;&#x2F;cryptography.io&#x2F;en&#x2F;latest&#x2F;hazmat&#x2F;primitives&#x2F;constant-time&#x2F;&lt;&#x2F;a&gt; -
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;isislovecruft&#x2F;subtle&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;isislovecruft&#x2F;subtle&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Remote Timing Attacks are Pratical; David Brumley, Dan Boneh;
&lt;a href=&quot;http:&#x2F;&#x2F;crypto.stanford.edu&#x2F;~dabo&#x2F;pubs&#x2F;papers&#x2F;ssl-timing.pdf&quot;&gt;http:&#x2F;&#x2F;crypto.stanford.edu&#x2F;~dabo&#x2F;pubs&#x2F;papers&#x2F;ssl-timing.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Remote Timing Attacks are Pratical; David Brumley, Dan Boneh;
&lt;a href=&quot;http:&#x2F;&#x2F;crypto.stanford.edu&#x2F;~dabo&#x2F;pubs&#x2F;papers&#x2F;ssl-timing.pdf&quot;&gt;http:&#x2F;&#x2F;crypto.stanford.edu&#x2F;~dabo&#x2F;pubs&#x2F;papers&#x2F;ssl-timing.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Chosen Plaintext: A beginner&#x27;s guide to contant-time cryptography;
&lt;a href=&quot;https:&#x2F;&#x2F;www.chosenplaintext.ca&#x2F;articles&#x2F;beginners-guide-constant-time-cryptography.html&quot;&gt;https:&#x2F;&#x2F;www.chosenplaintext.ca&#x2F;articles&#x2F;beginners-guide-constant-time-cryptography.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;As Sonic the Hedgehog always says, Gotta Go Fast!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;BearSSL: Constant Time Multiplication
&lt;a href=&quot;https:&#x2F;&#x2F;bearssl.org&#x2F;ctmul.html&quot;&gt;https:&#x2F;&#x2F;bearssl.org&#x2F;ctmul.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;Cryptography Coding Standards: Coding rules;
&lt;a href=&quot;https:&#x2F;&#x2F;cryptocoding.net&#x2F;index.php&#x2F;Coding_rules&quot;&gt;https:&#x2F;&#x2F;cryptocoding.net&#x2F;index.php&#x2F;Coding_rules&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;7&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Chosen Plaintext: A beginner&#x27;s guide to contant-time cryptography;
&lt;a href=&quot;https:&#x2F;&#x2F;www.chosenplaintext.ca&#x2F;articles&#x2F;beginners-guide-constant-time-cryptography.html&quot;&gt;https:&#x2F;&#x2F;www.chosenplaintext.ca&#x2F;articles&#x2F;beginners-guide-constant-time-cryptography.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;8&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;16&lt;&#x2F;sup&gt;
&lt;p&gt;Dude, is my code constant-time? Oscar Reparaz, josep Balasch,
Ingrid Vebauwhede; &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;1123.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;1123.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;9&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;17&lt;&#x2F;sup&gt;
&lt;p&gt;Veryfying Constnat-Time Implementations, via Usenix;
&lt;a href=&quot;http:&#x2F;&#x2F;haslab.uminho.pt&#x2F;jba&#x2F;files&#x2F;16usenix.pdf&quot;&gt;http:&#x2F;&#x2F;haslab.uminho.pt&#x2F;jba&#x2F;files&#x2F;16usenix.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;10&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;Lucky Thirteen attack on TLS CBC Adam langley via ImperialViolet;
&lt;a href=&quot;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2013&#x2F;02&#x2F;04&#x2F;luckythirteen.html&quot;&gt;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2013&#x2F;02&#x2F;04&#x2F;luckythirteen.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;11&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;18&lt;&#x2F;sup&gt;
&lt;p&gt;BearSSL: Constant Time Multiplication
&lt;a href=&quot;https:&#x2F;&#x2F;bearssl.org&#x2F;ctmul.html&quot;&gt;https:&#x2F;&#x2F;bearssl.org&#x2F;ctmul.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;12&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;BearSSL: Why Consant-Time Crypto?
&lt;a href=&quot;https:&#x2F;&#x2F;bearssl.org&#x2F;constanttime.html&quot;&gt;https:&#x2F;&#x2F;bearssl.org&#x2F;constanttime.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;13&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;Remote Timing Attacks are Pratical; David Brumley, Dan Boneh;
&lt;a href=&quot;http:&#x2F;&#x2F;crypto.stanford.edu&#x2F;~dabo&#x2F;pubs&#x2F;papers&#x2F;ssl-timing.pdf&quot;&gt;http:&#x2F;&#x2F;crypto.stanford.edu&#x2F;~dabo&#x2F;pubs&#x2F;papers&#x2F;ssl-timing.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;14&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;19&lt;&#x2F;sup&gt;
&lt;p&gt;Chosen Plaintext: A beginner&#x27;s guide to contant-time
cryptography;
&lt;a href=&quot;https:&#x2F;&#x2F;www.chosenplaintext.ca&#x2F;articles&#x2F;beginners-guide-constant-time-cryptography.html&quot;&gt;https:&#x2F;&#x2F;www.chosenplaintext.ca&#x2F;articles&#x2F;beginners-guide-constant-time-cryptography.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;15&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;12&lt;&#x2F;sup&gt;
&lt;p&gt;A Lesson In Timing Attacks (or, Don&#x27;t use
&lt;code&gt;MessageDigest.isEquals&lt;&#x2F;code&gt;); Coda Hale;
&lt;a href=&quot;https:&#x2F;&#x2F;codahale.com&#x2F;a-lesson-in-timing-attacks&#x2F;&quot;&gt;https:&#x2F;&#x2F;codahale.com&#x2F;a-lesson-in-timing-attacks&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;16&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;20&lt;&#x2F;sup&gt;
&lt;p&gt;Checking that functions are constant-time with Valgrind; Adam
langley via ImperialViolet;
&lt;a href=&quot;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2010&#x2F;04&#x2F;01&#x2F;ctgrind.html&quot;&gt;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2010&#x2F;04&#x2F;01&#x2F;ctgrind.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;17&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;13&lt;&#x2F;sup&gt;
&lt;p&gt;Lucky Thirteen attack on TLS CBC Adam langley via ImperialViolet;
&lt;a href=&quot;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2013&#x2F;02&#x2F;04&#x2F;luckythirteen.html&quot;&gt;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2013&#x2F;02&#x2F;04&#x2F;luckythirteen.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;18&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;14&lt;&#x2F;sup&gt;
&lt;p&gt;Cryptography Coding Standards: Coding rules;
&lt;a href=&quot;https:&#x2F;&#x2F;cryptocoding.net&#x2F;index.php&#x2F;Coding_rules&quot;&gt;https:&#x2F;&#x2F;cryptocoding.net&#x2F;index.php&#x2F;Coding_rules&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;19&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;21&lt;&#x2F;sup&gt;
&lt;p&gt;Veryfying Constnat-Time Implementations, via Usenix;
&lt;a href=&quot;http:&#x2F;&#x2F;haslab.uminho.pt&#x2F;jba&#x2F;files&#x2F;16usenix.pdf&quot;&gt;http:&#x2F;&#x2F;haslab.uminho.pt&#x2F;jba&#x2F;files&#x2F;16usenix.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;20&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;15&lt;&#x2F;sup&gt;
&lt;p&gt;Dude, is my code constant-time? Oscar Reparaz, josep Balasch,
Ingrid Vebauwhede; &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;1123.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;1123.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Memory Hard Functions</title>
        <published>2017-10-17T00:00:00+00:00</published>
        <updated>2017-10-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/memory-hard-functions/"/>
        <id>https://elijah.run/blog/memory-hard-functions/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/memory-hard-functions/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This is a part of a series of blog posts I wrote for an Independent
Study on cryptography at Oregon State University. To read all of the
posts, check out the &#x27;Independent Crypto&#x27; tag.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;h2 id=&quot;problem-storing-passwords-is-hard&quot;&gt;Problem: storing passwords is hard&lt;&#x2F;h2&gt;
&lt;p&gt;You&#x27;re a system administrator and -- oh no! A hacker stole your database!&lt;&#x2F;p&gt;
&lt;p&gt;Well, not yet... but they &lt;em&gt;could&lt;&#x2F;em&gt;.
Once you get popular enough it&#x27;s bound to happen.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Can you make sure your users data is safe &lt;strong&gt;when&lt;&#x2F;strong&gt; that happens?&lt;&#x2F;p&gt;
&lt;p&gt;When you store passwords in a database you never store them in plain text.
Instead, you store a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hash_function&quot;&gt;hash&lt;&#x2F;a&gt; of that password.
For example:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Password: 12345678
&lt;&#x2F;span&gt;&lt;span&gt;sha256sum (hash): 2634c3097f98e36865f0c572009c4ffd73316bc8b88ccfe8d196af35f46e2394
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The hash is generated when the user tries to login.
The &lt;em&gt;hash&lt;&#x2F;em&gt; of the password the user sends at login is compared against the corresponding password hash for that user.
If it matches that means the user sent the right password and so they are authenticated.&lt;&#x2F;p&gt;
&lt;p&gt;What happens if the hacker pre-computes a bunch of popular passwords?
This might sound crazy, but there are lots of people that re-use passwords, like &lt;code&gt;123456&lt;&#x2F;code&gt;.
The hacker can pre-compute the hash for the 1,000,000 most popular passwords and more or less reverse-search for any user&#x27;s password once they have a database dump.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution-1-add-salt&quot;&gt;Solution 1: add salt&lt;&#x2F;h2&gt;
&lt;p&gt;Our first naive solution to solve this problem is to make the adversary&#x27;s life harder by adding &lt;em&gt;salt&lt;&#x2F;em&gt; to our passwords.
This is a piece of known information which is added to the password so adversaries can&#x27;t pre-compute a hash-table, they have to compute this after they have the database and figure out the salt.
For example:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Password: 12345678
&lt;&#x2F;span&gt;&lt;span&gt;Salt: cryptoHeckYeah!
&lt;&#x2F;span&gt;&lt;span&gt;New Password: 12345678cryptoHeckYeah!
&lt;&#x2F;span&gt;&lt;span&gt;sha256sum: 6e8a7780df48a0b687e9e272e8d082f5f4c0c3a8c43b63461c3f62618b111e9d
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately we live in 2017 and Graphics processors and &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application-specific_integrated_circuit&quot;&gt;ASICs&lt;&#x2F;a&gt; are cheap and can compute sha256sums &lt;strong&gt;super fast&lt;&#x2F;strong&gt; for &lt;strong&gt;really cheap&lt;&#x2F;strong&gt;.
This means that it might be more of a pain, but the adversary can still crack a password with relative ease and efficiency because they&#x27;ve got a computer &lt;em&gt;designed&lt;&#x2F;em&gt; to generate lots of hashes.
Curses.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution-2-h-h-h-x&quot;&gt;Solution 2: H(H(..H(x)..)&lt;&#x2F;h2&gt;
&lt;p&gt;Computing a single sha256sum is easy, but what if the hacker had to compute like... 1000 sha256sums for each password!
That sounds pretty hard... right?
If we compute the hash of the hash of the hash (etc) it would take like... 1000x longer to compute each user&#x27;s password.
Something like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;p = &amp;#39;12345678cryptoHeckYeah!&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;for x in 1..1000
&lt;&#x2F;span&gt;&lt;span&gt;  p = sha256sum( p )
&lt;&#x2F;span&gt;&lt;span&gt;end
&lt;&#x2F;span&gt;&lt;span&gt;return p
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Result: 47c76630def739ede9c05fd974065b1200d4712aa2421eefb1f6b241a1ca6bea
&lt;&#x2F;span&gt;&lt;span&gt;Time: 0m1.547s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Unfortunately this hurts more than it helps.&lt;&#x2F;p&gt;
&lt;p&gt;In bash on non-specialized hardware, this took about 1.6 seconds.
On specialized hardware, written in a systems programming language, and implemented in parallel it&#x27;d be much less costly for an adversary to crack passwords hashed this way.&lt;&#x2F;p&gt;
&lt;p&gt;Worst of all, this is &lt;em&gt;easier for an adversary to compute than it is for the the &quot;good guys&quot;&lt;&#x2F;em&gt; because the non-malicious actor is using generalized hardware and the adversary is using specialized hardware to compute the hashes.
It&#x27;s like trying to beat a Roadster in a drag race when you&#x27;re behind the wheel of a Minivan; the Minivan (&quot;good guys&quot;) &lt;em&gt;can&#x27;t win&lt;&#x2F;em&gt; because they weren&#x27;t built for drag races.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution-3-memory-hard-functions&quot;&gt;Solution 3: Memory Hard Functions&lt;&#x2F;h2&gt;
&lt;p&gt;The big problem we have is that CPUs can be specialized to crack passwords &lt;em&gt;very quickly&lt;&#x2F;em&gt;.
No matter how fast your AWS EC2 instance is, or even that top of the line IBM server you just bought, it will &lt;em&gt;never&lt;&#x2F;em&gt; be faster than a cheap custom designed ASIC.
At around 3000$&#x2F;box it won&#x27;t break the adversary&#x27;s bank to break into yours.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;While there specialized hash-cracking CPUs &lt;strong&gt;do&lt;&#x2F;strong&gt; exist, specialized hash-cracking &lt;em&gt;memory&lt;&#x2F;em&gt; does &lt;strong&gt;not&lt;&#x2F;strong&gt; exist.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
If we were to create an algorithm which depends on lots of memory, instead of lots of CPU cycles, we could &quot;level the playing field&quot;.
This should help stop adversaries from reversing passwords as fast as they currently can.&lt;&#x2F;p&gt;
&lt;p&gt;This theoretical hash-function is called a Memory Hard Function (MHF).
These are difficult to perform unless you have a certain threshold of memory.
As a result non-malicious actors can perform a hash in M seconds and it will take a malicious actor &lt;em&gt;at least&lt;&#x2F;em&gt; M seconds to perform the same hash.&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;TLDR: We want a hash function that takes as long for an adversary to
compute as it does for the &quot;good guys&quot; to compute. Since nobody has
specialized hash-cracking RAM we should be able to create a hash
function which is memory-intensive and fits our criteria. If we have a
function that fits this we will have got a &lt;em&gt;Memory hard Function&lt;&#x2F;em&gt; (MHF).&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;h2 id=&quot;scrypt-a-wild-mhf&quot;&gt;scrypt: a wild MHF&lt;&#x2F;h2&gt;
&lt;p&gt;scrpyt is a key derivation function &lt;a href=&quot;http:&#x2F;&#x2F;www.tarsnap.com&#x2F;scrypt.html&quot;&gt;developed for the Tarsnap project&lt;&#x2F;a&gt;.
It was designed explicitly to solve this problem and has some pretty impressive results.
Some especially impressive results include:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;scrypt is about 2&lt;sup&gt;5&lt;&#x2F;sup&gt; times more expensive to attack for logins than bcrypt.&lt;&#x2F;li&gt;
&lt;li&gt;scrypt is about 2&lt;sup&gt;15&lt;&#x2F;sup&gt; times more espensive to attack for logins than MD5 CRYPT.&lt;&#x2F;li&gt;
&lt;li&gt;scrypt is about 2&lt;sup&gt;37&lt;&#x2F;sup&gt; times more expensive to attack for file encryption than MD5.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;scrypt also happens to be a MHF.
Yay we found one!&lt;&#x2F;p&gt;
&lt;p&gt;So... how does it work?&lt;&#x2F;p&gt;
&lt;p&gt;Given a hash function H, an input B, and an integer N, compute:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;V&lt;sub&gt;i&lt;&#x2F;sub&gt; = H&lt;sup&gt;i&lt;&#x2F;sup&gt;(B), given 0 ≤ i &amp;lt; N,&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;and&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;X = H&lt;sup&gt;N&lt;&#x2F;sup&gt;(B)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;then iterate&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;j &amp;lt;- Integrify(X) mod N&lt;&#x2F;li&gt;
&lt;li&gt;X &amp;lt;- H(X ⊕ V&lt;sub&gt;j&lt;&#x2F;sub&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;N times; and output X&lt;&#x2F;p&gt;
&lt;p&gt;The function Integrify can be any bijection&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; from {0,1}&lt;sup&gt;k&lt;&#x2F;sup&gt;
to {0...2&lt;sup&gt;k&lt;&#x2F;sup&gt; - 1}.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Breaking that down a bit:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The function is given a different hash function (H), an input to compute the hash of (B), and a modulus (N).&lt;&#x2F;li&gt;
&lt;li&gt;N hashes are generated with variations of H and the input B called V&lt;sub&gt;0..N&lt;&#x2F;sub&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;X is initialized with a hash value and a loop begins:
&lt;ol&gt;
&lt;li&gt;j is set to a psuedo-random integer mod N.&lt;&#x2F;li&gt;
&lt;li&gt;X is set to the hash of the existing X value xor&#x27;d with one of the V values.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Loop N times and output the final X.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;One of the biggest gripes with scrypt is that it has a very predictable runtime.
This means that the running of the function is predictable based on the user&#x27;s input and so can be victim to a cache-timing side-channel attack.
We won&#x27;t be able to get into what this attack means, but basically you can say &quot;scrypt is good, but not perfect&quot;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;data-independent-mhfs-imhfs&quot;&gt;Data-independent MHFs (iMHFs)&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;DAG.gif&quot; alt=&quot;A directed acyclic graph map.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;iMHFs are supposed to solve the problem that scrypt has (side-channel attacks) by have unpredictable runtimes which still result in the same output.&lt;&#x2F;p&gt;
&lt;p&gt;iMHFs can be thought of as Directed Acyclic Graphs (DAGs) which are traversed during runtime.&lt;&#x2F;p&gt;
&lt;p&gt;Some specifics:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The function depends on a random oracle H: {0,1}&lt;sup&gt;2k&lt;&#x2F;sup&gt; -&amp;gt; {0,1}&lt;sup&gt;k&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The function provides a Directed Acyclic Graph Directed Acyclic Graph (DAG) G used to encode data-dependencies&lt;&#x2F;li&gt;
&lt;li&gt;The initial input is a password and a salt.&lt;&#x2F;li&gt;
&lt;li&gt;Each other node is labeled with the hash of it&#x27;s parent nodes.&lt;&#x2F;li&gt;
&lt;li&gt;The output is the hash of the value of the last node.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As mentioned before, a very nice feature of iMHFs is that their memory usage pattern does not depend on the user&#x27;s input (password) and so is not vulnerable to side-channel attacks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pebbling-a-directed-acyclic-graph-dag&quot;&gt;Pebbling a Directed Acyclic Graph (DAG)&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;dag-animated.gif&quot; alt=&quot;A directed acyclic graph traversal.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can think of the process of computing the output of an iMHF as pebbling a graph where:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Computing the value of a node is to pebble it.&lt;&#x2F;li&gt;
&lt;li&gt;There are rules about which nodes can be pebbled at any time.&lt;&#x2F;li&gt;
&lt;li&gt;When a pebble is removed from a node it is freed from memory.&lt;&#x2F;li&gt;
&lt;li&gt;Our goal is to pebble the last node.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Rules:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;We can only place a pebble on a node if we have pebbles on all of it&#x27;s parents nodes.&lt;&#x2F;li&gt;
&lt;li&gt;Our goal is to get to the sink node (exit node).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The naive pebbling algorithm, the one the &#x27;good guy&#x27; user would utilize is as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Only one pebble can be placed per time-step.&lt;&#x2F;li&gt;
&lt;li&gt;The graph is pebbled in in topological order.&lt;&#x2F;li&gt;
&lt;li&gt;Pebbles (calculated nodes) are never discarded until the end of the function.&lt;&#x2F;li&gt;
&lt;li&gt;Expected cost: scales with n&lt;sup&gt;2&lt;&#x2F;sup&gt; where n is the number of nodes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This does take up considerable resources, but it isn&#x27;t prohibitive for users on commodity hardware.
This means it won&#x27;t take &lt;em&gt;too long&lt;&#x2F;em&gt; to get your account authenticated.
More importantly, it will take about as long for the bad guys to calculate a token as it took you to calculate a token, as opposed to a small fraction it would take if this was a &quot;normal&quot; hash function.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attacks-on-imhfs&quot;&gt;Attacks on iMHFs&lt;&#x2F;h2&gt;
&lt;p&gt;An attack is defined as when cost of calculating a hash from an iMHF is lower than via the nieve approach.&lt;&#x2F;p&gt;
&lt;p&gt;The general idea of an iMHF attack is that it has two phases: light phase and balloon phase.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;light-phase&quot;&gt;Light Phase&lt;&#x2F;h3&gt;
&lt;p&gt;In the light phase the algorithm races through the DAG discarding as many pebbles as possible, essentially performing a breadth first search for the end of the graph, computing nodes in parallel when possible.
Once a node is computed and it isn&#x27;t immediately needed it is discarded.&lt;&#x2F;p&gt;
&lt;p&gt;If the DAG were a straight line from beginning to end this would be fairly memory efficient.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;balloon-phase&quot;&gt;Balloon Phase&lt;&#x2F;h3&gt;
&lt;p&gt;In the balloon phase the algorithm has &#x27;hit a wall&#x27; and back-computes the nodes it needs to compute the next node whose parent&#x27;s have already been discarded.
This causes a slow-down.&lt;&#x2F;p&gt;
&lt;p&gt;An attack described like this has the following complexity:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;E&lt;sub&gt;R&lt;&#x2F;sub&gt;(A) = O(en + √(n&lt;sup&gt;3&lt;&#x2F;sup&gt;d))&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;For small values of e and d this results in an attack as:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;E&lt;sub&gt;R&lt;&#x2F;sub&gt;(A) = O(n&lt;sup&gt;2&lt;&#x2F;sup&gt;) for e,d = O(n)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Preventing against this type of attack is where much of the research into iMHF&#x27;s is focused.
An ideal iMHF DAG minimize the disparity between the attackers compute time and the &quot;good guy&#x27;s&quot; compute time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This has been a rough overview of Memory Hard functions, how they work, and how variations of MHFs differ.&lt;&#x2F;p&gt;
&lt;p&gt;MHFs are functions which remove the advantage that adversaries have to crack passwords by depending heavily on memory.
This reduces the adversary&#x27;s advantage if they have an ASIC or GPU processor(s) to brute-force a password crack and ought to make it very difficult (ideally &lt;em&gt;impractical&lt;&#x2F;em&gt;) for adversaries to crack a password hashed with an MHF.&lt;&#x2F;p&gt;
&lt;p&gt;Some existing MHFs, like scrypt, are vulnerable to side-channel attacks so iMHFs have been theorized which do not have a predictable runtime and so are not vulnerable to side-channel attacks.
No iMHFs exist yet, however many functions have been developed with get &lt;em&gt;close&lt;&#x2F;em&gt; and offer many of the benefits of iMFHs.
Some of these include Argon2i, Catena, and Balloon hashing, which we did not cover in this post.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;annotated-bibliography&quot;&gt;Annotated Bibliography&lt;&#x2F;h2&gt;
&lt;p&gt;Conference Presentations by Jeremiah Blocki[^5][^6]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#7&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; The video presentations online by Jeremiah were a very important resource for getting a grasp on what MHFs are, and more specifically what iMHFS and how they worked.
The three videos cited in this post cover largely the same content and present the material, including the problem, naive solution, MHF solution, iMFH solution, and possible attacks against iMHFs in about 30 minutes.
I like to think I&#x27;m pretty good at public speaking, but this material was very complicated and presented in a very digestible format.&lt;&#x2F;p&gt;
&lt;p&gt;I cannot stress enough how useful these videos were.
I learned an incredible amount from these videos and referenced them for the majority of this content.&lt;&#x2F;p&gt;
&lt;p&gt;Strict Memory Hard Hashing Functions&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#8&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This paper was very short and presented some essential knowledge to discuss the differences between MHFs and iMHFs.
I didn&#x27;t directly use or reference this content, however it did present an easily understandable academic definition and comparison of iMHF compared to MHFs.&lt;&#x2F;p&gt;
&lt;p&gt;Practical Graphs for Optimal Side-Channel Resistant Memory-Hard Functions&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#9&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This paper was used in the writing of this post, however it was very long and dense, so it was never directly cited.&lt;&#x2F;p&gt;
&lt;p&gt;scrypt: A new key derivation function&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#10&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This was the soul reference for the scrypt section of this post.
There is an academic paper published too, but the slides were simple and presented all of the same knowledge (I think) sans any proofs.&lt;&#x2F;p&gt;
&lt;p&gt;If I feel an existential hole in my heart I might read the proofs, but in the interest of time I chose not to right now.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errata&quot;&gt;Errata&lt;&#x2F;h2&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;haveibeenpwned.com&#x2F;PwnedWebsites&quot;&gt;https:&#x2F;&#x2F;haveibeenpwned.com&#x2F;PwnedWebsites&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Antminer &quot;Bitcoin Miner&quot; &lt;a href=&quot;http:&#x2F;&#x2F;a.co&#x2F;2E20HW8&quot;&gt;http:&#x2F;&#x2F;a.co&#x2F;2E20HW8&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Yet.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;Bijection: A function which creates a 1-to-1 relationship between inputs and outputs.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;Efficiently Computing Data Independent Memory Hard Functions (Video) Joël Alwen and Jeremiah Blocki, Crypto 2016, September 26, 2016, &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;ujpvPtn_N5Y&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;ujpvPtn_N5Y&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;Towards a Theory of Data-Independent Memory Hard Functions (Video), Jeremiah Blocki with Joel Alwen, Krzysztof Pietrzak 2017, Real World Crypto conference, February 1, 2017, &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;YtfVLzUkwME&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;YtfVLzUkwME&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;7&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;Memory Hard Functions and Password Hashings (Video), CERIAS Symposium 2017 - TechTalk, Jeremiah M. Blocki - Assistant Professor, Computer Science - Purdue University, May 1, 2017, &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;9yX4v89m5oo&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;9yX4v89m5oo&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;8&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;Strict Memory Hard Hashing Functions, Sergio Demian Lerner, (Preliminary v0.3, 01-19-14), &lt;a href=&quot;http:&#x2F;&#x2F;www.hashcash.org&#x2F;papers&#x2F;memohash.pdf&quot;&gt;http:&#x2F;&#x2F;www.hashcash.org&#x2F;papers&#x2F;memohash.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;9&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Practical Graphs for Optimal Side-Channel Resistant Memory-Hard Functions Joel Alwen, Jeremiah Blocki, Ben Harsha IACR Cryptography ePrint Archive, 2017, &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2017&#x2F;443.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2017&#x2F;443.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;10&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;scrypt: A new key derivation function (variable subtitles) Colin Percival, May 9, 2009, &lt;a href=&quot;http:&#x2F;&#x2F;www.tarsnap.com&#x2F;scrypt&#x2F;scrypt-slides.pdf&quot;&gt;http:&#x2F;&#x2F;www.tarsnap.com&#x2F;scrypt&#x2F;scrypt-slides.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Garbled Circuits</title>
        <published>2017-10-10T00:00:00+00:00</published>
        <updated>2017-10-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/garbled-circuits/"/>
        <id>https://elijah.run/blog/garbled-circuits/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/garbled-circuits/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This is a part of a series of blog posts I wrote for an Independent Study on cryptography at Oregon State University.
To read all of the posts, check out the &#x27;Independent Crypto&#x27; tag.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Let&#x27;s imagine you are a billionaire.
You want to know if you have more money than your billionaire friend Bob, but for some reason it&#x27;s &lt;em&gt;very&lt;&#x2F;em&gt; faux pas to let anybody know how much money you have, even your good friend Bob.&lt;&#x2F;p&gt;
&lt;p&gt;But you&#x27;re a billionaire!
You&#x27;re not used to the phrase &quot;that isn&#x27;t possible&quot;.
In your frustration you try to figure out if you can use some of your billions to find a solution.&lt;&#x2F;p&gt;
&lt;p&gt;The first solution you come up with is Trusty Tina.
You tell Tina how much you make, Bob tells Tina how much he makes, and then Tina tells both of you who makes more.&lt;&#x2F;p&gt;
&lt;p&gt;The only problem is that Tina isn&#x27;t &lt;em&gt;that&lt;&#x2F;em&gt; trustworthy, her parent&#x27;s just named her that.
Like... you wouldn&#x27;t trust her with your life or anything.
You could pay her to keep your assets secret but Bob might pay her a bit more reveal your number to him.
Tina reminds you of this so you have to pay her &lt;em&gt;more&lt;&#x2F;em&gt; to keep the secret, and eventually you have an arms-race type situation at hand.
With your cunning accountant skills you can already tell that Tina might be more trouble than she&#x27;s worth.&lt;&#x2F;p&gt;
&lt;p&gt;If you won&#x27;t tell Bob directly, and you can&#x27;t depend on Manipulative Tina, is there &lt;em&gt;any&lt;&#x2F;em&gt; way to determine out who has more money?&lt;&#x2F;p&gt;
&lt;p&gt;Yes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-party-secure-function-evaluation&quot;&gt;2-Party Secure Function Evaluation&lt;&#x2F;h2&gt;
&lt;p&gt;The problem above is the Millionaires problem&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and it is solved by the use of 2-party secure function evaluation (SFE).
The general idea&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; is that you have a function &lt;code&gt;f&lt;&#x2F;code&gt; which takes as input &lt;code&gt;x&lt;&#x2F;code&gt; and &lt;code&gt;y&lt;&#x2F;code&gt;.
This function is garbled by one of the two parties into &lt;code&gt;f&#x27;&lt;&#x2F;code&gt; and the inputs are garbled into &lt;code&gt;x&#x27;&lt;&#x2F;code&gt; and &lt;code&gt;y&#x27;&lt;&#x2F;code&gt; by each of the parties.
&lt;code&gt;f&#x27;(x&#x27;, y&#x27;) == f(x,y)&lt;&#x2F;code&gt; but does not leak any of the inputs, because &lt;code&gt;x&lt;&#x2F;code&gt; and &lt;code&gt;y&lt;&#x2F;code&gt; were obfuscated.&lt;&#x2F;p&gt;
&lt;p&gt;In other words...&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice and Bob agree on a function (i.e., circuit) &lt;code&gt;f(a,b)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Alice garbles the function (&lt;em&gt;cough&lt;&#x2F;em&gt; circuit) &lt;code&gt;f&lt;&#x2F;code&gt; and her input &lt;code&gt;a&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Alice sends &lt;code&gt;f&#x27;&lt;&#x2F;code&gt; and &lt;code&gt;a&#x27;&lt;&#x2F;code&gt; to Bob.&lt;&#x2F;li&gt;
&lt;li&gt;Bob gets his input &lt;code&gt;b&lt;&#x2F;code&gt; garbled into &lt;code&gt;b&#x27;&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Bob evaluates &lt;code&gt;f&#x27;(a&#x27;, b&#x27;)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;This reveals the result of &lt;code&gt;f(a,b)&lt;&#x2F;code&gt; to Bob, but does not reveal
Alice&#x27;s input.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;The first half of this post focuses on honest garbled circuit uses,
meaning both parties are acting honestly (and don&#x27;t pull any fast-ones).&lt;&#x2F;p&gt;
&lt;p&gt;The latter portion focuses on problems with that &#x27;vanilla&#x27; garbled
circuit implementation and potential solutions.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;h2 id=&quot;garbling-a-gate&quot;&gt;Garbling a gate&lt;&#x2F;h2&gt;
&lt;p&gt;How does Alice actually... &#x27;garble&#x27; a circuit?
It sounds kinda dirty.&lt;&#x2F;p&gt;
&lt;p&gt;Each gate (OR, AND, XOR, etc) has two inputs.
Stick with me.
Each input is encrypted.
Keeping up?
So you need a &lt;em&gt;key&lt;&#x2F;em&gt; to use &lt;em&gt;each gate&lt;&#x2F;em&gt;.
It gets better.
But if you have the keys, you don&#x27;t know which key corresponds with a &lt;code&gt;1&lt;&#x2F;code&gt; or a &lt;code&gt;0&lt;&#x2F;code&gt; so you can compute a function without knowing the actual values you put in.
Whoa.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s use the OR gate as an example.&lt;&#x2F;p&gt;
&lt;p&gt;Remember truth-tables for OR? Here&#x27;s a reminder:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;OR&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;0&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;1&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;0&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;1&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;This table is going to be important for Alice&#x27;s part of this dance.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;alice-s-circuit-input&quot;&gt;Alice&#x27;s circuit &amp;amp; input&lt;&#x2F;h3&gt;
&lt;p&gt;Alice definitely does the heavy lifting in this transaction.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice generates 4 keys &lt;code&gt;Kx0&lt;&#x2F;code&gt;, &lt;code&gt;Kx1&lt;&#x2F;code&gt;, &lt;code&gt;Ky0&lt;&#x2F;code&gt;, and &lt;code&gt;Ky1&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Alice creates four variables corresponding with the four values in the OR table:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;OR&lt;&#x2F;th&gt;&lt;th&gt;0&lt;&#x2F;th&gt;&lt;th&gt;1&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;0&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;B00&lt;&#x2F;code&gt; = 0&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;B01&lt;&#x2F;code&gt; = 1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;1&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;B10&lt;&#x2F;code&gt; = 1&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;B11&lt;&#x2F;code&gt; = 1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Each box is encrypted with the two keys:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;OR&lt;&#x2F;th&gt;&lt;th&gt;0&lt;&#x2F;th&gt;&lt;th&gt;1&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;0&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;`E(Kx0&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;1&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;`E(Kx1&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Alice sends these ciphertexts (unordered) to Bob.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;bob-s-input&quot;&gt;Bob&#x27;s input&lt;&#x2F;h3&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;Bob gets Alice&#x27;s input, key &lt;code&gt;KxA&lt;&#x2F;code&gt;, from Alice.&lt;&#x2F;li&gt;
&lt;li&gt;Bob uses oblivious transfer&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; to get his input &lt;code&gt;KyB&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;With these two keys Bob is able to process the circuit (an OR gate).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Bob has enough information to get one of the four possible outputs of the circuit, but doesn&#x27;t know if Alice&#x27;s input is a 1 or a 0.&lt;&#x2F;p&gt;
&lt;p&gt;Importantly, while Bob can share the output of the circuit, he should &lt;strong&gt;not&lt;&#x2F;strong&gt; share his input. That would make using OT (step 6) obtuse.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;extending-the-garbled-gate&quot;&gt;Extending the garbled gate&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;garbled-circuit.jpg&quot; alt=&quot;Garbled circuit example diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;The UTF-8 Padlock symbol doesn&#x27;t render on my browser because I seem to
have gone back in the time to the late 90s. Being stuck in the past, we
have to comprmise. The ⛨ symbol is meant to represent a lock and the ⚿
represents a key.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Multiple gates can be connected together to build more complicated
circuits. One important difference is that while each intermediate
circuit still has four cipher-texts, for the four outcomes of a
truth-table, those decrypt to a &lt;em&gt;key&lt;&#x2F;em&gt; and not a 1 or 0. The only gates
which decrypt to a plain-text of 0 or 1 are output gates, not the
intermediate gates.&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;&lt;em&gt;PSST&lt;&#x2F;em&gt; Check out the end of this post for a &lt;strong&gt;GAME&lt;&#x2F;strong&gt;!&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;h2 id=&quot;problems-with-garbled-circuits&quot;&gt;Problems with garbled circuits&lt;&#x2F;h2&gt;
&lt;p&gt;There are a few important flaws in the &lt;em&gt;security&lt;&#x2F;em&gt; of garbled circuits as
they have been described. The first is that although Alice and Bob agree
on a circuit to garble there is no guarantee that the circuit one is
evaluating (if you&#x27;re Bob) is the circuit you agreed upon.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice and Bob &#x27;agree&#x27; on a function &lt;code&gt;f(a,b)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Alice creates her own function &lt;code&gt;g(a,b)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Alice garbles &lt;code&gt;g&lt;&#x2F;code&gt; and her input &lt;code&gt;a&lt;&#x2F;code&gt; and sends it to Bob as &lt;code&gt;f&#x27;&lt;&#x2F;code&gt; and &lt;code&gt;a&#x27;&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Bob evaluates &lt;code&gt;g&#x27;(a&#x27;,b&#x27;)&lt;&#x2F;code&gt; and reveals the output to Alice.
Alice now knows something other than than Bob agreed to.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;improvements-on-garbled-circuit-security&quot;&gt;Improvements on garbled circuit security&lt;&#x2F;h2&gt;
&lt;p&gt;To prevent the above adversarial attack we do something called &quot;Cut-and-Choose&quot;.
This is when Bob checks Alice&#x27;s work to make sure she&#x27;s not cheating.&lt;&#x2F;p&gt;
&lt;p&gt;Remember that Alice and Bob agreed on a given circuit.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice generates M garbled circuits for the agreed upon function where M &amp;gt; 1.&lt;&#x2F;li&gt;
&lt;li&gt;All secrets for a randomly chosen N circuits are revealed where 1 ≤ N &amp;lt; M, the circuits are &quot;opened&quot;.&lt;&#x2F;li&gt;
&lt;li&gt;Bob selects one of the remaining M-N circuits to evaluate as outlined earlier.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This ensures that Alice is not nefarious to some statistical certainty.
She had control over how the circuits were garbled but she does not have control over which are revealed or evaluated.
If she made one (or two or three...) nefarious circuits that bad behavior is &lt;em&gt;probably&lt;&#x2F;em&gt; revealed in step 2, if all the checked circuits are good Alice is &lt;em&gt;probably&lt;&#x2F;em&gt; being honest.&lt;&#x2F;p&gt;
&lt;p&gt;This doesn&#x27;t break garbled circuits for the following reasons:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;While Alice reveals the secrets of the N circuits, she doesn&#x27;t reveal anything about her input.
We are only un-garbling the circuit not the inputs (revealing all possible inputs, not Alice&#x27;s).&lt;&#x2F;li&gt;
&lt;li&gt;We&#x27;re not un-garbling the M-N circuits which may be evaluated, so those are still secret.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As M grows and N approaches M this method gets more secure at the cost of computation cycles and bandwidth in transferring the garbled circuits.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-free-xor-optimization&quot;&gt;The &quot;Free XOR&quot; Optimization&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m definitely not a circuits person.
You can show me a circuit diagram and I&#x27;ll say
&quot;Yep, that&#x27;s a circuit. What&#x27;s it do?&quot;
I couldn&#x27;t even even identify which gate is which without Wikipedia.&lt;&#x2F;p&gt;
&lt;p&gt;I was told during my research for this post that XOR gates are very popular with garbled circuit design, and more broadly circuit design in
general.
This was shared to me in the form of a cryptic hint so I figured I&#x27;d investigate and share my findings here.&lt;&#x2F;p&gt;
&lt;p&gt;As it turns out the Wikipedia page notes that this XOR optimization exists and even cites the original paper published on the topic.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The jist of this optimization is that one can very efficiently garble an XOR gate such that the output of the gate is encoded as the XOR of the keys used to unlock the gate and some known global constant.
This is in contrast with the implementations discussed in the beginning where each gate had to be decrypted with two cipher-texts and revealed another key.&lt;&#x2F;p&gt;
&lt;p&gt;Basically using XOR, which is pretty fast, we can avoid generating four keys per gate and instead craft 1 key which is produced as the result of &#x27;unlocking&#x27; a gate.&lt;&#x2F;p&gt;
&lt;p&gt;Put a bit more formally:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a gate G with input wires A and B and output wire C and a random string R, the garbled gate is obtained by XORing the garbled gates inputs C&lt;sup&gt;1&lt;&#x2F;sup&gt; = C&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ R:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;C&lt;sup&gt;0&lt;&#x2F;sup&gt; = A&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ B&lt;sup&gt;0&lt;&#x2F;sup&gt; = (A&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ R ) ⊕ (B&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ R) = A&lt;sup&gt;1&lt;&#x2F;sup&gt; ⊕ B&lt;sup&gt;1&lt;&#x2F;sup&gt;
C&lt;sup&gt;1&lt;&#x2F;sup&gt; = C&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ R = A&lt;sup&gt;0&lt;&#x2F;sup&gt; (B&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ R) = A&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ B&lt;sup&gt;1&lt;&#x2F;sup&gt; = (A&lt;sup&gt;0&lt;&#x2F;sup&gt; ⊕ R) ⊕ B&lt;sup&gt;0&lt;&#x2F;sup&gt; = A&lt;sup&gt;1&lt;&#x2F;sup&gt; ⊕ B&lt;sup&gt;0&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;LETTER&lt;sup&gt;{0,1}&lt;&#x2F;sup&gt; is short-hand for the True or False output of the
given gate.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;This isn&#x27;t super intuitive, and honestly I just put those equations up there to prove that I read a paper about this.&lt;&#x2F;p&gt;
&lt;p&gt;The main takeaway is that &#x27;free XOR&#x27; saves us computation generating and processing cryptographic keys by simply performing the XOR operation.
This optimization is so powerful that using &lt;em&gt;mostly&lt;&#x2F;em&gt; XOR gates makes garbled circuits notably faster and more useful for secure computation.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;annotated-bibliography&quot;&gt;Annotated Bibliography&lt;&#x2F;h2&gt;
&lt;p&gt;Foundations of Garbled Circuits&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#6&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; This is by far the most thorough academic source I have.
If I had a better foundation in academic reading this might be the perfect paper but most of it went way over my head.
That said the overview of each section was fairly human-readable and gave me a good rough overview for many of the topics covered in this post.&lt;&#x2F;p&gt;
&lt;p&gt;A Brief History of Practical Garbled Circuits&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#7&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; This was the first source I checked out to get a feel for how difficult garbled circuits are as a topic.
It quickly glanced at the basics of garbled circuits and then quickly went into the optimizations on garbled circuits.
This was overwhelming, but as I started to learn more about garbled circuits and filled in the knowledge gaps it gained significant value.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s a great talk about Garbled Circuits which wasn&#x27;t ideal for beginners, but did give me a good breadth of the topic and what I could dive into.&lt;&#x2F;p&gt;
&lt;p&gt;Improved garbled Circuit: Free XOR Gates and Applications&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#8&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This paper was useful in giving me an academic preview of the XOR optimization in Garbled Circuits.
I quickly started looking at the many other papers referenced by this one, kind of like following down the Wikipedia wormhole, but with more PDFs and less pictures.&lt;&#x2F;p&gt;
&lt;p&gt;SFE: Yao&#x27;s Garbled Circuit&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#9&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This slide-deck was very useful as a reference for basic GCs and securing GC&#x27;s with cut-and-choose.
It wasn&#x27;t a great initial source for this material, but it was useful &lt;em&gt;after&lt;&#x2F;em&gt; I had a basic understanding of a topic to solidify it with pretty pictures and Comic Sans.&lt;&#x2F;p&gt;
&lt;p&gt;Mike Rosulek on Stack Exchange[^10]&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#11&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This is more of a shout-out than a citation.
Mike Rosulek&#x27;s posts on crypto.stackexchange.com were very helpful in breaking down core concepts like what garbled circuits are and why XOR is &quot;free&quot;.
They also provided a good list of further reading which was helpful in addition to the resources provided in the syllabus.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errata&quot;&gt;Errata&lt;&#x2F;h2&gt;
&lt;iframe src=&quot;&#x2F;garbled-circuits-game.html&quot; height=&quot;400px&quot; width=&quot;100%&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;Yes, the name is a misnomer. The goal is to &lt;em&gt;evaluate&lt;&#x2F;em&gt; a garbled
circuit, but that just doesn&#x27;t roll off the tongue the same.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;The original problem was developed in the 80&#x27;s.
This post adjusts the scenario for inflation.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;To completely level with you, it&#x27;s been anecdotally proven that there is at least 1 definition of Garbled Circuits for each paper on the topic.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Oblivious Transfer has been described to me as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Alice sends two possible options to a box labeled OT.&lt;&#x2F;li&gt;
&lt;li&gt;Bob sends a choice to the box labeled OT.&lt;&#x2F;li&gt;
&lt;li&gt;Bob gets back one of the two options, without knowledge of the
other.&lt;&#x2F;li&gt;
&lt;li&gt;Alice does not know which option Bob got.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is a cryptographic primitive which is very useful for tasks like generating Bob&#x27;s input to the garbled circuit &lt;code&gt;f&#x27;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;Improved garbled Circuit: Free XOR Gates and Applications, Written by Vladimir Kolesnikov and Thomas Shneider, Published July 2008. &lt;a href=&quot;http:&#x2F;&#x2F;www.cs.toronto.edu&#x2F;~vlad&#x2F;papers&#x2F;XOR_ICALP08.pdf&quot;&gt;http:&#x2F;&#x2F;www.cs.toronto.edu&#x2F;~vlad&#x2F;papers&#x2F;XOR_ICALP08.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;A Brief History of Practical Garbled Circuit Optimizations, Presented by Mike Rosulek, Published by the Simons Institute, June 15, 2015. &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;FTxh908u9y8&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;FTxh908u9y8&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;6&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;Foundations of Garbled Circuits, Written by Mihir Bellare, Viet tung Hoang, and Phillip Rogaway, Published October, 2012. &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2012&#x2F;265.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2012&#x2F;265.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;7&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;A Brief History of Practical Garbled Circuit Optimizations, Presented by Mike Rosulek, Published by the Simons Institute, June 15, 2015. &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;FTxh908u9y8&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;FTxh908u9y8&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;8&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;Improved garbled Circuit: Free XOR Gates and Applications, Written by Vladimir Kolesnikov and Thomas Shneider, Published July 2008. &lt;a href=&quot;http:&#x2F;&#x2F;www.cs.toronto.edu&#x2F;~vlad&#x2F;papers&#x2F;XOR_ICALP08.pdf&quot;&gt;http:&#x2F;&#x2F;www.cs.toronto.edu&#x2F;~vlad&#x2F;papers&#x2F;XOR_ICALP08.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;9&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;SFE: Yao&#x27;s Garbled Circuit, Published by engr.illinois.edu, for the course CS 598, Fall 2009. &lt;a href=&quot;https:&#x2F;&#x2F;courses.engr.illinois.edu&#x2F;cs598man&#x2F;fa2009&#x2F;slides&#x2F;ac-f09-lect16-yao.pdf&quot;&gt;https:&#x2F;&#x2F;courses.engr.illinois.edu&#x2F;cs598man&#x2F;fa2009&#x2F;slides&#x2F;ac-f09-lect16-yao.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;10&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;What exactly is a &quot;garbled circuit&quot;? Asked by user Ella Rose, Answered by user Mikero on on July 27, 2016. &lt;a href=&quot;https:&#x2F;&#x2F;crypto.stackexchange.com&#x2F;a&#x2F;37993&quot;&gt;https:&#x2F;&#x2F;crypto.stackexchange.com&#x2F;a&#x2F;37993&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;11&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;Why XOR and NOT is free in garbled circuits Asked by user Jason, Answered by user Mikero on February 28, 2017. &lt;a href=&quot;https:&#x2F;&#x2F;crypto.stackexchange.com&#x2F;a&#x2F;44278&quot;&gt;https:&#x2F;&#x2F;crypto.stackexchange.com&#x2F;a&#x2F;44278&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Elliptic Curve Cryptography</title>
        <published>2017-10-04T00:00:00+00:00</published>
        <updated>2017-10-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/elliptic-curve-cryptography/"/>
        <id>https://elijah.run/blog/elliptic-curve-cryptography/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/elliptic-curve-cryptography/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This is a part of a series of blog posts I wrote for an Independent
Study on cryptography at Oregon State University. To read all of the
posts, check out the &#x27;Independent Crypto&#x27; tag.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;div class=&quot;warning&quot;&gt;
    &lt;span class=&quot;warning-title&quot;&gt;
        Warning
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;warning-body&quot;&gt;
        &lt;p&gt;This post is jumps around a bit. We&#x27;ll start by showing how Elliptic
Curve Cryptography works at a high level, then create a list of
questions about how&#x2F;why Elliptic Curve Cryptography works and how it is
useful to cryptogrpahy. Once those questions are answered we will end
with a recap. Hopefully we will zero in on what Elliptic Curves are and
what Elliptic Curve Cryptography is.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;diffie-hellman-key-exchange&quot;&gt;Diffie-Hellman key exchange ++&lt;&#x2F;h2&gt;
&lt;p&gt;You find yourself day-dreaming during a walk around campus wondering if there is an alternative cryptography system to the very popular RSA.
You want something that has improved computational and network efficiency.
You want smaller keys that are harder to crack.
Could such a system exist?&lt;&#x2F;p&gt;
&lt;p&gt;You share this fantasy with a friend, you share all of your crypto fantasies with this friend, and they tell you that Elliptic Curve Cryptography is promising and it perfectly fits your needs.
... but how does it work?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;diffie-hellman-key-exchange-a-recap&quot;&gt;Diffie-Hellman key exchange (a recap)&lt;&#x2F;h3&gt;
&lt;p&gt;To create a useful crypto out of Elliptic Curves we need to implement &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Diffie%E2%80%93Hellman_key_exchange&quot;&gt;Diffie–Hellman key exchange&lt;&#x2F;a&gt; (DHKE).
Once we have DHKE we more or less have a valid crypto system which we can build upon to encrypt and decrypt private information.&lt;&#x2F;p&gt;
&lt;p&gt;The reader (you) is assumed to be familiar with DHKE.
While DHKE is fairly simple, it is not unforgettable, so here is quick reminder:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice and Bob agree on a public modulus (p) and a base (g).&lt;&#x2F;li&gt;
&lt;li&gt;Alice and Bob both choose secret integers (a and b).&lt;&#x2F;li&gt;
&lt;li&gt;Alice sends Bob g&lt;sup&gt;a&lt;&#x2F;sup&gt; (mod p) (we call it A) and Bob sends Alice g&lt;sup&gt;b&lt;&#x2F;sup&gt; (mod p) (we call it B).&lt;&#x2F;li&gt;
&lt;li&gt;Alice computes B&lt;sup&gt;a&lt;&#x2F;sup&gt; (mod p) and Bob computes A&lt;sup&gt;b&lt;&#x2F;sup&gt; (mod p).
These are equivalent (mod p).
This is Alice and Bob&#x27;s shared secret.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;How do we use Elliptic Curves get a similar &#x27;shared secret&#x27;?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;elliptic-diffie-hellman-key-exchange&quot;&gt;Elliptic Diffie-Hellman key exchange&lt;&#x2F;h3&gt;
&lt;p&gt;At a (very) high level the algorithm is as follows:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Alice and Bob agree to use a given Elliptic Curve over a finite field, E(F&lt;sub&gt;p&lt;&#x2F;sub&gt;), and a public point P ∈ E(F&lt;sub&gt;p&lt;&#x2F;sub&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Alice chooses a secret integer n&lt;sub&gt;A&lt;&#x2F;sub&gt; and Bob choose secret integers n&lt;sub&gt;B&lt;&#x2F;sub&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Alice computes Q&lt;sub&gt;A&lt;&#x2F;sub&gt; = n&lt;sub&gt;A&lt;&#x2F;sub&gt;P and Bob computes Q&lt;sub&gt;B&lt;&#x2F;sub&gt; = n&lt;sub&gt;B&lt;&#x2F;sub&gt;P.
These are the &quot;Public Keys&quot;&lt;&#x2F;li&gt;
&lt;li&gt;Alice sends Bob her public key, Bob send Alice his public key.&lt;&#x2F;li&gt;
&lt;li&gt;Alice computes n&lt;sub&gt;A&lt;&#x2F;sub&gt;Q&lt;sub&gt;B&lt;&#x2F;sub&gt;, Bob computes n&lt;sub&gt;B&lt;&#x2F;sub&gt;Q&lt;sub&gt;A&lt;&#x2F;sub&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The shared secret value is n&lt;sub&gt;A&lt;&#x2F;sub&gt;Q&lt;sub&gt;B&lt;&#x2F;sub&gt; = n&lt;sub&gt;A&lt;&#x2F;sub&gt;(n&lt;sub&gt;B&lt;&#x2F;sub&gt;P) = n&lt;sub&gt;B&lt;&#x2F;sub&gt;(n&lt;sub&gt;A&lt;&#x2F;sub&gt;P) = n&lt;sub&gt;B&lt;&#x2F;sub&gt;Q&lt;sub&gt;A&lt;&#x2F;sub&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It looks similar to the given DHKE algorithm, and seems promising, but... how does it work?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;elliptic-curves-and-elliptic-curve-cryptography-q-a&quot;&gt;Elliptic Curves and Elliptic Curve Cryptography Q&amp;amp;A&lt;&#x2F;h2&gt;
&lt;p&gt;To answer that we are going to answer the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;What are Elliptic Curves?&lt;&#x2F;li&gt;
&lt;li&gt;What does an Elliptic Curve look like?&lt;&#x2F;li&gt;
&lt;li&gt;What does it mean to multiply P by n?&lt;&#x2F;li&gt;
&lt;li&gt;What about a finite field?&lt;&#x2F;li&gt;
&lt;li&gt;How are the pubic keys used? Why are these a shared secret?&lt;&#x2F;li&gt;
&lt;li&gt;Why is Elliptic Curve Cryptography useful?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;what-are-elliptic-curves&quot;&gt;What are Elliptic Curves?&lt;&#x2F;h3&gt;
&lt;p&gt;A Elliptic Curve is the set of solutions to an equation of the form&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;y&lt;sup&gt;2&lt;&#x2F;sup&gt; = x&lt;sup&gt;3&lt;&#x2F;sup&gt; + AX + B&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;what-does-an-elliptic-curve-look-like&quot;&gt;What does an Elliptic Curve look like?&lt;&#x2F;h3&gt;
&lt;p&gt;Two examples of Elliptic Curves are as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;ecc-1.png&quot; alt=&quot;A simple elliptic curve&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;and:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;ecc-2.png&quot; alt=&quot;Another simple elliptic curve&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;adding-p-and-q&quot;&gt;Adding P and Q&lt;&#x2F;h3&gt;
&lt;p&gt;Multiplication is &lt;em&gt;just&lt;&#x2F;em&gt; repeated addition.
Oh shoot we haven&#x27;t said how &quot;addition&quot; happens on an Elliptic Curve. Let&#x27;s do that.&lt;&#x2F;p&gt;
&lt;p&gt;Addition is the process of drawing a line L between P and Q.
The third point that the line L intersects is point R. When R is reflected over the X axis we call this R&#x27;.
The result of P ⊕ Q (read: P &#x27;plus&#x27; Q) is R&#x27;.&lt;&#x2F;p&gt;
&lt;p&gt;We can enumerate these steps as:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Take two points P and Q on the Elliptic Curve E.&lt;&#x2F;li&gt;
&lt;li&gt;Draw a line L which passes through these two points.&lt;&#x2F;li&gt;
&lt;li&gt;L should ultimately pass through &lt;em&gt;three&lt;&#x2F;em&gt; points: P, Q, and R.&lt;&#x2F;li&gt;
&lt;li&gt;Multiply the Y coordinate of R by -1, this is R&#x27;.&lt;&#x2F;li&gt;
&lt;li&gt;P ⊕ Q = R&#x27;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Here&#x27;s a visualization of straight forward addition.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;ecc-3.png&quot; alt=&quot;Annotated curve E with points P, Q, R, R&amp;#39; and line L labeled.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You might think &quot;What happens when P is tangent a point on E?&quot; In that
case we say P = Q, so R = P ⊕ P, or R = 2P. It looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;ecc-4.png&quot; alt=&quot;Annotated curve E with points P, R, R&amp;#39; and line L labeled. P is tangent to the curve.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wait a second, 2P looks like n*P which was one of the questions we had!
Don&#x27;t worry, we&#x27;ll get there soon.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;that-thing-about-finite-fields&quot;&gt;That thing about Finite Fields&lt;&#x2F;h3&gt;
&lt;p&gt;In practice we bound the curve over a field F&lt;sub&gt;p&lt;&#x2F;sub&gt; with p ≥ 3.
We input {1, 2, ..., p-1} as the value of X in E and select the results which are squares modulo 13.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;E : y&lt;sup&gt;2&lt;&#x2F;sup&gt; = x&lt;sup&gt;3&lt;&#x2F;sup&gt; + 3X + 8 over F&lt;sub&gt;13&lt;&#x2F;sub&gt;
X = 1
1 + 3 + 8 = 12
12 is a square (mod 13)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Repeating this gives us the set of points in E(F&lt;sub&gt;13&lt;&#x2F;sub&gt;):&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;E(F&lt;sub&gt;13&lt;&#x2F;sub&gt;) = {O, (1,5), (1,8), (2,3), (2,10), (9,6), (9,7),
(12,2), (12,11)}&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In practice this bounds the graph of E and forces us to draw a strange modulus graph shown below:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;independent-crypto&#x2F;ecc-5.gif&quot; alt=&quot;Elliptic Curves illustrated where each point is a valid coordinate. There are no curves.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Image source: A (relatively easy to understand) primer on elliptic curve cryptography&lt;&#x2F;em&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;multiplying-p-by-an-integer-with-the-double-and-add-algorithm&quot;&gt;Multiplying P by an integer with The Double-and-Add Algorithm&lt;&#x2F;h3&gt;
&lt;p&gt;To &quot;multiply&quot; P by n we need to use the Double-and-Add Algorithm.
Here&#x27;s how that looks:&lt;&#x2F;p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;Take a point P ∈ E(F&lt;sub&gt;p&lt;&#x2F;sub&gt;) and an integer n ≥ 1.&lt;&#x2F;li&gt;
&lt;li&gt;Set Q = P and R = O.&lt;&#x2F;li&gt;
&lt;li&gt;Loop while n &amp;gt; 0.
3.  If n ≡ 1 (mod 2), set R = R + Q
4.  Set Q = 2Q and n = floor(n&#x2F;2).&lt;&#x2F;li&gt;
&lt;li&gt;Return the point R, which equals nP.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;em&gt;Recall that the algorithm for finding point 2Q was covered in the above section&lt;&#x2F;em&gt; &lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;elliptic-curve-cryptography&#x2F;#adding-p-and-q&quot;&gt;Adding P and Q&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-is-the-shared-secret&quot;&gt;What &lt;em&gt;is&lt;&#x2F;em&gt; the shared secret?&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s review.
The shared secret is the second point n&lt;sub&gt;A&lt;&#x2F;sub&gt;n&lt;sub&gt;B&lt;&#x2F;sub&gt;P, which is a point on the public curve E(F&lt;sub&gt;p&lt;&#x2F;sub&gt;).
This point can be used to encrypt information as it is a shared secret (necessary for DHKE).
How exactly it is used to encrypt information is left as an exercise for readers in charge of cryptographic implementation standards.&lt;&#x2F;p&gt;
&lt;p&gt;The reason this is a shared secret is because an adversary needs to solve the following Elliptic Curve Discrete Logarithm Problem&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;nP = Q&lt;sub&gt;A&lt;&#x2F;sub&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Which is a very hard problem, as mentioned in the next section.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;an-example-of-elliptic-curve-cryptography&quot;&gt;An example of Elliptic Curve Cryptography&lt;&#x2F;h2&gt;
&lt;p&gt;This sounds good in theory, but let&#x27;s give it a test drive.&lt;&#x2F;p&gt;
&lt;p&gt;Alice and Bob are given the following shared information:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;p = 3851, E: y&lt;sup&gt;2&lt;&#x2F;sup&gt; = x&lt;sup&gt;3&lt;&#x2F;sup&gt; + 324X + 1287, P = (920, 303) ∈ E(F&lt;sub&gt;3851&lt;&#x2F;sub&gt;)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Alice and Bob choose their secret integers:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;n&lt;sub&gt;A&lt;&#x2F;sub&gt; = 1194
n&lt;sub&gt;B&lt;&#x2F;sub&gt; = 1759&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Alice and Bob then compute their public keys:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Alice computes Q&lt;sub&gt;A&lt;&#x2F;sub&gt; = 1194P = (2067, 2178) ∈ E(F&lt;sub&gt;3851&lt;&#x2F;sub&gt;)
Bob computes Q&lt;sub&gt;B&lt;&#x2F;sub&gt; = 1759P = (3684, 3125) ∈ E(F&lt;sub&gt;3851&lt;&#x2F;sub&gt;)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;Remember that we use the Double-and-Add algorithm to compute
Q&lt;sub&gt;A&lt;&#x2F;sub&gt; and Q&lt;sub&gt;B&lt;&#x2F;sub&gt;. This invloves iteratively computing the
tangent line at a point, the intersection with E at that intersection,
and reflecting that point over the X axis.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Alice and Bob trade public keys and calculate their shared secret:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Alice computes n&lt;sub&gt;A&lt;&#x2F;sub&gt;Q&lt;sub&gt;B&lt;&#x2F;sub&gt; = 1194(3684, 3125) = (3347, 1242) ∈ E(F&lt;sub&gt;3851&lt;&#x2F;sub&gt;)
Bob computes n&lt;sub&gt;B&lt;&#x2F;sub&gt;Q&lt;sub&gt;A&lt;&#x2F;sub&gt; = 1759(2067, 2178) = (3347, 1242) ∈ E(F&lt;sub&gt;3851&lt;&#x2F;sub&gt;)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Therefore (3347, 1242) is the shared secret.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-elliptic-curve-cryptography-is-useful&quot;&gt;Why Elliptic Curve Cryptography is useful&lt;&#x2F;h2&gt;
&lt;p&gt;While it is harder than simply multiplying mod p for Alice to compute her shared secret (which is the case in RSA), it is &lt;em&gt;even harder&lt;&#x2F;em&gt; for a
malicious actor to figure out that same shared secret.
This point is best put by the source &lt;em&gt;A (relatively easy to understand) primer on elliptic curve cryptography&lt;&#x2F;em&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can compute how much energy is needed to break a cryptographic algorithm and compare that with how much water that energy could boil.
This is a kind of a cryptographic carbon footprint. By this measure, breaking a 228-bit RSA key requires less energy than it takes to boil a teaspoon of water.
Comparatively, breaking a 228-bit elliptic curve &amp;gt; key requires enough energy to boil all the water on earth.
For this &amp;gt; level of security with RSA, you&#x27;d need a key with 2,380 bits.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So an Elliptic Curve Cryptography key can be one magnitude smaller in size and offer the same level of security as RSA.&lt;&#x2F;p&gt;
&lt;p&gt;We can put this in more concrete terms: the fastest algorithm to solve the Elliptic Curve Discrete Logarithm Problem, which Elliptic DHKE security is built upon, in E(F&lt;sub&gt;p&lt;&#x2F;sub&gt;) takes √p steps.
This is much more difficult than the &#x27;vanilla&#x27; Discrete Logarithm Problem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notes-and-edge-cases&quot;&gt;Notes and edge cases&lt;&#x2F;h2&gt;
&lt;p&gt;Elliptic Curve Cryptography, much like the rest of Cryptography, deals heavily with &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Number_theory&quot;&gt;Number Theory&lt;&#x2F;a&gt;.
Despite my best efforts most of the nitty-gritty Number Theory in this topic went &lt;em&gt;way&lt;&#x2F;em&gt; over my head.
As a result I didn&#x27;t include much of that kind of stuff and instead focused on the things I &lt;em&gt;could&lt;&#x2F;em&gt; share and sound smart about.&lt;&#x2F;p&gt;
&lt;p&gt;Here are some other things about Elliptic Curve Cryptography I didn&#x27;t cover that deserve more air time:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The Elliptic Curve chosen must meet a special set of criteria; any old Elliptic Curve won&#x27;t do.
This was the cause of a cryptographic breach with Elliptic Curve Cryptography a few years ago that triggered doubts about Elliptic Curve Cryptography as a whole.&lt;&#x2F;li&gt;
&lt;li&gt;Some primes cause solving the Elliptic Curve Discrete Logarithm Problem for E(F&lt;sub&gt;p&lt;&#x2F;sub&gt;) to be easier than the Discrete Logarithm Problem, these primes can be computed and should be avoided.&lt;&#x2F;li&gt;
&lt;li&gt;If you want a deeper understanding of the theory of Elliptic Curves (addition of points on these curves, etc) you should look into &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Algebraic_geometry&quot;&gt;algebraic geometry&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;annotated-bibliography&quot;&gt;Annotated Bibliography&lt;&#x2F;h2&gt;
&lt;p&gt;An Introduction to Mathematical Cryptography&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; The chapter in this textbook on Elliptic Curves in Cryptography established the bedrock understanding of the topic of Elliptic Curve Cryptography.
This ended up being the main resource for this post and offered a great median between &quot;Regular Joe&#x27;s guide to Elliptic Curve Cryptography&quot; and &quot;The graduate student&#x27;s guide to Elliptic Curve Cryptography&quot; which were my other two resources.
It was also the source of all examples, which were very useful in gaining an intuitive understanding of the material.&lt;&#x2F;p&gt;
&lt;p&gt;A (relatively easy to understand) primer on elliptic curve cryptography&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#4&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; This blog post was my &lt;em&gt;second&lt;&#x2F;em&gt; source and did a good job of taking the proofs and dense material in Intro to Math Cyrpto (above) and boiled it down to the important stuff.
It drastically improved further readings of the original textbook and provided that great animated image of adding P ⊕ Q in E(F&lt;sub&gt;p&lt;&#x2F;sub&gt;). It didn&#x27;t cover any of the Number Theory, but explained the historical context of Elliptic Curve Cryptography, roughly how&#x2F;why it works, and did a good job of describing it&#x27;s impact in our world today.&lt;&#x2F;p&gt;
&lt;p&gt;Cryptography: An Introduction&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#5&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
This wasn&#x27;t a resource I actually &lt;em&gt;used&lt;&#x2F;em&gt;, but I did read the chapter on Elliptic Curve Cryptography (chapter 2!).
It gave me an appreciation for the previous two sources and some exposure to the other ways Elliptic Curves can be taught.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errata&quot;&gt;Errata&lt;&#x2F;h2&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;A (relatively easy to understand) primer on elliptic curve cryptography, October 24, 2013, Nick Sullivan, Cloudflare blog, reposted on Ars Technica, &lt;a href=&quot;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&quot;&gt;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;A (relatively easy to understand) primer on elliptic curve cryptography, October 24, 2013, Nick Sullivan, Cloudflare blog, reposted on Ars Technica, &lt;a href=&quot;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&quot;&gt;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;3&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;An Introduction to Mathematical Cryptography, 2008, Jeffery Hoffstein, Jill Pipher, Joseph H. Silverman, Springer Publishing, ISBN 978-0-387-77993-5&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;4&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;A (relatively easy to understand) primer on elliptic curve cryptography, October 24, 2013, Nick Sullivan, Cloudflare blog, reposted on Ars Technica, &lt;a href=&quot;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&quot;&gt;https:&#x2F;&#x2F;arstechnica.com&#x2F;information-technology&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;5&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;Cryptography: An Introduction (Third Edition), May 19, 2016, Nigel Smart, &lt;a href=&quot;https:&#x2F;&#x2F;www.cs.umd.edu&#x2F;~waa&#x2F;414-F11&#x2F;IntroToCrypto.pdf&quot;&gt;https:&#x2F;&#x2F;www.cs.umd.edu&#x2F;~waa&#x2F;414-F11&#x2F;IntroToCrypto.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Independent Crypto Course syllabus</title>
        <published>2017-07-10T00:00:00+00:00</published>
        <updated>2017-07-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/independent-crypto/"/>
        <id>https://elijah.run/blog/independent-crypto/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/independent-crypto/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This is a part of a series of blog posts I wrote for an Independent Study on cryptography at Oregon State University.
To read all of the posts, check out the &#x27;Independent Crypto&#x27; tag.
{% end() %}&lt;&#x2F;p&gt;
&lt;p&gt;{% warning() %}
This syllabus was written by an Oregon State University undergraduate student and not by an Oregon State University staff member.
This should explain any irregularities in the structure and substance of the document.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;The purpose of this course (&quot;Independent Crypto&quot;) is to give students an opportunity to dive deeper into interesting topics of Cryptography.&lt;&#x2F;p&gt;
&lt;p&gt;By the end of this course you should &lt;em&gt;grok&lt;&#x2F;em&gt; the following topics:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Elliptic curve cryptography&lt;&#x2F;li&gt;
&lt;li&gt;Memory hard functions&lt;&#x2F;li&gt;
&lt;li&gt;Garbled circuits&lt;&#x2F;li&gt;
&lt;li&gt;An topic of your choosing (get creative!)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Each of these should take about 40 hours of work to complete.
An overview of what that means is outlined below.&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This course is designed to be a 4 credit hour independent study.&lt;&#x2F;p&gt;
&lt;p&gt;As is standard Oregon State University policy, this corresponds with 160
hours of work over a 10 week period.
Plan accordingly.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Each topic ought to take about 40 hours of work to complete over the course of a 10 week term.
If you schedule your time well this will be a piece of cake at just 16 hours per week.
That&#x27;s 2.28 hours per day, 3.2 hours per week-day, or 16 hours the day before your check-in is due!&lt;&#x2F;p&gt;
&lt;p&gt;The basic structure is as follows:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Research a topic.
Read papers, watch informative videos, ask questions and learn as much as you can about a given topic.&lt;&#x2F;li&gt;
&lt;li&gt;Maintain an &lt;em&gt;annotated bibliography&lt;&#x2F;em&gt;.
This should include materials found while studying a given topic, a summary of each of the materials, and a final summary of the topic as a whole.&lt;&#x2F;li&gt;
&lt;li&gt;Meet weekly with the mentoring professor.&lt;&#x2F;li&gt;
&lt;li&gt;Repeat.&lt;&#x2F;li&gt;
&lt;li&gt;???&lt;&#x2F;li&gt;
&lt;li&gt;Profit.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The end goal, in addition to learning about a breadth of topics in modern security, is to produce an annotated bibliography.
This will exercise the student&#x27;s ability to read and process academic topics, journals, and videos.&lt;&#x2F;p&gt;
&lt;p&gt;Of course if you are particularly passionate about a topic you are encouraged to go further: implementing things of interest, investigating new questions, and generally &#x27;digging deeper&#x27; as you gain interest in different topics.&lt;&#x2F;p&gt;
&lt;p&gt;The following topics do not &lt;em&gt;need&lt;&#x2F;em&gt; to be completed in order, however doing so will result in an optimal &#x27;difficulty curve&#x27; as the kids say.
The kids do still say that right?&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;Included are a few resources grabbed in a quick internet search.
These are meant to be starting places for each topic, generating questions and providing external resources.
You will need to find additional resources for each topic.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;h2 id=&quot;elliptic-curve-cryptography&quot;&gt;Elliptic Curve Cryptography&lt;&#x2F;h2&gt;
&lt;p&gt;Weeks 0-2 will be dedicated to Elliptic Curve Cryptography.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kickoff-resources&quot;&gt;Kickoff Resources&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;A (relatively easy to understand) primer on Elliptic Curve Cryptography: &lt;a href=&quot;https:&#x2F;&#x2F;arstechnica.com&#x2F;security&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&quot;&gt;https:&#x2F;&#x2F;arstechnica.com&#x2F;security&#x2F;2013&#x2F;10&#x2F;a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Elliptic Curve Cryptography in Practice: &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;734.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;734.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Elliptic Curve Cryptography, a gentle introduction: &lt;a href=&quot;http:&#x2F;&#x2F;andrea.corbellini.name&#x2F;2015&#x2F;05&#x2F;17&#x2F;elliptic-curve-cryptography-a-gentle-introduction&#x2F;&quot;&gt;http:&#x2F;&#x2F;andrea.corbellini.name&#x2F;2015&#x2F;05&#x2F;17&#x2F;elliptic-curve-cryptography-a-gentle-introduction&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;kickoff-questions&quot;&gt;Kickoff Questions&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;What are elliptic curves?&lt;&#x2F;li&gt;
&lt;li&gt;How do elliptic curves relate to cryptography?&lt;&#x2F;li&gt;
&lt;li&gt;How are Elliptic Curve Cryptography functions different from similar ones like RSA?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;memory-hard-functions&quot;&gt;Memory-hard functions&lt;&#x2F;h2&gt;
&lt;p&gt;Weeks 3 and 4 of the course should be dedicated to the topic of Memory Hard Functions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kickoff-resources-1&quot;&gt;Kickoff Resources&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Memory-hard functions and tradeoff cryptanalysis with applications to password hashing, cryptocurrencies, and white-box cryptography: &lt;a href=&quot;https:&#x2F;&#x2F;www.cryptolux.org&#x2F;images&#x2F;d&#x2F;d1&#x2F;Tradeoff-slides.pdf&quot;&gt;https:&#x2F;&#x2F;www.cryptolux.org&#x2F;images&#x2F;d&#x2F;d1&#x2F;Tradeoff-slides.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Strict Memory Hard Hashing Functions: &lt;a href=&quot;http:&#x2F;&#x2F;www.hashcash.org&#x2F;papers&#x2F;memohash.pdf&quot;&gt;http:&#x2F;&#x2F;www.hashcash.org&#x2F;papers&#x2F;memohash.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;kickoff-questions-1&quot;&gt;Kickoff Questions&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;What are Memory-hard functions?&lt;&#x2F;li&gt;
&lt;li&gt;What purposes are Memory-hard functions used for?&lt;&#x2F;li&gt;
&lt;li&gt;What are some examples of Memory-hard functions and how do they work?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;garbled-circuits&quot;&gt;Garbled circuits&lt;&#x2F;h2&gt;
&lt;p&gt;Weeks 5-7 should be dedicated to garbled circuits.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kickoff-resources-2&quot;&gt;Kickoff Resources&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Garbled Circuits: &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;TxCu1L_tzlU&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;TxCu1L_tzlU&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Foundations of Garbled Circuits: &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2012&#x2F;265.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2012&#x2F;265.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Faster Secure Two-Party Computation Using Garbled Circuits: &lt;a href=&quot;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;event&#x2F;sec11&#x2F;tech&#x2F;full_papers&#x2F;Huang.pdf&quot;&gt;https:&#x2F;&#x2F;www.usenix.org&#x2F;legacy&#x2F;event&#x2F;sec11&#x2F;tech&#x2F;full_papers&#x2F;Huang.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;SFE: Yao’s Garbled Circuit: &lt;a href=&quot;https:&#x2F;&#x2F;courses.engr.illinois.edu&#x2F;cs598man&#x2F;fa2009&#x2F;slides&#x2F;ac-f09-lect16-yao.pdf&quot;&gt;https:&#x2F;&#x2F;courses.engr.illinois.edu&#x2F;cs598man&#x2F;fa2009&#x2F;slides&#x2F;ac-f09-lect16-yao.pdf&lt;&#x2F;a&gt; (bonus points if you find the talk for these slides).&lt;&#x2F;li&gt;
&lt;li&gt;Garbled Circuts, Cryptowiki, &lt;a href=&quot;http:&#x2F;&#x2F;cryptowiki.net&#x2F;index.php?title=Garbled_circuits&quot;&gt;http:&#x2F;&#x2F;cryptowiki.net&#x2F;index.php?title=Garbled_circuits&lt;&#x2F;a&gt; (probably don&#x27;t cite this one in a paper)&lt;&#x2F;li&gt;
&lt;li&gt;Amortizing Garbled Circuits: &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2015&#x2F;081.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2015&#x2F;081.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;independent-study&quot;&gt;Independent study&lt;&#x2F;h2&gt;
&lt;p&gt;In the last seven or so weeks you&#x27;ve learned a lot.
You&#x27;ve read papers, watch informative lectures, and had insightful conversations with peers and mentors.
Many of these probably sparked your attention in a particular topic.
Use these last few weeks to investigate one of those sparks that you&#x27;ve been itching to learn more about.&lt;&#x2F;p&gt;
&lt;p&gt;If you truly feel uninspired you can use this time to learn about Private Set Intersection.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kickoff-resources-for-private-set-intersection&quot;&gt;Kickoff Resources for Private Set Intersection&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;BIU Winter School on Cryptography on Youtube.&lt;&#x2F;li&gt;
&lt;li&gt;CSCI E-127, Introduction to Cryptography &lt;a href=&quot;http:&#x2F;&#x2F;cm.dce.harvard.edu&#x2F;2014&#x2F;01&#x2F;14301&#x2F;publicationListing.shtml&quot;&gt;http:&#x2F;&#x2F;cm.dce.harvard.edu&#x2F;2014&#x2F;01&#x2F;14301&#x2F;publicationListing.shtml&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;generic-kickoff-questions&quot;&gt;Generic Kickoff Questions&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;What topic are you investigating?&lt;&#x2F;li&gt;
&lt;li&gt;How does this relate to Cryptography?&lt;&#x2F;li&gt;
&lt;li&gt;How would you explain this topic to your friends or parents?&lt;&#x2F;li&gt;
&lt;li&gt;Why is this topic important?&lt;&#x2F;li&gt;
&lt;li&gt;What interests you about this topic?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;additional-resources&quot;&gt;Additional resources&lt;&#x2F;h2&gt;
&lt;p&gt;OSU Professor &lt;a href=&quot;http:&#x2F;&#x2F;web.engr.oregonstate.edu&#x2F;~rosulekm&#x2F;&quot;&gt;Mike Rosulek&lt;&#x2F;a&gt; volunteered the following additional resources:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Scrypt is maximally memory-hard, &lt;a href=&quot;http:&#x2F;&#x2F;www.cs.bu.edu&#x2F;fac&#x2F;reyzin&#x2F;papers&#x2F;BostonCryptoDayTalk-Leo.pptx&quot;&gt;http:&#x2F;&#x2F;www.cs.bu.edu&#x2F;fac&#x2F;reyzin&#x2F;papers&#x2F;BostonCryptoDayTalk-Leo.pptx&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Practical Graphs for Optimal Side-Channel Resistant Memory-Hard Functions, &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2017&#x2F;443.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2017&#x2F;443.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Efficiently Computing Data Independent Memory Hard Functions, &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;ujpvPtn_N5Y&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;ujpvPtn_N5Y&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Memory hard Functions and Password Hashing, &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;9yX4v89m5oo&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;9yX4v89m5oo&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Towards a Theory of Data-Independent Memory Hard Functions, &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;YtfVLzUkwME&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;YtfVLzUkwME&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Depth-Robust Graphs and Their Cumulative Memory Complexity, &lt;a href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;875.pdf&quot;&gt;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;875.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Practical Garbled Circuit Optimizations, &lt;a href=&quot;http:&#x2F;&#x2F;web.engr.oregonstate.edu&#x2F;~rosulekm&#x2F;pubs&#x2F;gc-survey-talk.pdf&quot;&gt;http:&#x2F;&#x2F;web.engr.oregonstate.edu&#x2F;~rosulekm&#x2F;pubs&#x2F;gc-survey-talk.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Pratical Garbled Circuit Optimizations, &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;FTxh908u9y8&quot;&gt;https:&#x2F;&#x2F;youtu.be&#x2F;FTxh908u9y8&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Cache-timing attacks on AES, &lt;a href=&quot;http:&#x2F;&#x2F;cr.yp.to&#x2F;antiforgery&#x2F;cachetiming-20050414.pdf&quot;&gt;http:&#x2F;&#x2F;cr.yp.to&#x2F;antiforgery&#x2F;cachetiming-20050414.pdf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Lucky Thirteen attack on TLS CBC, &lt;a href=&quot;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2013&#x2F;02&#x2F;04&#x2F;luckythirteen.html&quot;&gt;https:&#x2F;&#x2F;www.imperialviolet.org&#x2F;2013&#x2F;02&#x2F;04&#x2F;luckythirteen.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Deploying Buildbot on Kubernetes</title>
        <published>2016-12-12T00:00:00+00:00</published>
        <updated>2016-12-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/buildbot-on-kubernetes/"/>
        <id>https://elijah.run/blog/buildbot-on-kubernetes/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/buildbot-on-kubernetes/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;kubernetes-logo.png&quot; alt=&quot;kubernetes logo&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TLDR:&lt;&#x2F;strong&gt; If you just want to see the end-result of this post, the results can be found at this GitHub Repository: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ElijahCaine&#x2F;buildbot-on-kubernetes&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;ElijahCaine&#x2F;buildbot-on-kubernetes&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;preamble&quot;&gt;Preamble&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m learning Kubernetes (K8s) for work and decided to try my hand at deploying Buildbot with K8s because we all know the universal law discovered made by Science McSmartyPants in the 1758 which stated: &lt;strong&gt;doing cool shit &amp;gt; reading docs&lt;&#x2F;strong&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#docs-should&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.
I would describe K8s and Buildbot, but they each already did that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Buildbot is an open-source framework for automating software build, test, and release processes.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;- &lt;a href=&quot;http:&#x2F;&#x2F;buildbot.net&#x2F;&quot;&gt;Buildbot.net&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;Kubernetes is an open-source system for automating deployment,
scaling, and management of containerized applications.&lt;&#x2F;p&gt;
&lt;p&gt;- &lt;a href=&quot;http:&#x2F;&#x2F;kubernetes.io&#x2F;&quot;&gt;Kubernetes.io&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;If that still didn&#x27;t make sense, don&#x27;t worry you should keep reading.
This is a fun post.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;&#x2F;strong&gt; As you read this post keep in mind: &lt;em&gt;it might walk like a
tutorial, quack like a tutorial, and even read like a tutorial, but I
promise you that it is in fact&lt;&#x2F;em&gt; &lt;strong&gt;not&lt;&#x2F;strong&gt; &lt;em&gt;a tutorial.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;This post is an adventure.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;squad-goals&quot;&gt;Squad Goals&lt;&#x2F;h3&gt;
&lt;p&gt;Here&#x27;s a quick rundown of what I want to achieve:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Deploy an instance of Buildbot on K8s.&lt;&#x2F;li&gt;
&lt;li&gt;Have that instance scale it&#x27;s number of workers automagically
depending on the amount of work being asked of it.&lt;&#x2F;li&gt;
&lt;li&gt;Share all relevant storage between replicated containers (e.g.,
databases, builds, etc).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h3&gt;
&lt;p&gt;I have never deployed Buildbot ever for anything. I have also not really
worked with K8s until starting my recent jorb at
&lt;a href=&quot;https:&#x2F;&#x2F;coreos.com&quot;&gt;CoreOS&lt;&#x2F;a&gt;. Why Buildbot and why K8s?&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;I have to learn K8s sooner or later for work.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;I want to deploy something a little more complicated than Nginx. As
fun as that is, every K8s tutorial uses that as an example and it&#x27;s
getting &lt;em&gt;oooooold&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Buildbot seems like a good K8s challenge b&#x2F;c:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It has 3 moving parts (master, worker, database)&lt;&#x2F;li&gt;
&lt;li&gt;It could benefit from the fancy-dancy auto-scaling features
built into K8s (e.g., high workload -&amp;gt; add more workers)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Anyway, let&#x27;s get started.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;my-sick-rig&quot;&gt;My sick rig&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;m using the latest version of K8s and
&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;minikube#minikube&quot;&gt;Minikube&lt;&#x2F;a&gt;, which is
backed by Virtualbox on a 2014 MacBook Pro running OSX.&lt;&#x2F;p&gt;
&lt;p&gt;Minikube version and associated OS:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ minikube version
&lt;&#x2F;span&gt;&lt;span&gt;minikube version: v0.13.1
&lt;&#x2F;span&gt;&lt;span&gt;$ minikube ssh
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;Boot2Docker version 1.11.1, build master : 901340f - Fri Jul  1 22:52:19 UTC 2016
&lt;&#x2F;span&gt;&lt;span&gt;Docker version 1.11.1, build 5604cbe
&lt;&#x2F;span&gt;&lt;span&gt;docker@minikube:~$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There&#x27;s some Minikube-specific semantics in this post, but you can
probably get by with whatever K8s back-end you want&#x2F;have lying around.&lt;&#x2F;p&gt;
&lt;p&gt;Kubernetes version:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl version
&lt;&#x2F;span&gt;&lt;span&gt;Client Version: version.Info{Major:&amp;quot;1&amp;quot;, Minor:&amp;quot;4&amp;quot;, GitVersion:&amp;quot;v1.4.6&amp;quot;, GitCommit:&amp;quot;e569a27d02001e343cb68086bc06d47804f62af6&amp;quot;, GitTreeState:&amp;quot;clean&amp;quot;, BuildDate:&amp;quot;2016-11-12T05:22:15Z&amp;quot;, GoVersion:&amp;quot;go1.7.1&amp;quot;, Compiler:&amp;quot;gc&amp;quot;, Platform:&amp;quot;darwin&#x2F;amd64&amp;quot;}
&lt;&#x2F;span&gt;&lt;span&gt;Server Version: version.Info{Major:&amp;quot;1&amp;quot;, Minor:&amp;quot;4&amp;quot;, GitVersion:&amp;quot;v1.4.6&amp;quot;, GitCommit:&amp;quot;e569a27d02001e343cb68086bc06d47804f62af6&amp;quot;, GitTreeState:&amp;quot;clean&amp;quot;, BuildDate:&amp;quot;1970-01-01T00:00:00Z&amp;quot;, GoVersion:&amp;quot;go1.7.1&amp;quot;, Compiler:&amp;quot;gc&amp;quot;, Platform:&amp;quot;linux&#x2F;amd64&amp;quot;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Between finishing editing and pushing this post the above versions will
probably be out of date. &lt;em&gt;SHRUG&lt;&#x2F;em&gt;. What are you gonna do. Software,
amirite?&lt;&#x2F;p&gt;
&lt;p&gt;Virtualbox version:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ virtualbox --help
&lt;&#x2F;span&gt;&lt;span&gt;Oracle VM VirtualBox Manager 5.1.6
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;OSX Version and hardware:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ sw_vers
&lt;&#x2F;span&gt;&lt;span&gt;ProductName:    Mac OS X
&lt;&#x2F;span&gt;&lt;span&gt;ProductVersion: 10.10.5
&lt;&#x2F;span&gt;&lt;span&gt;BuildVersion:   14F1912
&lt;&#x2F;span&gt;&lt;span&gt;$ system_profiler
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;    Hardware Overview:
&lt;&#x2F;span&gt;&lt;span&gt;      Model Name: MacBook Pro
&lt;&#x2F;span&gt;&lt;span&gt;      Model Identifier: MacBookPro11,1
&lt;&#x2F;span&gt;&lt;span&gt;      Processor Name: Intel Core i5
&lt;&#x2F;span&gt;&lt;span&gt;      Processor Speed: 2.6 GHz
&lt;&#x2F;span&gt;&lt;span&gt;      Number of Processors: 1
&lt;&#x2F;span&gt;&lt;span&gt;      Total Number of Cores: 2
&lt;&#x2F;span&gt;&lt;span&gt;      ...
&lt;&#x2F;span&gt;&lt;span&gt;      Memory: 16 GB
&lt;&#x2F;span&gt;&lt;span&gt;      ...
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The hardware and Virtualbox versions are a little less important, but
might as well be included for completeness.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;first-pass&quot;&gt;First Pass&lt;&#x2F;h2&gt;
&lt;p&gt;The Buildbot project is nice enough to provide &lt;a href=&quot;https:&#x2F;&#x2F;docs.buildbot.net&#x2F;current&#x2F;tutorial&#x2F;docker.html&quot;&gt;some Buidlbot Docker
infrastructure&lt;&#x2F;a&gt;
to start working with. It uses a &lt;a href=&quot;https:&#x2F;&#x2F;docs.docker.com&#x2F;compose&#x2F;&quot;&gt;Docker
Compose&lt;&#x2F;a&gt; YAML file to deploy one
worker container, one master service, and one PostgreSQL service, each
of which is linked together and &lt;em&gt;just works™&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Great!
In theory &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#theory-vs-practice&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; we can just translate the options in &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; to K8s options to get a simple cluster up and running.
Which, to clarify, isn&#x27;t an established &lt;strong&gt;thing&lt;&#x2F;strong&gt;, it&#x27;s just a process I&#x27;m guessing should work based on the fact that Docker Compose and K8s are both orchestration tools.
One is &lt;strong&gt;way&lt;&#x2F;strong&gt; more complicated and robust, but At least &lt;strong&gt;some&lt;&#x2F;strong&gt; of their features should over-lap in that Venn diagram.&lt;&#x2F;p&gt;
&lt;p&gt;Once we&#x27;ve got a nieve translated-docker-compose k8s setup running then we can (hopefully) tweak some knobs and get persistent storage and auto-scaling working &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#why&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;throw-some-containers-at-the-wall-and-see-what-sticks&quot;&gt;Throw some containers at the wall and see what sticks&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s start really basic and just try to get something running with &lt;code&gt;kubectl run&lt;&#x2F;code&gt;.
We&#x27;ll use K8s to deploy a Buildbot &lt;code&gt;master&lt;&#x2F;code&gt; container mentioned in that &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; with translated configuration options from that file.
Remember, we&#x27;re just mapping a &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; into a K8s setup to begin.
Nothing fancy, no pre-emptive optimizations, just this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl run master \
&lt;&#x2F;span&gt;&lt;span&gt;    --image=buildbot&#x2F;buildbot-master:master \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;BUILDBOT_CONFIG_DIR=config&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;BUILDBOT_CONFIG_URL=https:&#x2F;&#x2F;github.com&#x2F;buildbot&#x2F;buildbot-docker-example-config&#x2F;archive&#x2F;master.tar.gz&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;BUILDBOT_WORKER_PORT=9989&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;BUILDBOT_WEB_URL=http:&#x2F;&#x2F;localhost:8080&#x2F;&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;BUILDBOT_WEB_PORT=8080&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --port=8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Some reading later and I can tell you that command started a &lt;em&gt;Deployment&lt;&#x2F;em&gt; of &lt;em&gt;Pods&lt;&#x2F;em&gt;.
To see if it worked, let&#x27;s run &lt;code&gt;kubect get pods&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods
&lt;&#x2F;span&gt;&lt;span&gt;NAME                               READY     STATUS             RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;master-4259088255-afsfk            1&#x2F;1       Running            1          10s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This looks pretty good...&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods
&lt;&#x2F;span&gt;&lt;span&gt;NAME                               READY     STATUS             RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;master-4259088255-afsfk            0&#x2F;1       CrashLoopBackOff   2          1m
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;... nooo!
The thing was at 1&#x2F;1 and now it&#x27;s at 0&#x2F;1 &lt;strong&gt;and&lt;&#x2F;strong&gt; it says &lt;strong&gt;CrashLoopBackOff&lt;&#x2F;strong&gt;.
Numbers going down when they&#x27;re supposed to stay the same is never a good sign, and crashing is almost never what you want.&lt;&#x2F;p&gt;
&lt;p&gt;If I&#x27;ve learned &lt;em&gt;anything&lt;&#x2F;em&gt; about fixing stuff that&#x27;s broke it&#x27;s &lt;em&gt;always check the logs&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl logs po&#x2F;master-4259088255-afsfk
&lt;&#x2F;span&gt;&lt;span&gt;[...]
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 22:31:42+0000 [-] Setting up database with URL &amp;#39;sqlite:&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 22:31:42+0000 [-] The Buildmaster database needs to be upgraded before this version of
&lt;&#x2F;span&gt;&lt;span&gt;[...]
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 22:31:42+0000 [-] BuildMaster startup failed
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 22:31:42+0000 [-] BuildMaster is stopped
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 22:31:42+0000 [-] Main loop terminated.
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 22:31:42+0000 [-] Server Shut Down.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Gross, but probably useful.
How?
Good question:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;I saw the word &lt;code&gt;database&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;We &lt;em&gt;didn&#x27;t&lt;&#x2F;em&gt; deploy a database.&lt;&#x2F;li&gt;
&lt;li&gt;QED let&#x27;s do that.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;add-one-cup-of-postgres-to-the-mix&quot;&gt;Add one cup of Postgres to the mix&lt;&#x2F;h3&gt;
&lt;p&gt;Just like with the &lt;code&gt;master&lt;&#x2F;code&gt; container, we&#x27;re just going to use CLI arguments to get a database running.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl run postgres \
&lt;&#x2F;span&gt;&lt;span&gt;    --image=postgres:9.4\
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;POSTGRES_PASSWORD=change_me&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;POSTGRES_USER=buildbot&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;POSTGRES_DB=buildbot&amp;quot; \
&lt;&#x2F;span&gt;&lt;span&gt;    --env=&amp;quot;BUILDBOT_DB_URL=postgresql+psycopg2:&#x2F;&#x2F;{POSTGRES_USER}:{POSTGRES_PASSWORD}@db&#x2F;{POSTGRES_DB}&amp;quot;\
&lt;&#x2F;span&gt;&lt;span&gt;    --port=5432
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Cross fingers aaand...&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods
&lt;&#x2F;span&gt;&lt;span&gt;NAME                               READY     STATUS             RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;master-4259088255-afsfk            0&#x2F;1       CrashLoopBackOff   6          9m
&lt;&#x2F;span&gt;&lt;span&gt;postgres-2443857112-3ermh          0&#x2F;1       ContainerCreating  0          15s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;&#x2F;me holds breath&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods
&lt;&#x2F;span&gt;&lt;span&gt;NAME                               READY     STATUS             RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;master-4259088255-afsfk            0&#x2F;1       CrashLoopBackOff   6          9m
&lt;&#x2F;span&gt;&lt;span&gt;postgres-2443857112-3ermh          1&#x2F;1       Running            0          54s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Yuss! Wait, for real?&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl logs postgres-2443857112-3ermh
&lt;&#x2F;span&gt;&lt;span&gt;[... hey look a bunch of useful Postgres garbage ...]
&lt;&#x2F;span&gt;&lt;span&gt;PostgreSQL init process complete; ready for start up.
&lt;&#x2F;span&gt;&lt;span&gt;[... some more useful Postgres garbage ...]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Good &#x27;nuff.
Now how does this database plug into the master container?&lt;&#x2F;p&gt;
&lt;p&gt;Well, in the Docker Compose world, containers talked to one-another on a private network with the &lt;code&gt;link&lt;&#x2F;code&gt; directive.
There&#x27;s probably some way to do we do that with K8s right?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;welcome-yaml-config-files-to-the-class&quot;&gt;Welcome YAML config files to the class&lt;&#x2F;h3&gt;
&lt;p&gt;Running Command-Line Interface (CLI) commands is fun, but the easiest way to get this system running seems to be with configuration files.
I&#x27;m sure I &lt;em&gt;can&lt;&#x2F;em&gt; use CLI commands to orchestrate this entire project, but... honestly all the tutorials talk about how to do things in YAML so we&#x27;re doing it in YAML now.&lt;&#x2F;p&gt;
&lt;p&gt;Some research later it looks like declaring a &lt;a href=&quot;http:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;user-guide&#x2F;pods&#x2F;&quot;&gt;Pod&lt;&#x2F;a&gt; is the way to go?
For context, here&#x27;s where I got the idea from the K8s docs:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A pod (as in a pod of whales or pea pod) is a group of one or more containers (such as Docker containers), the shared storage for those containers, and options about how to run the containers.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Well that sounds &lt;em&gt;roughly&lt;&#x2F;em&gt; like what we&#x27;re doing.
I&#x27;ve got some containers, I want them to be able to talk to each other, and they&#x27;re
all logically connected to one another.
Let&#x27;s go down this rabbit hole.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;alice-down.gif&quot; alt=&quot;Alice down the rabbit hole...&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here I have Frankensteined this config &lt;code&gt;buildbot.yaml&lt;&#x2F;code&gt; from examples in the configs:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Pod&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containers&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&#x2F;buildbot-master:master&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containerPort&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8080
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_CONFIG_DIR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_CONFIG_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;buildbot&#x2F;buildbot-docker-example-config&#x2F;archive&#x2F;master.tar.gz&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_WORKER_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;9989&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_WEB_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;http:&#x2F;&#x2F;localhost:8080&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_WEB_PORT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;8080&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_PASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;change_me&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_USER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_DB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_DB_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgresql+psycopg2:&#x2F;&#x2F;{POSTGRES_USER}:{POSTGRES_PASSWORD}@db&#x2F;{POSTGRES_DB}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres:9.4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containerPort&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;5432
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_PASSWORD&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;change_me&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_USER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_DB&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_DB_URL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgresql+psycopg2:&#x2F;&#x2F;{POSTGRES_USER}:{POSTGRES_PASSWORD}@db&#x2F;{POSTGRES_DB}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What happens when we run it?&lt;&#x2F;p&gt;
&lt;p&gt;Well first we need to clean up that CLI-created garbage we were doing
earlier.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl delete deployment master postgres
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;master&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;postgres&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then deploy the new pod:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl create -f buildbot.yaml
&lt;&#x2F;span&gt;&lt;span&gt;pod &amp;quot;buildbot&amp;quot; created
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Aaaand:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods
&lt;&#x2F;span&gt;&lt;span&gt;buildbot   2&#x2F;2       Running   0          23s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;m suspicious...&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl logs po&#x2F;buildbot master
&lt;&#x2F;span&gt;&lt;span&gt;checking basedir
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;usr&#x2F;lib&#x2F;python2.7&#x2F;site-packages&#x2F;buildbot&#x2F;config.py:85: ConfigWarning: [0.9.0 and later] `buildbotNetUsageData` is not configured and defaults to basic
&lt;&#x2F;span&gt;&lt;span&gt;[...]
&lt;&#x2F;span&gt;&lt;span&gt;Failure: sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) could not translate host name &amp;quot;db&amp;quot; to address: Try again
&lt;&#x2F;span&gt;&lt;span&gt;[...]
&lt;&#x2F;span&gt;&lt;span&gt;problem while upgrading!:
&lt;&#x2F;span&gt;&lt;span&gt;Traceback (most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;[... python traceback ...]
&lt;&#x2F;span&gt;&lt;span&gt;OperationalError: (psycopg2.OperationalError) could not translate host name &amp;quot;db&amp;quot; to address: Try again
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Whelp let&#x27;s play &#x27;Where do I fix &lt;em&gt;that&lt;&#x2F;em&gt;?&#x27;&lt;&#x2F;p&gt;
&lt;p&gt;Is the problem in:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;buildbot-master&lt;&#x2F;code&gt; image&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;postgres&lt;&#x2F;code&gt; image&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;code&gt;buildbot.yml&lt;&#x2F;code&gt; file&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If you guessed &lt;strong&gt;c&lt;&#x2F;strong&gt; you would be right so let&#x27;s start in
&lt;code&gt;buildbot.yaml&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Based on my experience with databases, specifically the startup time of database containers like Postgres and MariaDB, I&#x27;d &lt;em&gt;guess&lt;&#x2F;em&gt; that the database was taking too long to start.
After some digging around, I found out that Pods were the entirely wrong way to go. Here&#x27;s how that discovery went:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Q&lt;&#x2F;strong&gt;: Does K8s have anything like docker-compose&#x27;s &lt;code&gt;depends_on:&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;&#x2F;strong&gt;: No.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Q&lt;&#x2F;strong&gt;: Okay, so how... actually, is there anything like what I&#x27;m doing already out there?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;&#x2F;strong&gt;: Yes.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Q&lt;&#x2F;strong&gt;: ... Where?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;&#x2F;strong&gt;: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;kubernetes&#x2F;tree&#x2F;master&#x2F;examples&#x2F;mysql-wordpress-pd&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;kubernetes&#x2F;tree&#x2F;master&#x2F;examples&#x2F;mysql-wordpress-pd&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Q&lt;&#x2F;strong&gt;: Noice. So the &lt;em&gt;Pods&lt;&#x2F;em&gt; thing was the wrong rabbit hole to go down?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;&#x2F;strong&gt;: Right.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Q&lt;&#x2F;strong&gt;: Right like correct or right like...?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;A&lt;&#x2F;strong&gt;: Stop.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;yay-examples&quot;&gt;Yay examples&lt;&#x2F;h3&gt;
&lt;p&gt;So let&#x27;s run that example to make sure it all works fine.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Clone repo&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cd&lt;&#x2F;code&gt; to example&lt;&#x2F;li&gt;
&lt;li&gt;Follow README instructions&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl create -f local-volumes.yaml
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolume &amp;quot;local-pv-1&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolume &amp;quot;local-pv-2&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f mysql-deployment.yaml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;wordpress-mysql&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolumeclaim &amp;quot;mysql-pv-claim&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;wordpress-mysql&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f wordpress-deployment.yaml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;wordpress&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolumeclaim &amp;quot;wp-pv-claim&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;wordpress&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl get all
&lt;&#x2F;span&gt;&lt;span&gt;NAME                  CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
&lt;&#x2F;span&gt;&lt;span&gt;svc&#x2F;kubernetes        10.0.0.1     &amp;lt;none&amp;gt;        443&#x2F;TCP    2h
&lt;&#x2F;span&gt;&lt;span&gt;svc&#x2F;wordpress         10.0.0.28    &amp;lt;pending&amp;gt;     80&#x2F;TCP     5s
&lt;&#x2F;span&gt;&lt;span&gt;svc&#x2F;wordpress-mysql   None         &amp;lt;none&amp;gt;        3306&#x2F;TCP   17s
&lt;&#x2F;span&gt;&lt;span&gt;NAME                                  READY     STATUS              RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;po&#x2F;buildbot                           2&#x2F;2       Running             0          8m
&lt;&#x2F;span&gt;&lt;span&gt;po&#x2F;wordpress-1618093523-4if9k         0&#x2F;1       ContainerCreating   0          5s
&lt;&#x2F;span&gt;&lt;span&gt;po&#x2F;wordpress-mysql-2379610080-mqvll   0&#x2F;1       ContainerCreating   0          17s
&lt;&#x2F;span&gt;&lt;span&gt;NAME                 STATUS    VOLUME       CAPACITY   ACCESSMODES   AGE
&lt;&#x2F;span&gt;&lt;span&gt;pvc&#x2F;mysql-pv-claim   Bound     local-pv-1   20Gi       RWO           17s
&lt;&#x2F;span&gt;&lt;span&gt;pvc&#x2F;wp-pv-claim      Bound     local-pv-2   20Gi       RWO           5s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And I can go to the site?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;wordpress-working.png&quot; alt=&quot;Wordpress working correctly&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Great.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;now-use-the-example&quot;&gt;Now Use the example&lt;&#x2F;h3&gt;
&lt;p&gt;Now we need to morph &lt;code&gt;wordpress-deployment.yaml&lt;&#x2F;code&gt; into &lt;code&gt;postgres.yaml&lt;&#x2F;code&gt;, and &lt;code&gt;wordpress-deployment.yaml&lt;&#x2F;code&gt; into &lt;code&gt;master.yaml&lt;&#x2F;code&gt;
Also, let&#x27;s ignore &lt;code&gt;local-volumes.yaml&lt;&#x2F;code&gt; for now, just to be safe.
Don&#x27;t forget: we&#x27;re not doing anything fancy yet.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;master.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Service
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;port&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8080
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;frontend
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;selector&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;tier&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;NodePort
&lt;&#x2F;span&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Deployment
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;strategy&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Recreate
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;template&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;tier&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containers&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&#x2F;buildbot-master:master
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_CONFIG_DIR
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;config
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_CONFIG_URL
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;buildbot&#x2F;buildbot-docker-example-config&#x2F;master&#x2F;master.cfg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_WORKER_PORT
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;9989&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_WEB_URL
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;http:&#x2F;&#x2F;localhost:8080&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_WEB_PORT
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;8080&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_PASSWORD
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;change_me
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_USER
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_DB
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_DB_HOST
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_DB_URL
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgresql+psycopg2:&#x2F;&#x2F;{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_DB_HOST}&#x2F;{POSTGRES_DB}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containerPort&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;8080
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;frontend
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;postgres.yaml:&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Service
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;port&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;5432
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;selector&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;tier&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;clusterIP&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Deployment
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;strategy&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Recreate
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;template&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;tier&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containers&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres:9.4
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_PASSWORD
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;change_me
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_USER
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_DB
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;POSTGRES_DB_HOST
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDBOT_DB_URL
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgresql+psycopg2:&#x2F;&#x2F;{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_DB_HOST}&#x2F;{POSTGRES_DB}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containerPort&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;5432
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;postgres
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And with a flick of my wand:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl delete pods,deployment,service --all  # cleanup the old stuff
&lt;&#x2F;span&gt;&lt;span&gt;pod &amp;quot;buildbot&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;pod &amp;quot;wordpress-1618093523-4if9k&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;pod &amp;quot;wordpress-mysql-2379610080-mqvll&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;wordpress&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;wordpress-mysql&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;kubernetes&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;wordpress&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;wordpress-mysql&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f postrges.yml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;postgres&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;postgres&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f master.yml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;master&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;master&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ minikube service master
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Opens up this wonderful site:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;buildbot-working.png&quot; alt=&quot;Buildbot working&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Great, they can talk &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#same-app-note&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hire-a-worker&quot;&gt;Hire a worker&lt;&#x2F;h3&gt;
&lt;p&gt;So we&#x27;ve got a website and a database, but we&#x27;re not actually running any builds yet. Let&#x27;s fix that.&lt;&#x2F;p&gt;
&lt;p&gt;Based on what the &lt;code&gt;docker-compose.yml&lt;&#x2F;code&gt; says we should be able to throw this together and have it work:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;worker.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Service
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;port&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;9989
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;selector&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;tier&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;clusterIP&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;None
&lt;&#x2F;span&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Deployment
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;strategy&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Recreate
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;template&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;app&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;tier&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containers&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;      - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;image&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;buildbot&#x2F;buildbot-worker:master&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;env&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDMASTER
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;master
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;BUILDMASTER_PORT
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;9989&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;WORKERNAME
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;example-worker
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;WORKERPASS
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;pass
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;WORKER_ENVIRONMENT_BLACKLIST
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;DOCKER_BUILDBOT* BUILDBOT_ENV_* BUILDBOT_1* WORKER_ENVIRONMENT_BLACKLIST&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;ports&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;        - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;containerPort&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;9989
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;worker
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl create -f worker.yaml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;worker&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;worker&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl get -f worker.yaml
&lt;&#x2F;span&gt;&lt;span&gt;NAME                  CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
&lt;&#x2F;span&gt;&lt;span&gt;svc&#x2F;worker            None         &amp;lt;none&amp;gt;        9989&#x2F;TCP   44s
&lt;&#x2F;span&gt;&lt;span&gt;NAME                     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
&lt;&#x2F;span&gt;&lt;span&gt;deploy&#x2F;worker            1         1         1            0           44s
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Looks promising...&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods -l tier=worker
&lt;&#x2F;span&gt;&lt;span&gt;NAME                               READY     STATUS    RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;worker-3607067131-qdpfd   1&#x2F;1       Running   0          1m
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl logs worker-3607067131-ke4zb -f
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:45+0000 [-] Loading buildbot.tac...
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:45+0000 [-] Loaded.
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:45+0000 [-] twistd 16.5.0 (&#x2F;usr&#x2F;bin&#x2F;python 2.7.12) starting up.
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:45+0000 [-] reactor class: twisted.internet.epollreactor.EPollReactor.  2016-11-21 19:46:45+0000 [-] Starting Worker -- version: latest
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:45+0000 [-] recording hostname in twistd.hostname
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:45+0000 [-] Starting factory &amp;lt;buildbot_worker.pb.BotFactory instance at 0x7fd8c2339cf8&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:45+0000 [-] Connecting to buildbot:9989
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:56+0000 [Uninitialized] Connection to buildbot:9989 failed: Connection Refused
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:56+0000 [Uninitialized] &amp;lt;twisted.internet.tcp.Connector instance at 0x7fd8c233a170&amp;gt; will retry in 2 seconds
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:56+0000 [-] Stopping factory &amp;lt;buildbot_worker.pb.BotFactory instance at 0x7fd8c2339cf8&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:59+0000 [-] Starting factory &amp;lt;buildbot_worker.pb.BotFactory instance at 0x7fd8c2339cf8&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:46:59+0000 [-] Connecting to buildbot:9989
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:47:29+0000 [-] Connection to buildbot:9989 failed: [Failure instance: Traceback (failure with no frames): &amp;lt;class &amp;#39;twisted.internet.error.TimeoutError&amp;#39;&amp;gt;: User timeout caused connection failure.
&lt;&#x2F;span&gt;&lt;span&gt;    ]
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:47:29+0000 [-] &amp;lt;twisted.internet.tcp.Connector instance at 0x7fd8c233a170&amp;gt; will retry in 5 seconds
&lt;&#x2F;span&gt;&lt;span&gt;2016-11-21 19:47:29+0000 [-] Stopping factory &amp;lt;buildbot_worker.pb.BotFactory instance at 0x7fd8c2339cf8&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Khaaaaaan!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;connection-issues&quot;&gt;Connection issues&lt;&#x2F;h3&gt;
&lt;p&gt;Fine, let&#x27;s get to work debugging.
First we&#x27;ll login to the worker pod and try to ping the &lt;code&gt;buildbot&lt;&#x2F;code&gt; pod since the output makes it seem like there was a timeout between the host and the worker.
This usually means they can&#x27;t reach each other.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl exec -it worker-3607067131-qdpfd bash
&lt;&#x2F;span&gt;&lt;span&gt;buildbot@worker-3607067131-qdpfd:&#x2F;buildbot$ ping master
&lt;&#x2F;span&gt;&lt;span&gt;bash: ping: command not found
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Uhh...&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;buildbot@worker-3607067131-ke4zb:&#x2F;buildbot$ curl http:&#x2F;&#x2F;master:8080
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;[... definitely actually a webpage ...]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So the worker can reach the master, but can the master reach the worker?&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods -l tier=master
&lt;&#x2F;span&gt;&lt;span&gt;NAME                                 READY     STATUS    RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;master-2152810066-9ip8b              1&#x2F;1       Running   0          21m
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl exec -it master-2152810066-9ip8b sh
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;var&#x2F;lib&#x2F;buildbot # ping worker
&lt;&#x2F;span&gt;&lt;span&gt;PING worker (172.17.0.6): 56 data bytes
&lt;&#x2F;span&gt;&lt;span&gt;64 bytes from 172.17.0.6: seq=0 ttl=64 time=0.083 ms
&lt;&#x2F;span&gt;&lt;span&gt;64 bytes from 172.17.0.6: seq=1 ttl=64 time=0.101 ms
&lt;&#x2F;span&gt;&lt;span&gt;^C
&lt;&#x2F;span&gt;&lt;span&gt;--- worker ping statistics ---
&lt;&#x2F;span&gt;&lt;span&gt;2 packets transmitted, 2 packets received, 0% packet loss
&lt;&#x2F;span&gt;&lt;span&gt;round-trip min&#x2F;avg&#x2F;max = 0.083&#x2F;0.092&#x2F;0.101 ms
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Okay, so they can connect to one-another.
What&#x27;s the problem then?
My best guess is that the &lt;code&gt;master&lt;&#x2F;code&gt; pod needs to have it&#x27;s special worker port (&lt;code&gt;9989&lt;&#x2F;code&gt;) exposed.
So let&#x27;s add those lines to &lt;code&gt;master.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;updated-master.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;updated-master.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -8,6 +8,8 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;   ports:
&lt;&#x2F;span&gt;&lt;span&gt;     - port: 8080
&lt;&#x2F;span&gt;&lt;span&gt;       name: frontend
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    - port: 9989
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      name: worker
&lt;&#x2F;span&gt;&lt;span&gt;   selector:
&lt;&#x2F;span&gt;&lt;span&gt;     app: buildbot
&lt;&#x2F;span&gt;&lt;span&gt;     tier: master
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -55,3 +57,5 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;         ports:
&lt;&#x2F;span&gt;&lt;span&gt;         - containerPort: 8080
&lt;&#x2F;span&gt;&lt;span&gt;           name: frontend
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        - containerPort: 9989
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          name: worker
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And after tearing everything down and bringing it back up:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods -l tier=worker
&lt;&#x2F;span&gt;&lt;span&gt;NAME                               READY     STATUS    RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;worker-2552724660-l4kmv            1&#x2F;1       Running   0          12s
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl logs worker-2552724660-l4kmv
&lt;&#x2F;span&gt;&lt;span&gt;[... logs logs logs ...]
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 23:30:18+0000 [-] Connecting to master:9989
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 23:30:18+0000 [HangCheckProtocol,client] message from master: attached
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 23:30:18+0000 [HangCheckProtocol,client] message from master: attached
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 23:30:18+0000 [HangCheckProtocol,client] Connected to master:9989; worker is ready
&lt;&#x2F;span&gt;&lt;span&gt;2016-12-09 23:30:18+0000 [HangCheckProtocol,client] sending application-level keepalives every 600 seconds
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hey that looks like success to me!
How does the front-end look?&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get pods -l tier=master
&lt;&#x2F;span&gt;&lt;span&gt;NAME                               READY     STATUS    RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;master-3038604518-jim6q            1&#x2F;1       Running   0          2m
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl port-forward master-3038604518-jim6q 8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And in a browser:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;build-success.png&quot; alt=&quot;Buildbot still working.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You may now do a happy dance.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;happy-dance.gif&quot; alt=&quot;Happy Dance .gif&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;storage&quot;&gt;Storage&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve got the three core moving parts of our system, next on our list is adding some persistent storage.
Thankfully, we can recycle the MySQL+Wordpress example we used before.
Yay examples.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s add the storage bits back in that we ignored before.
This results in configs that look like so (abbreviated for your scrollbar&#x27;s convenience):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;volumes.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;yaml&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;PersistentVolume
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;local-pv-1
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;local
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;capacity&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;storage&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;1Gi
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;accessModes&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;ReadWriteOnce
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;persistentVolumeReclaimPolicy&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Recycle
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;hostPath&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;data&#x2F;pv-1
&lt;&#x2F;span&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;PersistentVolume
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;local-pv-2
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;local
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;capacity&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;storage&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;5Gi
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;accessModes&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;ReadWriteOnce
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;persistentVolumeReclaimPolicy&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Recycle
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;hostPath&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;data&#x2F;pv-2
&lt;&#x2F;span&gt;&lt;span&gt;---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;apiVersion&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;PersistentVolume
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;local-pv-3
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;labels&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;type&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;local
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;spec&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;capacity&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;storage&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;5Gi
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;accessModes&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;ReadWriteOnce
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;persistentVolumeReclaimPolicy&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Recycle
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;hostPath&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;data&#x2F;pv-3
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;master.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;diff --git a&#x2F;blogpost&#x2F;volumes-master.yaml b&#x2F;blogpost&#x2F;volumes-master.yaml
&lt;&#x2F;span&gt;&lt;span&gt;index 7cbffd7..c7479e3 100644
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;volumes-master.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;volumes-master.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -15,6 +15,19 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;     tier: master
&lt;&#x2F;span&gt;&lt;span&gt;   type: NodePort
&lt;&#x2F;span&gt;&lt;span&gt; ---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+apiVersion: v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+kind: PersistentVolumeClaim
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  name: master-pv-claim
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  labels:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    app: buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+spec:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  accessModes:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    - ReadWriteOnce
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  resources:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    requests:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      storage: 1Gi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+---
&lt;&#x2F;span&gt;&lt;span&gt; apiVersion: extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;span&gt; kind: Deployment
&lt;&#x2F;span&gt;&lt;span&gt; metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -37,7 +50,7 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_CONFIG_DIR
&lt;&#x2F;span&gt;&lt;span&gt;           value: config
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_CONFIG_URL
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-          value: &amp;#39;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;buildbot&#x2F;buildbot-docker-example-config&#x2F;master&#x2F;master.cfg&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          value: &amp;#39;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;ElijahCaine&#x2F;buildbot-on-kubernetes&#x2F;master&#x2F;simple&#x2F;master.cfg&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_WORKER_PORT
&lt;&#x2F;span&gt;&lt;span&gt;           value: &amp;#39;9989&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_WEB_URL
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -59,3 +72,10 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;           name: frontend
&lt;&#x2F;span&gt;&lt;span&gt;         - containerPort: 9989
&lt;&#x2F;span&gt;&lt;span&gt;           name: worker
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        volumeMounts:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        - name: master-persistent-storage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          mountPath: &#x2F;var&#x2F;lib&#x2F;buildbot&#x2F;builds
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      volumes:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      - name: master-persistent-storage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        persistentVolumeClaim:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          claimName: master-pv-claim
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;postgres.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;volumes-postgres.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;volumes-postgres.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -13,6 +13,19 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;     tier: postgres
&lt;&#x2F;span&gt;&lt;span&gt;   clusterIP: None
&lt;&#x2F;span&gt;&lt;span&gt; ---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+apiVersion: v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+kind: PersistentVolumeClaim
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  name: postgres-pv-claim
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  labels:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    app: buildbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+spec:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  accessModes:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    - ReadWriteOnce
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  resources:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    requests:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      storage: 5Gi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+---
&lt;&#x2F;span&gt;&lt;span&gt; apiVersion: extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;span&gt; kind: Deployment
&lt;&#x2F;span&gt;&lt;span&gt; metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -45,3 +58,10 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;         ports:
&lt;&#x2F;span&gt;&lt;span&gt;         - containerPort: 5432
&lt;&#x2F;span&gt;&lt;span&gt;           name: postgres
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        volumeMounts:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        - name: postgres-persistent-storage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          mountPath: &#x2F;var&#x2F;lib&#x2F;postgresql
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      volumes:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      - name: postgres-persistent-storage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        persistentVolumeClaim:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          claimName: postgres-pv-claim
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;worker.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;volumes-worker.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;volumes-worker.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -13,6 +13,19 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;     tier: worker
&lt;&#x2F;span&gt;&lt;span&gt;   clusterIP: None
&lt;&#x2F;span&gt;&lt;span&gt; ---
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+apiVersion: v1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+kind: PersistentVolumeClaim
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  name: worker-pv-claim
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  labels:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    app: buidlbot
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+spec:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  accessModes:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    - ReadWriteOnce
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+  resources:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    requests:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      storage: 5Gi
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+---
&lt;&#x2F;span&gt;&lt;span&gt; apiVersion: extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;span&gt; kind: Deployment
&lt;&#x2F;span&gt;&lt;span&gt; metadata:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -45,3 +58,10 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;         ports:
&lt;&#x2F;span&gt;&lt;span&gt;         - containerPort: 9989
&lt;&#x2F;span&gt;&lt;span&gt;           name: worker
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        volumeMounts:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        - name: worker-persistent-storage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          mountPath: &#x2F;buildbot&#x2F;builds
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      volumes:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      - name: worker-persistent-storage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        persistentVolumeClaim:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          claimName: worker-pv-claim
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And of lastly we edit the Buildbot &lt;code&gt;master.cfg&lt;&#x2F;code&gt; to use our custom paths
for storing and carrying out builds:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;diff --git a&#x2F;blogpost&#x2F;volumes-master.cfg b&#x2F;blogpost&#x2F;volumes-master.cfg
&lt;&#x2F;span&gt;&lt;span&gt;index 06ad65b..36212ea 100644
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;volumes-master.cfg
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;volumes-master.cfg
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -78,7 +78,9 @@ c[&amp;#39;builders&amp;#39;] = []
&lt;&#x2F;span&gt;&lt;span&gt; c[&amp;#39;builders&amp;#39;].append(
&lt;&#x2F;span&gt;&lt;span&gt;     util.BuilderConfig(name=&amp;quot;runtests&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;       workernames=[&amp;quot;example-worker&amp;quot;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-      factory=factory))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      factory=factory,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      builddir=&amp;#39;builds&amp;#39;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      workerbuilddir=&amp;#39;builds&amp;#39;))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; ####### STATUS TARGETS
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is just an edited version of the original &lt;code&gt;master.cfg&lt;&#x2F;code&gt; you can find
in the original Buildbot docker-compose example repository.&lt;&#x2F;p&gt;
&lt;p&gt;So this &lt;em&gt;should&lt;&#x2F;em&gt; just work, right?
We request a volume of a given size, the volume exists and is the correct size, badda bing badda boom, do the thing like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl delete service,deployment,pods --all
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;master&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;postgres&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;worker&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;kubernetes&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;master&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;postgres&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;worker&amp;quot; deleted
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f volumes.yaml
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolume &amp;quot;local-pv-1&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolume &amp;quot;local-pv-2&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolume &amp;quot;local-pv-3&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f postgres.yaml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;postgres&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolumeclaim &amp;quot;postgres-pv-claim&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;postgres&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f master.yaml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;master&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolumeclaim &amp;quot;master-pv-claim&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;master&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl create -f worker.yaml
&lt;&#x2F;span&gt;&lt;span&gt;service &amp;quot;-worker&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;persistentvolumeclaim &amp;quot;worker-pv-claim&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;worker&amp;quot; created
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl get pods -l tier=master
&lt;&#x2F;span&gt;&lt;span&gt;NAME                        READY     STATUS    RESTARTS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;master-3176013930-gvy2i   1&#x2F;1       Running   0          1m
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl port-forward master-3176013930-gvy2i 8080
&lt;&#x2F;span&gt;&lt;span&gt;Forwarding from 127.0.0.1:8080 -&amp;gt; 8080
&lt;&#x2F;span&gt;&lt;span&gt;Forwarding from [::1]:8080 -&amp;gt; 8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That kinda works, but it kept getting weird arbitrary errors which
looked suspicious.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;permissions-build-fail.png&quot;
class=&quot;align-center&quot; style=&quot;width:100.0%&quot;
alt=&quot;Permissions fail in buildbot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Since the only thing that had really changed was the volumes I figured I
might as well login to the host and investigate.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ minikube ssh
&lt;&#x2F;span&gt;&lt;span&gt;docker@minikube:~$ ls -alh &#x2F;data&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;total 20
&lt;&#x2F;span&gt;&lt;span&gt;drwxr-xr-x    5 root     root        4.0K Dec 11 02:21 .&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;drwxr-xr-x    6 root     root        4.0K Dec 11 01:48 ..&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;drwxr-xr-x    2 root     root        4.0K Dec 11 02:20 pv-1&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;drwxr-xr-x    2 root     root        4.0K Dec 11 02:33 pv-2&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;drwxr-xr-x    3 root     root        4.0K Dec 11 02:33 pv-3&#x2F;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ahah!
That&#x27;s the problem, root owns everything but the builds are run by the &lt;code&gt;buildbot&lt;&#x2F;code&gt; user (&lt;code&gt;uid: 1000&lt;&#x2F;code&gt;) &lt;em&gt;&#x2F;me shakes fist at permissions errors.&lt;&#x2F;em&gt;
The last first place you think to look.&lt;&#x2F;p&gt;
&lt;p&gt;So is there any way to change the permissions of a volume as you claim it (i.e., in &lt;code&gt;volumes.yaml&lt;&#x2F;code&gt;)?
We can both go through this journey together or I can share with you a quote from my coworker Barak Michener, the BAMF that works on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;coreos&#x2F;torus&quot;&gt;Torus&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Barak Michener&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;yeah, hostPath is completely hands-off from k8s perspective
so you just chmod the underlying dir
to whatever uid you&#x27;re using inside the pod&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Turns out the problem was with my &lt;code&gt;type&lt;&#x2F;code&gt; of storage in &lt;code&gt;volumes.yaml&lt;&#x2F;code&gt;.
As of yet there is no type-agnostic way to assign permissions for mounted volumes.
Storage, why you gotta be like that?&lt;&#x2F;p&gt;
&lt;p&gt;So after digging around and asking Barak I finally concluded that I had to had to login to my host and set the correct permissions on the directories being reserved.
Here&#x27;s how you do that on Minikube:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ minikube ssh
&lt;&#x2F;span&gt;&lt;span&gt;docker@minikube$ sudo chown -R 1000:1000 &#x2F;data&#x2F;pv*
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case we could just chown the one volume that&#x27;s going to be used by the &lt;code&gt;worker&lt;&#x2F;code&gt; pod, since the other ones run their services as &lt;code&gt;root&lt;&#x2F;code&gt;, but much like Debra from accounting, &lt;code&gt;root&lt;&#x2F;code&gt; doesn&#x27;t give a fuck.
Might as well.&lt;&#x2F;p&gt;
&lt;p&gt;So if we try the build again with the correct permissions, what happens?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;build-success-perms.png&quot; alt=&quot;Buildbot with permissions fixed&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Huzah&lt;&#x2F;p&gt;
&lt;h2 id=&quot;autoscaling&quot;&gt;Autoscaling&lt;&#x2F;h2&gt;
&lt;p&gt;At last we have what I suspect will be the &lt;em&gt;hardest&lt;&#x2F;em&gt; part of the project: autoscaling.
Here&#x27;s what we want in a perfect world:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;When a lot of builds get requested, spin up more &lt;code&gt;worker&lt;&#x2F;code&gt; nodes.&lt;&#x2F;li&gt;
&lt;li&gt;When fewer builds are requested, destroy those extra &lt;code&gt;worker&lt;&#x2F;code&gt; nodes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;asking-the-question&quot;&gt;Asking the question&lt;&#x2F;h3&gt;
&lt;p&gt;This task is actually a pretty tough cookie to crack.
We want enough workers to each deal with 1&#x2F;N requests in a queue of N builds, essentially scaling the building service to deal with usage spikes.
It sounds straight forward enough, but how do we test it?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;creating-a-test-case&quot;&gt;Creating a test-case&lt;&#x2F;h3&gt;
&lt;p&gt;For this we need to add a few projects to our instance of Buildbot, each of which will have a hefty workload.
To do this we need to host a Buildbot &lt;code&gt;master.cfg&lt;&#x2F;code&gt; config file at some public location and refer to this in the &lt;code&gt;master.yaml&lt;&#x2F;code&gt; config file.
I used the GitHub repo that accompanies this blogpost &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#accompanying-repo&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but you could use GitHub Gists or a pastebin; just make sure you&#x27;re referring to the &lt;strong&gt;raw&lt;&#x2F;strong&gt; file or a &lt;code&gt;.tar.gz&lt;&#x2F;code&gt; with the &lt;code&gt;master.cfg&lt;&#x2F;code&gt; file at the base of the tarball.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s pull a project out of a hat that takes a while to build, how about... &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo&quot;&gt;Cargo&lt;&#x2F;a&gt;.
Any objections?
Great, let&#x27;s roll.&lt;&#x2F;p&gt;
&lt;p&gt;To get started we&#x27;ll need a custom &lt;code&gt;worker&lt;&#x2F;code&gt; container can build Cargo.
A small adventure later and we have this Dockerfile which has all of the dependencies to build what we want:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;FROM buildbot&#x2F;buildbot-worker:master
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;RUN curl https:&#x2F;&#x2F;sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly
&lt;&#x2F;span&gt;&lt;span&gt;RUN echo &amp;#39;PATH=$PATH:$HOME&#x2F;.cargo&#x2F;bin&amp;#39; &amp;gt;&amp;gt; $HOME&#x2F;.bashrc
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;USER root
&lt;&#x2F;span&gt;&lt;span&gt;RUN apt update -y
&lt;&#x2F;span&gt;&lt;span&gt;RUN apt install -y cmake pkg-config
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;USER buildbot
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I set this to auto-build on &lt;a href=&quot;https:&#x2F;&#x2F;quay.io&#x2F;&quot;&gt;quay.io&lt;&#x2F;a&gt;, hosted at the docker-pull url &lt;code&gt;quay.io&#x2F;elijahcaine&#x2F;buidlbot-rust-worker&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have a capable worker container, we need to create an arbitrary workload.
To do that we&#x27;ll use this Buildbot &lt;code&gt;master.cfg&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;diff --git a&#x2F;blogpost&#x2F;robust-master.cfg b&#x2F;blogpost&#x2F;robust-master.cfg
&lt;&#x2F;span&gt;&lt;span&gt;index 06ad65b..892188b 100644
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;robust-master.cfg
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;robust-master.cfg
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -18,7 +18,7 @@ c = BuildmasterConfig = {}
&lt;&#x2F;span&gt;&lt;span&gt; # a Worker object, specifying a unique worker name and password.  The same
&lt;&#x2F;span&gt;&lt;span&gt; # worker name and password must be configured on the worker.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-c[&amp;#39;workers&amp;#39;] = [worker.Worker(&amp;quot;example-worker&amp;quot;, &amp;#39;pass&amp;#39;)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+c[&amp;#39;workers&amp;#39;] = [worker.Worker(&amp;quot;rust-worker&amp;quot;, &amp;#39;pass&amp;#39;)]
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; if &amp;#39;BUILDBOT_MQ_URL&amp;#39; in os.environ:
&lt;&#x2F;span&gt;&lt;span&gt;     c[&amp;#39;mq&amp;#39;] = {
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -43,7 +43,7 @@ c[&amp;#39;protocols&amp;#39;] = {&amp;#39;pb&amp;#39;: {&amp;#39;port&amp;#39;: os.environ.get(&amp;quot;BUILDBOT_WORKER_PORT&amp;quot;, 9989)}}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; c[&amp;#39;change_source&amp;#39;] = []
&lt;&#x2F;span&gt;&lt;span&gt; c[&amp;#39;change_source&amp;#39;].append(changes.GitPoller(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-        &amp;#39;git:&#x2F;&#x2F;github.com&#x2F;buildbot&#x2F;pyflakes.git&amp;#39;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        &amp;#39;git:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo.git&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;         workdir=&amp;#39;gitpoller-workdir&amp;#39;, branch=&amp;#39;master&amp;#39;,
&lt;&#x2F;span&gt;&lt;span&gt;         pollinterval=300))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -57,10 +57,10 @@ c[&amp;#39;schedulers&amp;#39;].append(schedulers.SingleBranchScheduler(
&lt;&#x2F;span&gt;&lt;span&gt;                             name=&amp;quot;all&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;                             change_filter=util.ChangeFilter(branch=&amp;#39;master&amp;#39;),
&lt;&#x2F;span&gt;&lt;span&gt;                             treeStableTimer=None,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-                            builderNames=[&amp;quot;runtests&amp;quot;]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+                            builderNames=[&amp;quot;cargo1-runtests&amp;quot;, &amp;quot;cargo2-runtests&amp;quot;, &amp;quot;cargo3-runtests&amp;quot;]))
&lt;&#x2F;span&gt;&lt;span&gt; c[&amp;#39;schedulers&amp;#39;].append(schedulers.ForceScheduler(
&lt;&#x2F;span&gt;&lt;span&gt;                             name=&amp;quot;force&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-                            builderNames=[&amp;quot;runtests&amp;quot;]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+                            builderNames=[&amp;quot;cargo1-runtests&amp;quot;, &amp;quot;cargo2-runtests&amp;quot;, &amp;quot;cargo3-runtests&amp;quot;]))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; ####### BUILDERS
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -68,17 +68,30 @@ c[&amp;#39;schedulers&amp;#39;].append(schedulers.ForceScheduler(
&lt;&#x2F;span&gt;&lt;span&gt; # what steps, and which workers can execute them.  Note that any particular build will
&lt;&#x2F;span&gt;&lt;span&gt; # only take place on one worker.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-factory = util.BuildFactory()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-# check out the source
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-factory.addStep(steps.Git(repourl=&amp;#39;http:&#x2F;&#x2F;github.com&#x2F;buildbot&#x2F;pyflakes.git&amp;#39;, mode=&amp;#39;incremental&amp;#39;))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-# run the tests (note that this will require that &amp;#39;trial&amp;#39; is installed)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-factory.addStep(steps.ShellCommand(command=[&amp;quot;trial&amp;quot;, &amp;quot;pyflakes&amp;quot;]))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+f = {}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+f[&amp;#39;cargo&amp;#39;] = util.BuildFactory()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+f[&amp;#39;cargo&amp;#39;].addStep(steps.Git(repourl=&amp;#39;git:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;cargo.git&amp;#39;, mode=&amp;#39;full&amp;#39;, method=&amp;#39;fresh&amp;#39;))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+f[&amp;#39;cargo&amp;#39;].addStep(steps.ShellCommand(command=[&amp;quot;&#x2F;home&#x2F;buildbot&#x2F;.cargo&#x2F;bin&#x2F;cargo&amp;quot;, &amp;quot;build&amp;quot;, &amp;quot;--release&amp;quot;]))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; c[&amp;#39;builders&amp;#39;] = []
&lt;&#x2F;span&gt;&lt;span&gt; c[&amp;#39;builders&amp;#39;].append(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-    util.BuilderConfig(name=&amp;quot;runtests&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-      workernames=[&amp;quot;example-worker&amp;quot;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-      factory=factory))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    util.BuilderConfig(name=&amp;quot;cargo1-runtests&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      workernames=[&amp;quot;rust-worker&amp;quot;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      factory=f[&amp;#39;cargo&amp;#39;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      builddir=&amp;#39;builds&#x2F;cargo1&amp;#39;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      workerbuilddir=&amp;#39;builds&#x2F;cargo1&amp;#39;))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+c[&amp;#39;builders&amp;#39;].append(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    util.BuilderConfig(name=&amp;quot;cargo2-runtests&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      workernames=[&amp;quot;rust-worker&amp;quot;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      factory=f[&amp;#39;cargo&amp;#39;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      builddir=&amp;#39;builds&#x2F;cargo2&amp;#39;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      workerbuilddir=&amp;#39;builds&#x2F;cargo2&amp;#39;))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+c[&amp;#39;builders&amp;#39;].append(
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+    util.BuilderConfig(name=&amp;quot;cargo3-runtests&amp;quot;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      workernames=[&amp;quot;rust-worker&amp;quot;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      factory=f[&amp;#39;cargo&amp;#39;],
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      builddir=&amp;#39;builds&#x2F;cargo3&amp;#39;,
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      workerbuilddir=&amp;#39;builds&#x2F;cargo3&amp;#39;))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; ####### STATUS TARGETS
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -93,8 +106,8 @@ c[&amp;#39;status&amp;#39;] = []
&lt;&#x2F;span&gt;&lt;span&gt; # the &amp;#39;title&amp;#39; string will appear at the top of this buildbot installation&amp;#39;s
&lt;&#x2F;span&gt;&lt;span&gt; # home pages (linked to the &amp;#39;titleURL&amp;#39;).
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-c[&amp;#39;title&amp;#39;] = &amp;quot;Pyflakes&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-c[&amp;#39;titleURL&amp;#39;] = &amp;quot;https:&#x2F;&#x2F;launchpad.net&#x2F;pyflakes&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+c[&amp;#39;title&amp;#39;] = &amp;quot;Rusty Stuffy&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+c[&amp;#39;titleURL&amp;#39;] = &amp;quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;en-US&#x2F;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; # the &amp;#39;buildbotURL&amp;#39; string should point to the location where the buildbot&amp;#39;s
&lt;&#x2F;span&gt;&lt;span&gt; # internal web server is visible. This typically uses the port number set in
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And deploy it with this &lt;code&gt;master.yaml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;diff --git a&#x2F;blogpost&#x2F;robust-master.yaml b&#x2F;blogpost&#x2F;robust-master.yaml
&lt;&#x2F;span&gt;&lt;span&gt;index c7479e3..f75b4d6 100644
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;robust-master.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;robust-master.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -50,7 +50,7 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_CONFIG_DIR
&lt;&#x2F;span&gt;&lt;span&gt;           value: config
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_CONFIG_URL
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-          value: &amp;#39;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;ElijahCaine&#x2F;buildbot-on-kubernetes&#x2F;master&#x2F;simple&#x2F;master.cfg&amp;#39;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          value: &amp;#39;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;ElijahCaine&#x2F;buildbot-on-kubernetes&#x2F;master&#x2F;robust&#x2F;master.cfg&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_WORKER_PORT
&lt;&#x2F;span&gt;&lt;span&gt;           value: &amp;#39;9989&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDBOT_WEB_URL
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we look at our setup in Buildbot it looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;ample-workload.png&quot; alt=&quot;Buildbot wih ample workload&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When each build is run it completely wipes away the old git clone and starts from scratch, which is &lt;em&gt;suuuper&lt;&#x2F;em&gt; wasteful, but exactly what we want here.
The purpose of this test is to create a heavy workload for our nodes to perform, and with this each build will &lt;em&gt;definitely&lt;&#x2F;em&gt; be heavy.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kubectl-autoscale&quot;&gt;kubectl autoscale&lt;&#x2F;h3&gt;
&lt;p&gt;Now to start scaling that build.
In a perfect world we&#x27;d get a request, that would start hogging our resources, and K8s would spin up a new worker instance to handle the next build in the queue.
Based on the output of &lt;code&gt;kubectl --help&lt;&#x2F;code&gt; it looks like &lt;code&gt;kubectl autoscale deployment worker&lt;&#x2F;code&gt; is the command we want... so let&#x27;s do that:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl autoscale deployment worker --max=5 --min=1 --cpu-percent=50
&lt;&#x2F;span&gt;&lt;span&gt;deployment &amp;quot;worker&amp;quot; autoscaled
&lt;&#x2F;span&gt;&lt;span&gt;$ kubectl describe hpa
&lt;&#x2F;span&gt;&lt;span&gt;Name:               worker
&lt;&#x2F;span&gt;&lt;span&gt;Namespace:          default
&lt;&#x2F;span&gt;&lt;span&gt;Labels:             &amp;lt;none&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;Annotations:            &amp;lt;none&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;CreationTimestamp:      Fri, 09 Dec 2016 11:13:15 -0800
&lt;&#x2F;span&gt;&lt;span&gt;Reference:          Deployment&#x2F;worker
&lt;&#x2F;span&gt;&lt;span&gt;Target CPU utilization:     50%
&lt;&#x2F;span&gt;&lt;span&gt;Current CPU utilization:    &amp;lt;unset&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;Min replicas:           1
&lt;&#x2F;span&gt;&lt;span&gt;Max replicas:           5
&lt;&#x2F;span&gt;&lt;span&gt;Events:
&lt;&#x2F;span&gt;&lt;span&gt;  FirstSeen LastSeen    Count   From                SubobjectPath   Type        Reason          Message
&lt;&#x2F;span&gt;&lt;span&gt;  --------- --------    -----   ----                -------------   --------    ------          -------
&lt;&#x2F;span&gt;&lt;span&gt;  37s       11s     6   {horizontal-pod-autoscaler }            Warning     FailedGetMetrics    failed to get CPU consumption and request: failed to get pods metrics: the server could not find the requested resource (get services http:heapster:)
&lt;&#x2F;span&gt;&lt;span&gt;  37s       11s     6   {horizontal-pod-autoscaler }            Warning     FailedComputeReplicas   failed to get CPU utilization: failed to get CPU consumption and request: failed to get pods metrics: the server could not find the requested resource (get services http:heapster:)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hmm... that output looks like things aren&#x27;t working.
Let&#x27;s look around the internet and see if we find anything useful.
I&#x27;ll go East, you go West, and we&#x27;ll meet back here in 20.&lt;&#x2F;p&gt;
&lt;p&gt;Great, what did you find? Me? Oh I found a bunch of Github issues &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#hpa-gh&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and Stack Overflow posts &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#hpa-so&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;; lot of people mentioned this Heapster thing.
The &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;heapster&quot;&gt;Heapster GitHub page&lt;&#x2F;a&gt; says it does &lt;em&gt;Compute Resource Usage Analysis and Monitoring of Container Clusters&lt;&#x2F;em&gt;, which sounds like what we want.
I also found the &lt;a href=&quot;http:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;user-guide&#x2F;horizontal-pod-autoscaling&#x2F;&quot;&gt;K8s Autoscaling&lt;&#x2F;a&gt; docs that point to a &lt;a href=&quot;http:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;user-guide&#x2F;horizontal-pod-autoscaling&#x2F;&quot;&gt;K8s Autoscaling Tutorial&lt;&#x2F;a&gt;.
That sounds super useful and confirms the suspicion that Heapster is useful.
&lt;strong&gt;TLDR&lt;&#x2F;strong&gt; things are pointing toward setting up Heapster.&lt;&#x2F;p&gt;
&lt;p&gt;As it turns out there is a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;minikube&#x2F;blob&#x2F;master&#x2F;README.md#add-ons&quot;&gt;Heapster addon for Minikube&lt;&#x2F;a&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#heapster-release&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, so let&#x27;s get that setup.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ minikube addons enable heapster
&lt;&#x2F;span&gt;&lt;span&gt;heapster was successfully enabled
&lt;&#x2F;span&gt;&lt;span&gt;$ minikube addons open heapster
&lt;&#x2F;span&gt;&lt;span&gt;Opening kubernetes service kube-system&#x2F;monitoring-grafana in default browser...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;hello-heapster.png&quot; alt=&quot;Heapster working&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Neato!&lt;&#x2F;p&gt;
&lt;p&gt;So now we&#x27;ve got Heapster running, what&#x27;s next?&lt;&#x2F;p&gt;
&lt;p&gt;Well the tutorial runs this line:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl run php-apache --image=gcr.io&#x2F;google_containers&#x2F;hpa-example --requests=cpu=200m --expose --port=80
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which we can appropriate to get some YAML to shove in our &lt;code&gt;worker.yaml&lt;&#x2F;code&gt; to get a good template for our Buildbot worker Deployment.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl run test --image=busybox --requests=cpu=200m -o yaml
&lt;&#x2F;span&gt;&lt;span&gt;apiVersion: extensions&#x2F;v1beta1
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;spec:
&lt;&#x2F;span&gt;&lt;span&gt;  ...
&lt;&#x2F;span&gt;&lt;span&gt;  template:
&lt;&#x2F;span&gt;&lt;span&gt;    ...
&lt;&#x2F;span&gt;&lt;span&gt;    spec:
&lt;&#x2F;span&gt;&lt;span&gt;      containers:
&lt;&#x2F;span&gt;&lt;span&gt;      - args:
&lt;&#x2F;span&gt;&lt;span&gt;        ...
&lt;&#x2F;span&gt;&lt;span&gt;        resources:
&lt;&#x2F;span&gt;&lt;span&gt;          requests:
&lt;&#x2F;span&gt;&lt;span&gt;            cpu: 200m
&lt;&#x2F;span&gt;&lt;span&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So I added that section to &lt;code&gt;worker.yaml&lt;&#x2F;code&gt;...&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span&gt;diff --git a&#x2F;blogpost&#x2F;robust-worker.yaml b&#x2F;blogpost&#x2F;robust-worker.yaml
&lt;&#x2F;span&gt;&lt;span&gt;index e57db12..de52320 100644
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;--- a&#x2F;blogpost&#x2F;robust-worker.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;+++ b&#x2F;blogpost&#x2F;robust-worker.yaml
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#75715e;&quot;&gt;@@ -42,15 +42,18 @@ spec:
&lt;&#x2F;span&gt;&lt;span&gt;         tier: worker
&lt;&#x2F;span&gt;&lt;span&gt;     spec:
&lt;&#x2F;span&gt;&lt;span&gt;       containers:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-      - image: &amp;quot;buildbot&#x2F;buildbot-worker:master&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+      - image: &amp;quot;quay.io&#x2F;elijahcaine&#x2F;buildbot-rust-worker:master&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;         name: worker
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+        resources:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          requests:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+            cpu: 200m
&lt;&#x2F;span&gt;&lt;span&gt;         env:
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDMASTER
&lt;&#x2F;span&gt;&lt;span&gt;           value: master
&lt;&#x2F;span&gt;&lt;span&gt;         - name: BUILDMASTER_PORT
&lt;&#x2F;span&gt;&lt;span&gt;           value: &amp;#39;9989&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;         - name: WORKERNAME
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f92672;&quot;&gt;-          value: example-worker
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a6e22e;&quot;&gt;+          value: rust-worker
&lt;&#x2F;span&gt;&lt;span&gt;         - name: WORKERPASS
&lt;&#x2F;span&gt;&lt;span&gt;           value: pass
&lt;&#x2F;span&gt;&lt;span&gt;         - name: WORKER_ENVIRONMENT_BLACKLIST
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;... and ran &lt;code&gt;kubectl replace -f worker.yaml&lt;&#x2F;code&gt;, but did it work?
Well, if you&#x27;re impatient like me you&#x27;ll keep refreshing, it won&#x27;t look like it&#x27;s working, and then you&#x27;ll pull your hair out.
If that happens to you, just wait.
Wait like... a minute.
Just get some tea, stare out the window for a second, &lt;em&gt;then&lt;&#x2F;em&gt; see if it worked or not.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ kubectl get hpa worker
&lt;&#x2F;span&gt;&lt;span&gt;NAME              REFERENCE                    TARGET    CURRENT   MINPODS   MAXPODS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;worker            Deployment&#x2F;worker            50%       0%        1         5         2m
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There.
That looks good.
Let&#x27;s throw some work at it!&lt;&#x2F;p&gt;
&lt;p&gt;A few builds:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;NAME              REFERENCE                    TARGET    CURRENT   MINPODS   MAXPODS   AGE
&lt;&#x2F;span&gt;&lt;span&gt;worker            Deployment&#x2F;worker            50%       536%      1         5         6m
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Great!
Let&#x27;s check up on Buildbot:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;replicas-didnt-work.png&quot; alt=&quot;replication failing&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ruh-roh that&#x27;s not good...&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s dig in a bit.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;failed-build.png&quot; alt=&quot;replication failing -- zoom, enhance&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s not good...&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;[... end of git pull ...]
&lt;&#x2F;span&gt;&lt;span&gt;75  security_updates_as_of=2016-10-07
&lt;&#x2F;span&gt;&lt;span&gt;76  using PTY: False
&lt;&#x2F;span&gt;&lt;span&gt;77  Cloning into &amp;#39;.&amp;#39;...
&lt;&#x2F;span&gt;&lt;span&gt;78
&lt;&#x2F;span&gt;&lt;span&gt;79  command interrupted, attempting to kill
&lt;&#x2F;span&gt;&lt;span&gt;80  process killed by signal 15
&lt;&#x2F;span&gt;&lt;span&gt;81  program finished with exit code -1
&lt;&#x2F;span&gt;&lt;span&gt;82  elapsedTime=2.051445
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre style=&quot;background-color:#191919;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;[... entirety of &amp;#39;cancelled&amp;#39; logs ...]
&lt;&#x2F;span&gt;&lt;span&gt;0  no reason
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Well, it looks like that plan didn&#x27;t work.&lt;&#x2F;p&gt;
&lt;p&gt;I did a bit more digging and I can say with certainty that the approach I took to scaling the workload did &lt;em&gt;not&lt;&#x2F;em&gt; work.
I can&#x27;t say &lt;em&gt;why&lt;&#x2F;em&gt; for sure, and I definitely can&#x27;t say how to fix it, but honestly... it&#x27;s late.
I&#x27;m tired and right now I&#x27;m okay with throwing in the towel for now.
Maybe we&#x27;ll solve this in a &lt;strong&gt;Part 2&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;debrief&quot;&gt;Debrief&lt;&#x2F;h2&gt;
&lt;blockquote&gt;
&lt;p&gt;First: This blogpost has a repo associated with it: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elijahcaine&#x2F;buildbot-on-kubernetes&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;elijahcaine&#x2F;buildbot-on-kubernetes&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Please check that out, see what it has to offer, and make issues&#x2F;pull requests.
Right now it&#x27;s just a copy of the configs used in this project and a little bit of documentation.&lt;&#x2F;p&gt;
&lt;p&gt;Happy hacking!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I&#x27;m terrible at endings so I&#x27;m just gonna braindump some stuff here and let you, the beautiful and charming reader, find your own closure from all of this.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;failure-its-what-s-on-the-menu&quot;&gt;Failure: its what&#x27;s on the menu&lt;&#x2F;h3&gt;
&lt;p&gt;That&#x27;s right, I didn&#x27;t do what I set out to achieve.
Is that a bad thing?
&lt;strong&gt;Of course not!&lt;&#x2F;strong&gt; To quote the great Jake the Dog:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;buildbot-on-k8s&#x2F;sucking-quote.jpg&quot; alt=&quot;Sucking at something is the first step to being kinda good at something&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sure we didn&#x27;t get the &lt;em&gt;perfect&lt;&#x2F;em&gt; BuildBot+K8s but we learned a ton and got &lt;em&gt;really&lt;&#x2F;em&gt; close!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;some-stuff-we-learned&quot;&gt;Some stuff we learned&lt;&#x2F;h3&gt;
&lt;p&gt;So what are some things we learned that we should probably write down?
This is a pretty open question and if you followed along you&#x27;ll &lt;em&gt;probably&lt;&#x2F;em&gt; get a drastically different list than I have.
Here&#x27;s the big things I feel like I&#x27;m walking away with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl &amp;lt;command&amp;gt; --dry-run -o yaml&lt;&#x2F;code&gt; is very useful for file-izing your infrastructure.&lt;&#x2F;li&gt;
&lt;li&gt;K8s is very well documented &lt;strong&gt;if&lt;&#x2F;strong&gt; you are a very patient individual.&lt;&#x2F;li&gt;
&lt;li&gt;Storage in K8s is still not a perfectly solved problem [^storage].&lt;&#x2F;li&gt;
&lt;li&gt;K8s applications share private networking.&lt;&#x2F;li&gt;
&lt;li&gt;K8s Pods are really just containers.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I&#x27;m sure there&#x27;s a ton more I&#x27;ve internalized and can&#x27;t recall.
I tried to take thorough notes during this entire experience to capture the failures as well as the successes, which is a harder skill than I expected.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;useful-resources&quot;&gt;Useful resources&lt;&#x2F;h3&gt;
&lt;p&gt;Beyond searching for specific answers these are &lt;em&gt;honestly&lt;&#x2F;em&gt; the websites I kept going back to throughout this project.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;&quot;&gt;http:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;&lt;&#x2F;a&gt; The main K8s docs.
A bit dense and sparse in key areas, a problem I&#x27;m actively I&#x27;m working on.
Includes API docs and user-guides which are useful for those patient enough to read them.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;k8s.info&#x2F;&quot;&gt;http:&#x2F;&#x2F;k8s.info&#x2F;&lt;&#x2F;a&gt; A community-run resource with some useful links and a &#x27;cheat sheet&#x27;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;community&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;community&lt;&#x2F;a&gt; Includes a bunch of very useful design documentation.
I&#x27;m not usually the kind of person that enjoys reading design docs, but sometimes a feature is too new to have a usable user-guide.
When it&#x27;s the best you&#x27;ve got, take it.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As far as Buildbot-specific stuff I honestly just used the &lt;a href=&quot;https:&#x2F;&#x2F;docs.buildbot.net&#x2F;current&#x2F;&quot;&gt;official Buildbot docs&lt;&#x2F;a&gt; which were more than enough.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;whats-next&quot;&gt;Whats next?&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;m sure I&#x27;ll be posting more about K8s going forward.
It is a very useful tool because of&#x2F;despite it&#x27;s complexities.
As I use it I&#x27;ll post more about it.&lt;&#x2F;p&gt;
&lt;p&gt;If you have any feedback on this post feel free to get in contact with me &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;pastywhitenoise&quot;&gt;@PastyWhiteNoise&lt;&#x2F;a&gt; on Twitter, &lt;code&gt;pop&lt;&#x2F;code&gt; on &lt;a href=&quot;https:&#x2F;&#x2F;webchat.freenode.net&#x2F;&quot;&gt;irc.freenode.net&lt;&#x2F;a&gt; &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#irc&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, you can make an issue on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elijahcaine&#x2F;elijahcaine.github.io&quot;&gt;this website&#x27;s Github Repository&lt;&#x2F;a&gt;, and of course I can be reached by Carrier Pigeon..&lt;&#x2F;p&gt;
&lt;h2 id=&quot;errata&quot;&gt;Errata&lt;&#x2F;h2&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;GIFEE&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;Google Infrastructure for Everyone Else&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;accompanying-repo&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ElijahCaine&#x2F;buildbot-on-kubernetes&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;ElijahCaine&#x2F;buildbot-on-kubernetes&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;docs-should&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;My job, at least a big part of it, is writing documentation.
Docs are a notable part of my identify, and I have a belief in the power of good documentation, but at the end of the day they &lt;strong&gt;are&lt;&#x2F;strong&gt; just a means to an end.&lt;&#x2F;p&gt;
&lt;p&gt;In a perfect world docs wouldn&#x27;t &lt;em&gt;need&lt;&#x2F;em&gt; to exist, so all docs should be enough to get whoever&#x27;s readin them to the point where they can do cool shit on their own.
Just like a great cinematographer is so good you don&#x27;t notice the camera in a movie, great docs should be so good you don&#x27;t &lt;strong&gt;notice&lt;&#x2F;strong&gt; how good they are.&lt;&#x2F;p&gt;
&lt;p&gt;So that&#x27;s why I like &lt;strong&gt;doing&lt;&#x2F;strong&gt; cool shit over &lt;strong&gt;reading&lt;&#x2F;strong&gt; about it.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s also fun to play with toys! Even if those toys are software.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;heapster-release&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;Authors Note: The heapster addon was added to Minikube &lt;strong&gt;during the writing of this post&lt;&#x2F;strong&gt;. How convenient!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hpa-gh&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;openshift&#x2F;origin&#x2F;issues&#x2F;6239&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;openshift&#x2F;origin&#x2F;issues&#x2F;6239&lt;&#x2F;a&gt; - &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;kubernetes&#x2F;issues&#x2F;18652&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;kubernetes&#x2F;kubernetes&#x2F;issues&#x2F;18652&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hpa-so&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;38874145&#x2F;autoscaling-hpa-failed-to-get-cpu-consumption-cannot-unmarshal-object-into-go&quot;&gt;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;38874145&#x2F;autoscaling-hpa-failed-to-get-cpu-consumption-cannot-unmarshal-object-into-go&lt;&#x2F;a&gt; - &lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;37631008&#x2F;kubernetes-hpa-cannot-get-cpu-consumption&quot;&gt;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;37631008&#x2F;kubernetes-hpa-cannot-get-cpu-consumption&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;irc&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;I usually hang out in the &lt;code&gt;#osu-lug&lt;&#x2F;code&gt; channel. They&#x27;re cool people, you should hang out with us!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;same-app-note&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;It wasn&#x27;t painfully obvious to me so it&#x27;s worth elaborating that for K8s services to communicate with one-another they need to be part of the same &lt;code&gt;app&lt;&#x2F;code&gt;. In the example the &lt;code&gt;postgres&lt;&#x2F;code&gt;, &lt;code&gt;worker&lt;&#x2F;code&gt;, and &lt;code&gt;master&lt;&#x2F;code&gt; containers are all part of the same &lt;code&gt;buildbot&lt;&#x2F;code&gt; app.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s not a terribly well documented &lt;strong&gt;key&lt;&#x2F;strong&gt; piece of information so it
seemed worth mentioning.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;storge&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;But neither is storage in general so who can blame &#x27;em?&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;theory-vs-practice&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;If you read that and thought &quot;You know what they say about theory versus
practice!&quot; then &lt;em&gt;yes&lt;&#x2F;em&gt; -- but you&#x27;re getting ahead of me.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;why&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;Might as well clarify &lt;em&gt;why&lt;&#x2F;em&gt; we want persistent storage and auto-scaling
since these are usually desired features in an orchestrator but nobody
explains &lt;em&gt;why&lt;&#x2F;em&gt; they&#x27;re desireable.&lt;&#x2F;p&gt;
&lt;p&gt;Autoscaling:
Autoscaling is important is because we&#x27;ve got a whole data-center (in
theory) and we want to maximize how we use that data-center&#x27;s
computational abilities. In a perfect world we would use exactly as much
of the data-center as is demanded by users, but in practice this is
super hard!&lt;&#x2F;p&gt;
&lt;p&gt;Say your website gets linked on Hacker News, you get tons of requests
pouring in, but your poor little 2004 server falls on it&#x27;s face when you
&lt;em&gt;look&lt;&#x2F;em&gt; at it wrong, and &lt;strong&gt;that&lt;&#x2F;strong&gt; is where the exact page was hosted. If
you don&#x27;t &lt;strong&gt;know&lt;&#x2F;strong&gt; that server fell down you&#x27;ll never fix the problem or
even &lt;strong&gt;know&lt;&#x2F;strong&gt; about the problem.&lt;&#x2F;p&gt;
&lt;p&gt;With an orchestrator we can (in theory) specify how much we want to
utilize a our data-center&#x27;s resources and under what conditions we want
to use more or less resources. If our service is creating a light load,
only have one container up; if it&#x27;s got a metric fuck-ton then spin up
20 containers across our entire cluster. You say what you want and the
load-balancer + scheduler + monitor take care of the rest.&lt;&#x2F;p&gt;
&lt;p&gt;Persistent Storage:
The reason persistent storage is a useful feature is for two reasons&lt;&#x2F;p&gt;
&lt;p&gt;The first is that containers are ephemeral. They can be created,
destroyed, and upgraded &lt;em&gt;all&lt;&#x2F;em&gt; the time, basically making them the polar
opposite of a &#x27;Special Snowflake&#x27; service.&lt;&#x2F;p&gt;
&lt;p&gt;This is nice, but what about state? As nice as it&#x27;d be to make an
entirely stateless data-center, cat pictures and builds aren&#x27;t going to
store themselves!&lt;&#x2F;p&gt;
&lt;p&gt;The solution to this problem is -- well it&#x27;s not solved, but there&#x27;s a
clear direction things are going in. The TLDR is that we create some
block device in the cloud and mount it to each identical container at
the same mount-point, so each container (K8s &#x27;Pod&#x27;) shares some amount
of state. Sorta like... I&#x27;m bad at examples actually. I&#x27;ll think of one
eventually.&lt;&#x2F;p&gt;
&lt;p&gt;Piggy-backing off of this, not only do we preserve state between
container upgrades&#x2F;deletes&#x2F;additions, but we can also share state
between scaled services (i.e., a set of identical containers across a
datacenter). Essentially we can have one worker pod carry out a build
and another pod perform some action on that build (uploading it, verify
it, archive it, etc). When the first worker pod gets deleted the build
lives on in the shared state.&lt;&#x2F;p&gt;
&lt;p&gt;This allows us to treat our state the same way we treat computing
resources in the world of GIFFEE&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;GIFEE&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;Create some block device for the service, mount it to this point, and let your orchestrator take care of the rest.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Conceptual hurdles in programming</title>
        <published>2016-08-21T00:00:00+00:00</published>
        <updated>2016-08-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/programming-hurdles/"/>
        <id>https://elijah.run/blog/programming-hurdles/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/programming-hurdles/">&lt;p&gt;I&#x27;ve been actively learning programming for almost five years now.
I started by taking a C++ class at Portland Community College.
That class was the best thing to happen to my engineering career because it taught me that &lt;em&gt;programming is very hard, and I am not naturally good at it&lt;&#x2F;em&gt;, but it was also very rewarding so I stuck with it.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m not special either, most of us aren&#x27;t very good at programming because it&#x27;s so abstract and hard to grasp, like Math and Infinite Jest.
There are of course the people that seem like &lt;em&gt;programming gods&lt;&#x2F;em&gt;, but nine times out of ten those people have been programming since they were eight and it&#x27;s really not fair to compare yourself to them.
That&#x27;s like comparing your sporting abilities to &lt;em&gt;any olympic athlete&lt;&#x2F;em&gt;.
Don&#x27;t be so hard on yourself.&lt;&#x2F;p&gt;
&lt;p&gt;In learning to program, and now teaching others how to program, I&#x27;ve identified a few &lt;strong&gt;hurdles&lt;&#x2F;strong&gt; (mountains, cliffs, obstacles, w&#x2F;e) that folks tend to hit and have trouble crossing.
They always get past these hurdles eventually (or they quit CS ☹), but not without a bit of unnecessary struggle.
Struggling builds character, and I don&#x27;t want to cheat anybody out of that, but I do want to help those that want it.&lt;&#x2F;p&gt;
&lt;p&gt;This post will in no way guarantee your success in overcoming these obstacles but it should at least give you a head start to help you understand what you&#x27;re learning and point you in the right direction when you want to ask a question.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;data-structures&quot;&gt;Data Structures&lt;&#x2F;h2&gt;
&lt;p&gt;Understanding that &lt;strong&gt;a lot of programming is basically manipulating data to fit a need&lt;&#x2F;strong&gt; is pretty important.
A social network can be thought of as a bunch of people&#x27;s personal information plugged into a bunch of algorithms to make connecting easier.
A word processor is really just a front-end for some &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Microsoft_Office_XML_formats&quot;&gt;XML under the hood&lt;&#x2F;a&gt;, which is itself &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;XML&quot;&gt;just a way to represent structured data&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When handling data try to keep in mind what you are trying to accomplish and the best way to structure the data in the pursuit of that goal.&lt;&#x2F;p&gt;
&lt;span class=&quot;define&quot;&gt;
    &lt;span class=&quot;define-word&quot;&gt;
        &amp;lt;a href=&amp;quot;https:&amp;#x2F;&amp;#x2F;en.wikipedia.org&amp;#x2F;wiki&amp;#x2F;Array_data_structure&amp;quot;&amp;gt;Arrays&amp;#x2F;Lists&amp;#x2F;Vectors&amp;lt;&amp;#x2F;a&amp;gt;
    &lt;&#x2F;p&gt;

    &lt;span class=&quot;define-body&quot;&gt;
        &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Arrays and Lists are an ordered data type&amp;lt;&amp;#x2F;strong&amp;gt;. Use them when you need to
keep track of the order things happened in, like queuing an event.
Try to keep them &amp;lt;em&amp;gt;relatively small&amp;lt;&amp;#x2F;em&amp;gt; since they are fast for retrieval but not inherently space efficient.&amp;lt;&amp;#x2F;p&amp;gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;{% define(word=&quot;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hash_table&quot;&gt;Hash-table&#x2F;Key-Value&#x2F;Dictionary&lt;&#x2F;a&gt;&quot; %}
&lt;strong&gt;Hashes are useful for storing unordered data&lt;&#x2F;strong&gt; with keys, like an address book or a small database.
We use them to access data quickly and easily since data is retrieved using a key and always takes approximately the same amount of time.
When you get data out of a dictionary you provide a key and get back the associated data, just like (you guessed it) &lt;em&gt;a real dictionary&lt;&#x2F;em&gt; where provided the word you get back a definition.&lt;&#x2F;p&gt;
&lt;p&gt;Hash-tables are useful tools but should only be used for &lt;em&gt;relatively small&lt;&#x2F;em&gt; amounts of data.
There is a bit of overhead in creating the table for storing your data so if your data-set gets too big you&#x27;ll run out of memory.
{% end %}&lt;&#x2F;p&gt;
&lt;span class=&quot;define&quot;&gt;
    &lt;span class=&quot;define-word&quot;&gt;
        &amp;lt;a href=&amp;quot;https:&amp;#x2F;&amp;#x2F;en.wikipedia.org&amp;#x2F;wiki&amp;#x2F;Linked_list&amp;quot;&amp;gt;Linked Lists&amp;#x2F;Sorted Trees&amp;lt;&amp;#x2F;a&amp;gt;
    &lt;&#x2F;p&gt;

    &lt;span class=&quot;define-body&quot;&gt;
        &amp;lt;p&amp;gt;Linked Lists and Sorted Trees aren&amp;#x27;t exactly the same thing but I&amp;#x27;m lumping them together because they both deal with a lot of the same concepts and can be implemented in similar ways.
In learning about LL&amp;#x2F;ST you&amp;#x27;ll probably deal with Structs, Nodes, Pointers, and dynamic memory allocation, which if you&amp;#x27;re like me will totally break your brain and then become second-nature.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;One advantage to these structures is that they can be implemented to take up only the space they require&amp;lt;&amp;#x2F;strong&amp;gt;.
Where Hash-maps and lists are hard to make the &amp;lt;em&amp;gt;right size&amp;lt;&amp;#x2F;em&amp;gt;, LL&amp;#x2F;ST can only take up exactly as much room as they need.
The trade-off (a word you hear a lot when dealing choosing data structures) is that they&amp;#x27;re not always the &amp;lt;em&amp;gt;fastest&amp;lt;&amp;#x2F;em&amp;gt; way to store&amp;#x2F;retrieve data.
Just consider your use-case and think about what you need for the task at hand.&amp;lt;&amp;#x2F;p&amp;gt;
&amp;lt;p&amp;gt;If you&amp;#x27;re interested in learning Rust though there&amp;#x27;s a great guide on &amp;lt;a href=&amp;quot;http:&amp;#x2F;&amp;#x2F;cglab.ca&amp;#x2F;~abeinges&amp;#x2F;blah&amp;#x2F;too-many-lists&amp;#x2F;book&amp;#x2F;README.html&amp;quot;&amp;gt;Learning Rust With Entirely Too Many Linked Lists&amp;lt;&amp;#x2F;a&amp;gt;.
I do suggest it.&amp;lt;&amp;#x2F;p&amp;gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;&lt;strong&gt;These are all just the structures you&#x27;re giving your data&lt;&#x2F;strong&gt; (a series of ones and zeros on disk and in memory).
Anybody that&#x27;s done work with a sufficiently complicated project (e.g., the Linux Kernel) can tell you that one glob of data can be treated as a Linked List, Array, Hash -- or all three at the same time!
The structure you give your data is just so &lt;em&gt;you&lt;&#x2F;em&gt; can work with it, the computer doesn&#x27;t really care one way or another, so choose what makes the most sense.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Speaking of data structures...&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;objects-classes&quot;&gt;Objects&#x2F;Classes&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Objects are logical groupings of data (variables) and functions that act on that data&lt;&#x2F;strong&gt;.
They differ from structs in that they are (usually) private by default, meaning that variables declared in an object are not accessible from the &lt;em&gt;outside&lt;&#x2F;em&gt; unless you explicitly say so.
Variables are usually manipulated via a method called a &lt;em&gt;getter&lt;&#x2F;em&gt; and &lt;em&gt;setter&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Well... what I&#x27;ve actually described so far is creating a &lt;strong&gt;class: aka a blueprint for an object&lt;&#x2F;strong&gt;.
This python is a pretty succinct way to describe classes and objects:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;objects_example.py
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;Declare a class named BazClass.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#8cdaff;&quot;&gt;BazClass&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;font-style:italic;color:#8cdaff;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;__init__&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff8942;&quot;&gt;None&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;        The __init__ function sets class variables and sets up the object.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.var1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;x
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.var2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;6
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;        a() acts on the object variables (accessed via `self`).
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;        &amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Variable you set &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;format&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.var1))
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Variable set by class definition &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;format&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.var2))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;Creating an instance of the class and call the `a()` function.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;foo_object &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;BazClass&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;foo_object.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Objects are something that will &lt;em&gt;click&lt;&#x2F;em&gt; after you use the for a while.
There&#x27;s some nuances and implementation quirks depending on the language you&#x27;re using, but in the end they&#x27;re just logical collections of private data and functions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;functional-programming&quot;&gt;Functional Programming&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Functional_programming&quot;&gt;Functional Programming&lt;&#x2F;a&gt; (FP) was my first big paradigm shift in CS since functions. FP includes concepts of variable immutability (once it&#x27;s set it&#x27;s set), callbacks (functions calling functions and propagating results up), program state -- the list goes on. Here&#x27;s an example to get us started.&lt;&#x2F;p&gt;
&lt;p&gt;Non-functional paradigm:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;function &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;average_evens&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;avg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;.length; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;++&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;avg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;i&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;avg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;avg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;.length;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;avg&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Functional Paradigm:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;function &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;average_evens&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;reduce&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fbdfb5;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;) &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;.length;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the non-functional example one would create a variable, iterate with a for-loop, and return a variable at the end.
In the functional example you call functions which return data that you handle (callback) and that result is added to or replaces the original data. I&#x27;m honestly not doing this topic justice but it&#x27;s one of those things you either learn first or you learn the hard way.&lt;&#x2F;p&gt;
&lt;p&gt;This is just the tip of the ice-berg; many people prefer functional programming.
If you are even remotely interested you should find one of those people and let them talk your ear off.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re learning functional programming I suggest either &lt;a href=&quot;http:&#x2F;&#x2F;learnyouahaskell.com&#x2F;chapters&quot;&gt;Learn You a Haskell for Great Good&lt;&#x2F;a&gt; if you&#x27;re interested in learning Haskell (which is interesting an interesting language if nothing else) or &lt;a href=&quot;http:&#x2F;&#x2F;www.oreilly.com&#x2F;programming&#x2F;free&#x2F;functional-programming-python.csp&quot;&gt;Functional Programming in Python&lt;&#x2F;a&gt; for &lt;em&gt;pythonistas&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;frameworks&quot;&gt;Frameworks&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Frameworks are a collection of libraries, methods, and tools to accomplish a specific type of task&lt;&#x2F;strong&gt;.
If you want to get something &lt;em&gt;complicated&lt;&#x2F;em&gt; done &lt;em&gt;fast&lt;&#x2F;em&gt;, you&#x27;ll use a framework.
Take for instance a web-app like Facebook or Twitter: it needs to be able to &lt;em&gt;send&#x2F;receive HTTP requests&lt;&#x2F;em&gt;, &lt;em&gt;interface with a database&lt;&#x2F;em&gt; &#x2F; &lt;em&gt;craft database queries&lt;&#x2F;em&gt;, &lt;em&gt;render web-pages&lt;&#x2F;em&gt;, &lt;em&gt;and&lt;&#x2F;em&gt; whatever the actual website is supposed to do.&lt;&#x2F;p&gt;
&lt;p&gt;Frameworks can be very small or very large but they are always a big hurdle for those of us that have never worked with one before.
A good starter framework I suggest is &lt;a href=&quot;http:&#x2F;&#x2F;flask.pocoo.org&#x2F;&quot;&gt;Flask&lt;&#x2F;a&gt; for Python-based web-apps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Testing is writing a program to test your program&lt;&#x2F;strong&gt;.
There are many different &lt;em&gt;kinds&lt;&#x2F;em&gt; of tests from &lt;em&gt;unit tests&lt;&#x2F;em&gt; (checking single functions), to &lt;em&gt;integration tests&lt;&#x2F;em&gt; (checking that your functions work &lt;em&gt;together&lt;&#x2F;em&gt;), to &lt;em&gt;random tests&lt;&#x2F;em&gt; (trying to break your program by telling a computer to break your functions by using they in weird ways).&lt;&#x2F;p&gt;
&lt;p&gt;Remember that first program you wrote for class?
You wrote one that prompted the user for data and then manipulated that input in some way?
Remember how you tested that?
Probably in the most tedious way imaginable: &lt;strong&gt;by hand&lt;&#x2F;strong&gt;.
Tests are much easier to write than your actual code and while they&#x27;re a tedious investment up-front it&#x27;s a small commitment relative to the &lt;em&gt;hours&lt;&#x2F;em&gt; you&#x27;d spend checking your program every time you made a change.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;troubleshooting&quot;&gt;Troubleshooting&lt;&#x2F;h2&gt;
&lt;p&gt;The last thing isn&#x27;t really about programming but about &lt;em&gt;fixing&lt;&#x2F;em&gt; your programming.
When you&#x27;re learning a new paradigm, language, or framework you&#x27;re going to spend a lot of time &lt;em&gt;fixing&lt;&#x2F;em&gt; what doesn&#x27;t currently work much more than you&#x27;re going to actually be producing working code.
This skill can also be summed up as &#x27;How to Read Error Messages and Google well&#x27;.&lt;&#x2F;p&gt;
&lt;p&gt;My troubleshooting advice is to &lt;em&gt;read&lt;&#x2F;em&gt; the error message, don&#x27;t give up, and search for anything that looks meaningful.
Once you find an answer try to &lt;em&gt;grok&lt;&#x2F;em&gt; what the answer means so you can learn &lt;em&gt;why&lt;&#x2F;em&gt; that worked instead of knowing &lt;em&gt;if I type this in a certain way it will not fall down&lt;&#x2F;em&gt;.
Future you will appreciate the investment you put into &lt;em&gt;understanding&lt;&#x2F;em&gt; the problem and it&#x27;s solution.&lt;&#x2F;p&gt;
&lt;p&gt;Also don&#x27;t be afraid to experiment. Make a copy of your program (or use &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;&quot;&gt;git&lt;&#x2F;a&gt;) and see if some crazy idea is exactly what you need.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;This list is far from complete but it still felt worth sharing.
If you think I missed something, &lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;about&#x2F;#contact&quot;&gt;contact me&lt;&#x2F;a&gt; and I might do a follow-up post.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Does a Lot of Things</title>
        <published>2016-07-27T00:00:00+00:00</published>
        <updated>2016-07-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/git-does-a-lot-of-things/"/>
        <id>https://elijah.run/blog/git-does-a-lot-of-things/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/git-does-a-lot-of-things/">&lt;p&gt;I should make a tool that extends &lt;code&gt;git&lt;&#x2F;code&gt; to delete all of the files matched by the &lt;code&gt;.gitginore&lt;&#x2F;code&gt;.
I spend way too much time crafting &lt;code&gt;find &amp;lt;...&amp;gt; | xargs rm&lt;&#x2F;code&gt; commands. I know, I&#x27;ll call it &lt;code&gt;git clean&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Well... before I get too far I&#x27;ll just make sure it doesn&#x27;t already exist.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ man git clean
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;GIT-CLEAN(1)                  Git Manual                       GIT-CLEAN(1)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;NAME
&lt;&#x2F;span&gt;&lt;span&gt;       git-clean - Remove untracked files from the working tree
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;SYNOPSIS
&lt;&#x2F;span&gt;&lt;span&gt;    git clean [-d] [-f] [-i] [-n] [-q] [-e &amp;lt;pattern&amp;gt;] [-x | -X] [--]
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;path&amp;gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;DESCRIPTION
&lt;&#x2F;span&gt;&lt;span&gt;    Cleans the working tree by recursively removing files that are not
&lt;&#x2F;span&gt;&lt;span&gt;    under version control, starting from the current directory.
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    ...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Huh... well I... that&#x27;s pretty much exactly how I would have done it...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;git&lt;&#x2F;code&gt; &lt;em&gt;tab tab&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;add                  filter-branch        relink
&lt;&#x2F;span&gt;&lt;span&gt;am                   format-patch         remote
&lt;&#x2F;span&gt;&lt;span&gt;annotate             fsck                 repack
&lt;&#x2F;span&gt;&lt;span&gt;apply                gc                   replace
&lt;&#x2F;span&gt;&lt;span&gt;archive              get-tar-commit-id    request-pull
&lt;&#x2F;span&gt;&lt;span&gt;bisect               grep                 reset
&lt;&#x2F;span&gt;&lt;span&gt;blame                help                 revert
&lt;&#x2F;span&gt;&lt;span&gt;branch               imap-send            review
&lt;&#x2F;span&gt;&lt;span&gt;bundle               init                 rm
&lt;&#x2F;span&gt;&lt;span&gt;checkout             instaweb             send-email
&lt;&#x2F;span&gt;&lt;span&gt;cherry               interpret-trailers   shortlog
&lt;&#x2F;span&gt;&lt;span&gt;cherry-pick          log                  show
&lt;&#x2F;span&gt;&lt;span&gt;clean                merge                show-branch
&lt;&#x2F;span&gt;&lt;span&gt;clone                mergetool            stage
&lt;&#x2F;span&gt;&lt;span&gt;column               mv                   stash
&lt;&#x2F;span&gt;&lt;span&gt;commit               name-rev             status
&lt;&#x2F;span&gt;&lt;span&gt;config               notes                submodule
&lt;&#x2F;span&gt;&lt;span&gt;credential           p4                   svn
&lt;&#x2F;span&gt;&lt;span&gt;describe             pull                 tag
&lt;&#x2F;span&gt;&lt;span&gt;diff                 push                 verify-commit
&lt;&#x2F;span&gt;&lt;span&gt;difftool             rebase               whatchanged
&lt;&#x2F;span&gt;&lt;span&gt;fetch                reflog               worktree
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ah, okay.
I get it now.
Git &lt;em&gt;does&lt;&#x2F;em&gt; do a lot of things.&lt;&#x2F;p&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;The above output is from &lt;code&gt;git 2.8.2&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Induction</title>
        <published>2016-07-27T00:00:00+00:00</published>
        <updated>2016-07-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/induction/"/>
        <id>https://elijah.run/blog/induction/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/induction/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;comics&#x2F;induction.png&quot; alt=&quot;Classic mathematics memes&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to Get the Most out of Your Python Exceptions</title>
        <published>2016-04-03T00:00:00+00:00</published>
        <updated>2016-04-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/python-exceptions/"/>
        <id>https://elijah.run/blog/python-exceptions/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/python-exceptions/">&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span&gt;var &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Please enter a number not equal to 0: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    var &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fdb082;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt;(var)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;except &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;ZeroDivisionError &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;e:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Error: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;(e))
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;You had one job!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;warning&quot;&gt;
    &lt;span class=&quot;warning-title&quot;&gt;
        Warning
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;warning-body&quot;&gt;
        &lt;p&gt;This post does not cover &lt;em&gt;what&lt;&#x2F;em&gt; python exceptions are. If the above code
doesn&#x27;t make sense you should check out this &lt;a href=&quot;https:&#x2F;&#x2F;wiki.python.org&#x2F;moin&#x2F;HandlingExceptions&quot;&gt;Introduction to Python
Exceptions&lt;&#x2F;a&gt; from
wiki.python.org before reading this post.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;If you&#x27;ve fallen in love with Python you&#x27;ve no doubt discovered exceptions:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# do a thing
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;except&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# thing did not work,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# do something else
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;They are endlessly useful and help one to avoid writing checks upon checks upon checks before getting to the meat of your project.
Just try a thing, catch the error, keep on rolling (or fail gracefully).&lt;&#x2F;p&gt;
&lt;p&gt;As powerful as they can be, I have found a lot of folks (past me included) who don&#x27;t know how to find python exceptions and don&#x27;t know how to write their own exceptions! So let&#x27;s do that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finding-exceptions&quot;&gt;Finding Exceptions&lt;&#x2F;h2&gt;
&lt;p&gt;When writing exception handling code it&#x27;s kosher to explicitly state &lt;em&gt;which&lt;&#x2F;em&gt; error you expect.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Bad:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# A thing that might not work
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;except&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Something else
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Good:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# A thing that might not work
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;except &lt;&#x2F;span&gt;&lt;span&gt;SpecificError &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;err:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Maybe print(err)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;# Something else
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When I first found this out I thought &lt;em&gt;Golly that does sound useful; I always try to be explicit in my error handling -- but how??&lt;&#x2F;em&gt;
Thankfully future me is here to answer questions like this.&lt;&#x2F;p&gt;
&lt;p&gt;The exception you are looking for (for instance, &lt;code&gt;SpecificError&lt;&#x2F;code&gt; in the above pseudo-code) can be found in the python traceback:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ echo &amp;quot;open(&amp;#39;myfakefile.txt&amp;#39;, &amp;#39;r&amp;#39;).close()&amp;quot; &amp;gt; my-unhandled-script.py
&lt;&#x2F;span&gt;&lt;span&gt;$ python my-unhandled-script.py
&lt;&#x2F;span&gt;&lt;span&gt;Traceback (most recent call last):
&lt;&#x2F;span&gt;&lt;span&gt;  File &amp;quot;&#x2F;tmp&#x2F;test.py&amp;quot;, line 1, in &amp;lt;module&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;    open(&amp;#39;myfakefile.txt&amp;#39;, &amp;#39;r&amp;#39;).close()
&lt;&#x2F;span&gt;&lt;span&gt;IOError: [Errno 2] No such file or directory: &amp;#39;myfakefile.txt&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That bit on the last line &lt;code&gt;IOError&lt;&#x2F;code&gt; is the exception you&#x27;re looking for.
So when you write your code you&#x27;ll say something like the following:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;myfakefile.txt&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;r&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;close&lt;&#x2F;span&gt;&lt;span&gt;()
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;except &lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;IOError &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;e:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(e)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;File `myfakefile.txt` does not exist&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To recap, here is one way (and my preferred method for) &#x27;doing&#x27; python exception handling:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Write breakable code.&lt;&#x2F;li&gt;
&lt;li&gt;Run breakable code, see what exceptions python spits out.&lt;&#x2F;li&gt;
&lt;li&gt;Wrap breakable code in explicit &lt;code&gt;try&#x2F;except&lt;&#x2F;code&gt; blocks.&lt;&#x2F;li&gt;
&lt;li&gt;???&lt;&#x2F;li&gt;
&lt;li&gt;Profit.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;writing-your-own-exceptions&quot;&gt;Writing Your Own Exceptions&lt;&#x2F;h2&gt;
&lt;p&gt;You (who me?), yes &lt;em&gt;you&lt;&#x2F;em&gt; can write custom python exceptions.
It&#x27;s dead easy too.&lt;&#x2F;p&gt;
&lt;p&gt;The long and short of it is you define an exception class which either inherits from the &lt;code&gt;Exception&lt;&#x2F;code&gt; class or another pre-existing exception.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;class &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#8cdaff;&quot;&gt;CusssstomError&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;font-style:italic;color:#8cdaff;&quot;&gt;Exception&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6d6d6d;&quot;&gt;&amp;#39;&amp;#39;&amp;#39;Raise when snakes&amp;#39;&amp;#39;&amp;#39;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;__init__&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.message &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;message
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ff5e5e;&quot;&gt;def &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;check_for_snakes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#fc9354;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;):
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;snake&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;foo.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;lower&lt;&#x2F;span&gt;&lt;span&gt;():
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;raise &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;CusssstomError&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Snakes! I hate snakes!&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    foo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Just don&amp;#39;t mention snakes: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;check_for_snakes&lt;&#x2F;span&gt;&lt;span&gt;(foo)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;except &lt;&#x2F;span&gt;&lt;span&gt;CusssstomError &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span&gt;e:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(e.message)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;else&lt;&#x2F;span&gt;&lt;span&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;Thanks. I appreciate it.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above code defines the &lt;code&gt;CusssstomError&lt;&#x2F;code&gt; exception class which you can &lt;code&gt;raise&lt;&#x2F;code&gt;.
Very neat and &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;2&#x2F;glossary.html#term-pythonic&quot;&gt;pythonic&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further Reading&lt;&#x2F;h2&gt;
&lt;p&gt;Here are a few references I suggest you check out to get an even better grasp on exception handling and custom exceptions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;This Stack Overflow post: &lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1319615&#x2F;proper-way-to-declare-custom-exceptions-in-modern-python&quot;&gt;Proper way to declare custom exceptions in modern Python?&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;This Python doc: &lt;a href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;2&#x2F;library&#x2F;exceptions.html&quot;&gt;Built-in Exceptions&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And as always, search engines are your friends.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to develop a site for the web</title>
        <published>2016-03-25T00:00:00+00:00</published>
        <updated>2016-03-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/how-to-develop-a-site-for-the-web/"/>
        <id>https://elijah.run/blog/how-to-develop-a-site-for-the-web/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/how-to-develop-a-site-for-the-web/">&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;This post does not deal with the basics of HTML, CSS, or Javascript, but
rather a simple and often overlooked part of the web-dev toolchain.&lt;&#x2F;p&gt;
&lt;p&gt;If you would like help with the basics of HTML, CSS, and Javascript I
suggest &lt;a href=&quot;https:&#x2F;&#x2F;codecademy.com&#x2F;learn&#x2F;make-a-website&quot;&gt;Codecademy&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Web Development, especially the front-endy stuff, is a great way to
understand how computers &lt;em&gt;think&lt;&#x2F;em&gt; and can be a wonderful foray into
computer programming. Anybody that&#x27;s made a website probably remembers
their first time:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Open up a text editor.&lt;&#x2F;li&gt;
&lt;li&gt;Type something like the following in:&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre data-lang=&quot;html&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-html &quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;Hello world!&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;p&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;This is so cool!&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;h1&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;code&gt;Save As index.html&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Right click and open the file in your browser.&lt;&#x2F;li&gt;
&lt;li&gt;Marvel at what you&#x27;ve created and hack away at it all night long.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;And there you go! You&#x27;ve got a website made and ready to roll. It&#x27;s not
on a server, and you can&#x27;t tell your friends to go to it from &lt;em&gt;their&lt;&#x2F;em&gt;
computer --but those are just technicalities. You can still celebrate
doing a thing &lt;em&gt;like a boss&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, when you test your website by viewing local files you&#x27;re
missing out on a lot of advantages and quirks that you get when you host
a website on a &lt;em&gt;real server&lt;&#x2F;em&gt; using something like &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Web_server&quot;&gt;Apache or
Nginx&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, when you run check your website by clicking through
&lt;code&gt;file&#x2F;&#x2F;&#x2F;home&#x2F;username&#x2F;project&#x2F;files.html&lt;&#x2F;code&gt; all of your hyperlinks that
should point to &lt;code&gt;http:&#x2F;&#x2F;mywebsite.ext&#x2F;somepage&#x2F;&lt;&#x2F;code&gt; will take you to
&lt;code&gt;file:&#x2F;&#x2F;&#x2F;&#x2F;somepage&lt;&#x2F;code&gt; when they should take you to
&lt;code&gt;file:&#x2F;&#x2F;&#x2F;home&#x2F;username&#x2F;projects&#x2F;myawesomesite&#x2F;somepage&#x2F;index.html&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;run-a-development-server-it-s-easy&quot;&gt;Run A Development Server (it&#x27;s easy!)&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;the-short-answer&quot;&gt;The Short Answer&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Use Python!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ python2 -m SimpleHTTPServer
&lt;&#x2F;span&gt;&lt;span&gt;Serving HTTP on 0.0.0.0 port 8000 ...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;the-longer-answer&quot;&gt;The Longer Answer&lt;&#x2F;h3&gt;
&lt;p&gt;You can run your own local webserver to serve files &lt;em&gt;locally&lt;&#x2F;em&gt;.
This gets you all of the developmental advantages of running a webserver without having to rent or run a server in the cloud.
The best part is that it&#x27;s very easy to run a development web server.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;python.org&#x2F;downloads&#x2F;&quot;&gt;Install Python&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Navigate to &lt;code&gt;your-awesome-website&lt;&#x2F;code&gt; directory&#x2F;folder.&lt;&#x2F;li&gt;
&lt;li&gt;Run &lt;code&gt;python -m SimpleHTTPServer&lt;&#x2F;code&gt; if you installed &lt;code&gt;python2&lt;&#x2F;code&gt; or run &lt;code&gt;python -m http.server&lt;&#x2F;code&gt; if you installed &lt;code&gt;python3&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;div class=&quot;note&quot;&gt;
    &lt;span class=&quot;note-title&quot;&gt;
        Note
    &lt;&#x2F;span&gt;

    &lt;span class=&quot;note-body&quot;&gt;
        &lt;p&gt;These instructions assume you are doing things in a Unix environment (OSX or Linux) thought the commandline.
If you are using Windows you should check out this &lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;17351016&#x2F;set-up-python-simplehttpserver-on-windows&quot;&gt;stack overflow post&lt;&#x2F;a&gt; for Windows-specific help.&lt;&#x2F;p&gt;

    &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;
&lt;p&gt;Then in your web browser go to the address &lt;code&gt;http:&#x2F;&#x2F;localhost:8000&lt;&#x2F;code&gt; and
bam! &lt;strong&gt;Your&lt;&#x2F;strong&gt; Website.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;gifs&#x2F;high-five.gif&quot; alt=&quot;High Five.gif&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Running Firefox in Docker</title>
        <published>2016-03-05T00:00:00+00:00</published>
        <updated>2016-03-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/running-firefox-in-docker/"/>
        <id>https://elijah.run/blog/running-firefox-in-docker/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/running-firefox-in-docker/">&lt;p&gt;Turns out you can run Firefox in Docker.
It&#x27;s actually pretty easy:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;code&quot;&gt;Code&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;From&lt;&#x2F;strong&gt; &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;ElijahCaine&#x2F;29e7e829341d58abe370&quot;&gt;my github
gist&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;script src=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;ElijahCaine&#x2F;29e7e829341d58abe370.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;p&gt;Installation instructions (on Linux):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;# install docker and start the docker daemon
&lt;&#x2F;span&gt;&lt;span&gt;$ git clone https:&#x2F;&#x2F;gist.github.com&#x2F;29e7e829341d58abe370.git docker-firefox
&lt;&#x2F;span&gt;&lt;span&gt;$ ln docker-firefox&#x2F;ff-docker &#x2F;some&#x2F;path&#x2F;for&#x2F;binaries
&lt;&#x2F;span&gt;&lt;span&gt;$ ff-docker -b  # -b pulls &amp;amp; builds container, etc used for first time startup.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h2&gt;
&lt;p&gt;I attempted to use &lt;a href=&quot;http:&#x2F;&#x2F;alpinelinux.org&#x2F;&quot;&gt;Alpine Linux&lt;&#x2F;a&gt; as a
proof-of-usability, since it&#x27;s the hip new kid on the containerization
block&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but as it turns out Alpine&#x27;s Firefox package is pretty
fucked&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I use &lt;a href=&quot;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;Dmenu&quot;&gt;dmenu&lt;&#x2F;a&gt;, this means I
can run &lt;code&gt;ff-docker&lt;&#x2F;code&gt; from my desktop without opening a terminal,
effectively making it a super-private-yet-convenient drop-in for
Firefox. Pretty neat right?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This was pretty simple but effective in terms of giving me the option to
have more privacy. I can see it being extended to add even more
security; e.g., routing all of the traffic in the container through a
VPN would be easy enough. Food for thought [citation needed].&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;5mb containers sounds pretty nice to me.
&lt;a href=&quot;http:&#x2F;&#x2F;gliderlabs.viewdocs.io&#x2F;docker-alpine&#x2F;&quot;&gt;http:&#x2F;&#x2F;gliderlabs.viewdocs.io&#x2F;docker-alpine&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;I get a segfault every time I try to start Firefox. More info
here: &lt;a href=&quot;https:&#x2F;&#x2F;bugzilla.mozilla.org&#x2F;show_bug.cgi?id=724227#c11&quot;&gt;https:&#x2F;&#x2F;bugzilla.mozilla.org&#x2F;show_bug.cgi?id=724227#c11&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>CatBarcamp 2015</title>
        <published>2015-10-12T00:00:00+00:00</published>
        <updated>2015-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/cat-barcamp-2015/"/>
        <id>https://elijah.run/blog/cat-barcamp-2015/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/cat-barcamp-2015/">&lt;p&gt;This weekend I went to &lt;a href=&quot;http:&#x2F;&#x2F;catbarcamp.org&#x2F;&quot;&gt;Cat Barcamp 2015&lt;&#x2F;a&gt;, an unconference run by the PSU &lt;a href=&quot;http:&#x2F;&#x2F;cat.pdx.edu&#x2F;&quot;&gt;Computer Action Team&lt;&#x2F;a&gt;.
I went to some awesome talks (and gave one myself).&lt;&#x2F;p&gt;
&lt;p&gt;I enjoyed every talk I went to. Here they are in order:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;History of Cryptography.&lt;&#x2F;strong&gt;
This was given by one of my OSL co-workers.
It didn&#x27;t contain a ton of new information for me, but was delivered very well and focused on different types of cryptography and the context in which each one was developed.
I enjoyed it.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Haskell on Steroids.&lt;&#x2F;strong&gt;
I kinda checked out during this talk because I wanted to write my slides... Wooops.
It looked very interesting and mathey though...&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Introduction to Test Driven Development in Power Shell.&lt;&#x2F;strong&gt;
Whoa Windows
(actually though, I learned more about Power Shell than I ever expected to know).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MY TALK.&lt;&#x2F;strong&gt;
&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;cat-barcamp-2015&#x2F;#my-talk&quot;&gt;(see below)&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Whirlwind Tour of Lojban.&lt;&#x2F;strong&gt;
Lojban seems like a cool language. Corbin (previous LUG president) gave this talk, he&#x27;s a cool guy... you might even say he&#x27;s TheMostAwesomeDude.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Adventures in IT Security: Then and now.&lt;&#x2F;strong&gt;
I like history.
I also like computers.
This was a good talk.
I am biased.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Talking to people! (or, How I learned to stop worrying and love the user.)&lt;&#x2F;strong&gt;
Spoiler: The secret is understanding social cues.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;my-talk&quot;&gt;My Talk&lt;&#x2F;h2&gt;
&lt;p&gt;I decided on the spur of the moment to give a talk &#x27;How to Write a (very mediocre) Static Site Generator&#x27; and with only 40 minutes of prep work I was able to fill an hour pretty well.&lt;&#x2F;p&gt;
&lt;p&gt;Here are some links from that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;ElijahCaine&#x2F;0ee1ef21692f3cbb6934&quot;&gt;demo code&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;a href=&quot;http:&#x2F;&#x2F;elijahcaine.me&#x2F;catbarcamp2015-demo&#x2F;&quot;&gt;abomination of a website&lt;&#x2F;a&gt; we built between the demo and the end of the session (epilepsy warning... no seriously).&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;a href=&quot;http:&#x2F;&#x2F;slides.elijahcaine.me&#x2F;cat-barcamp-2015_how-to-an-ssg&#x2F;&quot;&gt;very sparse slides&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;&#x2F;h2&gt;
&lt;p&gt;The CAT is an awesome group of people.
I&#x27;m glad I was able to get a few LUG members to come to the event.
If I went to PSU I would be honored to work with the CAT.
They throw a hellofan event.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Covertly Installing Packages with Docker</title>
        <published>2015-10-07T00:00:00+00:00</published>
        <updated>2015-10-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/covertly-install-packages-with-docker/"/>
        <id>https://elijah.run/blog/covertly-install-packages-with-docker/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/covertly-install-packages-with-docker/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;elijah.run&#x2F;blog&#x2F;covertly-install-packages-with-docker&#x2F;#the-deets-dockerfile-and-commands&quot;&gt;Jump to the codey bits&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem-workstations&quot;&gt;The Problem: Workstations&lt;&#x2F;h2&gt;
&lt;p&gt;At the OSL I use workstations which are provisioned by
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Chef_%28software%29&quot;&gt;Chef&lt;&#x2F;a&gt; to look more
or less identical (packages are the same and global config files are
consistent from machine to machine). This is nice because it allows
everybody at the lab to jump from workstation to workstation without
dreading the inevitable setup that usually comes with going to a new
computer.&lt;&#x2F;p&gt;
&lt;p&gt;The only downside here is that to install a package you have to make a
pull request to a GitHub Repository in which you modify a JSON file.
This is almost always for my own good, but as a dev I am prone to
avoiding things that the admins say are good for me (like broccoli,
milk, and consistent workstation environments).&lt;&#x2F;p&gt;
&lt;p&gt;For instance, yesterday I wanted to use
&lt;a href=&quot;http:&#x2F;&#x2F;rg3.github.io&#x2F;youtube-dl&#x2F;&quot;&gt;youtube-dl&lt;&#x2F;a&gt; to grab a video I was
watching on repeat*. I could have made a pull request to add the
package, waited until 30 after for the workstations to refresh, used the
package, and went about my day. This would have been the correct and
bureaucratic way to do things.&lt;&#x2F;p&gt;
&lt;p&gt;I &lt;em&gt;could&lt;&#x2F;em&gt; have, and probably &lt;em&gt;should&lt;&#x2F;em&gt; have, done that... but I didn&#x27;t.&lt;&#x2F;p&gt;
&lt;p&gt;* firefox kept crashing, I wasn&#x27;t just stealing music for the sake of
it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;enter-docker&quot;&gt;Enter: Docker&lt;&#x2F;h2&gt;
&lt;p&gt;In this case the solution to the &#x27;problem&#x27; was
&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Docker_%28software%29&quot;&gt;Docker&lt;&#x2F;a&gt;. I wrote a
Dockerfile which provisioned a container to have &lt;code&gt;youtube-dl&lt;&#x2F;code&gt; installed,
spun up the container with a shared directory (&lt;code&gt;$PWD:&#x2F;home&#x2F;&lt;&#x2F;code&gt;), and
executed the youtube-dl command. The .mp4 video was downloaded to my
current working directory and I was able to play it with my media player
of choice, all without installing &lt;code&gt;youtube-dl&lt;&#x2F;code&gt; locally.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-deets-dockerfile-and-commands&quot;&gt;The Deets: Dockerfile and Commands&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;Dockerfile&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;FROM ubuntu:latest
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;RUN apt-get -y update
&lt;&#x2F;span&gt;&lt;span&gt;RUN apt-get -y upgrade
&lt;&#x2F;span&gt;&lt;span&gt;RUN apt-get -y install python-pip
&lt;&#x2F;span&gt;&lt;span&gt;RUN pip install youtube-dl
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;WORKDIR &#x2F;home
&lt;&#x2F;span&gt;&lt;span&gt;RUN alias youtube-dl=&amp;#39;&#x2F;usr&#x2F;local&#x2F;bin&#x2F;youtube-dl&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you are in the directory containing the above Dockerfile, build the
container with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ docker build -t yt-dl .
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and run it with:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;$ docker run -v $PWD:&#x2F;home&#x2F; yt-dl youtube-dl &amp;lt;YOUTUBE-VID-URL&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will download any url&#x27;s video into the current working directory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pro-tip-add-an-alias&quot;&gt;Pro-Tip: Add an &lt;code&gt;Alias&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Add the following content to your &lt;code&gt;~&#x2F;.bashrc&lt;&#x2F;code&gt; file and then run
&lt;code&gt;source ~&#x2F;.bashrc&lt;&#x2F;code&gt; to get rid the of long Docker bits of the above
command.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#191919;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e9fdac;&quot;&gt;$VID_DIR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;&#x2F;path&#x2F;to&#x2F;downloaded&#x2F;videos&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6699cc;&quot;&gt;alias &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8cdaff;&quot;&gt;yt-dl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff5e5e;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#fbe3bf;&quot;&gt;docker run -v $VID_DIR:&#x2F;home&#x2F; yt-dl youtube-dl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;wait-this-is-overly-complicated&quot;&gt;Wait This is Overly Complicated&lt;&#x2F;h2&gt;
&lt;p&gt;You&#x27;re probably thinking: &quot;Hey, couldn&#x27;t you have just run
&lt;code&gt;pip install --user youtube-dl&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;p&gt;Yes. I could have. But that wouldn&#x27;t be fun and wouldn&#x27;t have given me
an excuse to write a blog, post now would it Ms. Smarty Pantz.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;drink the coolaid. come to the docker side.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Travel travel travel...</title>
        <published>2015-09-03T00:00:00+00:00</published>
        <updated>2015-09-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-09-03/"/>
        <id>https://elijah.run/blog/2015-09-03/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-09-03/">&lt;h2 id=&quot;travel-travel-travel&quot;&gt;Travel Travel Travel&lt;&#x2F;h2&gt;
&lt;p&gt;Travel travel travel travel travel travel travel travel travel travel
travel travel travel travel travel travel travel travel travel travel
travel travel. travel. Travel travel travel travel travel travel travel
travel travel travel travel travel travel travel travel travel travel
travel travel travel travel.&lt;&#x2F;p&gt;
&lt;p&gt;Travel travel travel travel travel travel travel travel travel travel
travel travel travel travel travel travel travel travel travel travel
travel travel. travel. Travel travel travel travel travel travel travel
travel travel travel travel travel travel travel travel travel travel
travel travel travel travel travel travel travel travel travel travel
travel travel travel travel travel. travel. Travel travel travel travel
travel travel travel travel travel travel travel travel travel travel
travel travel travel travel travel travel travel. travel travel travel
travel travel travel travel travel travel travel travel.&lt;&#x2F;p&gt;
&lt;p&gt;Travel travel travel travel travel travel. Travel travel travel travel
travel travel travel. Travel travel travel travel travel travel travel
travel travel.&lt;&#x2F;p&gt;
&lt;p&gt;Sleep.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A Personal Day in Prague: (Almost) Just Pictures</title>
        <published>2015-09-02T00:00:00+00:00</published>
        <updated>2015-09-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-09-02/"/>
        <id>https://elijah.run/blog/2015-09-02/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-09-02/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-charles-bridge.jpg&quot; alt=&quot;Charles Bridge.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-pilot-statute.jpg&quot; alt=&quot;Pilot Statue&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-view.jpg&quot; alt=&quot;View of Prague with some trees in the way.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I went on a hike, found a great view at the top of a hill.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-oldtown.jpg&quot; alt=&quot;Oldtown Prague&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-panorama-with-bridge.jpg&quot; alt=&quot;Panorama with bridge&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-creative-spelling.jpg&quot; alt=&quot;Starbucks Coffee&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&#x27;Eli&#x27;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-stunning-sunset.jpg&quot; alt=&quot;Stunning sunset&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I swear it&#x27;s not because I&#x27;m lazy and don&#x27;t want to write.
The pictures just capture it better.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Write the Docs Day 2</title>
        <published>2015-09-01T00:00:00+00:00</published>
        <updated>2015-09-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-09-01/"/>
        <id>https://elijah.run/blog/2015-09-01/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-09-01/">&lt;p&gt;Just like yesterday, I spent most of today enjoying some wonderful talks as well as stressing out -- I mean totally not stressing out -- about my own talk.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;wtd-day-2.jpg&quot; alt=&quot;write the Docs Staff Picture&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Write the Docs Staff saying thanks.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The first talk of the day was titled &quot;Judas Priest Ate My Scrum Master&quot;, which has almost nothing to do with Judas Priest or eating or scrum masters; instead it talked about things that are well known issues and a lot of laws (&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Brooks%E2%80%99_law&quot;&gt;Brooks&#x27; Law&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lehman&amp;#x27;s_laws_of_software_evolution&quot;&gt;Lehmann&#x27;s Laws&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Pareto_principle&quot;&gt;Pareto Principle&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Conway&amp;#x27;s_law&quot;&gt;Conway&#x27;s Law&lt;&#x2F;a&gt;, etc) that nobody talks about that much but can be super helpful to consider when working in an industry.&lt;&#x2F;li&gt;
&lt;li&gt;The second talk covered different types of user interfaces and what to consider when writing error messages, troubleshooting pages, product tours.
It was something I hadn&#x27;t considered having primarily written command line tools with pretty limited and well established interface
guidelines.&lt;&#x2F;li&gt;
&lt;li&gt;Then I gave a talk.
It was a talk. I&#x27;ll post a video of it once those get put up online and you can decide if it was good or bad.&lt;&#x2F;li&gt;
&lt;li&gt;The talk after mine was a nice history lesson and wanted the audience to reflect on what documentations can learn from documentation practices of the past.
The TLDR on that one is that it used to suck to write technical docs even more than it sucks now.&lt;&#x2F;li&gt;
&lt;li&gt;Then there were a bunch of lightning talks.
One talk from a twitter employee (there&#x27;s a fun name for them I&#x27;m sure) mentioned that gathering metrics are is important because without metrics everything you do is just guess and check.&lt;&#x2F;li&gt;
&lt;li&gt;The next talk &quot;MacGyvering your docs&quot; brought up the fact that the best documentation toolchain will (should?) only help existing developers.
A better toolchain won&#x27;t attract new devs.
That was something I think a lot of projects can lose sight of.&lt;&#x2F;li&gt;
&lt;li&gt;The talk after that covered a team of scientists studying clouds (water clouds not internet clouds) using computer simulations.
They wrote and documented a piece of software and they ended up publishing their program&#x27;s documentation in a scientific journal.
It&#x27;s already been sited and everything.
I hadn&#x27;t even considered that as a possibility (publishing docs as a scientific paper).&lt;&#x2F;li&gt;
&lt;li&gt;The next two talks were pretty short (15 minute) talks about putting the data where the users need it and an introduction to screen-casting.
The first was good for documenting things like an API and the second was good if I ever need to make a screen-cast.
I doubt that will happen, but you never know!&lt;&#x2F;li&gt;
&lt;li&gt;The last talk &quot;All roads might not lead to docs&quot; held too main takeaways for me: The quote &lt;em&gt;The Purpose of this document is ________&lt;&#x2F;em&gt; and the &lt;a href=&quot;http:&#x2F;&#x2F;voiceandtone.com&#x2F;&quot;&gt;mailchimp voice &amp;amp; tone guide&lt;&#x2F;a&gt;, which is a very good document I suggest you read it (the title is pretty self explanatory I think).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For a full list of talks given at the conference, check out the &lt;a href=&quot;http:&#x2F;&#x2F;www.writethedocs.org&#x2F;conf&#x2F;eu&#x2F;2015&#x2F;schedule&#x2F;&quot;&gt;event&#x27;s schedule&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The after party ended up happening at two venues since we got pre-maturely kicked out of the first one; we made the best of it and I got to talk to Anna Jaruga (the cloud research scientist) as well as a &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;&quot;&gt;Mozilla Development Network&lt;&#x2F;a&gt; writer, both very interesting people.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Write the Docs Day 1</title>
        <published>2015-08-31T00:00:00+00:00</published>
        <updated>2015-08-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-31/"/>
        <id>https://elijah.run/blog/2015-08-31/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-31/">&lt;p&gt;I spent most of today enjoying the Write the Docs talks and (air
conditioned) venue. I took some notes.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The keynote about the imposter syndrome was very relatable.
The coping mechanism of framing goals in &quot;I want to do...&quot; instead of &quot;I want to be...&quot; seems like it could be effective.
I liked the quote &quot;Make better mistakes tomorrow&quot;.&lt;&#x2F;li&gt;
&lt;li&gt;The second talk about naming things was very good and got me to think about the structure of documentation metadata (using labels vs taxonomy vs thesaurus, etc).
This will be useful someday I&#x27;m sure.&lt;&#x2F;li&gt;
&lt;li&gt;The third talk about [emojii] and the use of emoji was [emojii].
I never considered using them before, but I will going forward.&lt;&#x2F;li&gt;
&lt;li&gt;The fourth talk mentioned using &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Selenium_%28software%29?wprov=sfia1&quot;&gt;Selenium&lt;&#x2F;a&gt; to test docs, that just makes sense.
It&#x27;s so obvious I wish it was easier.&lt;&#x2F;li&gt;
&lt;li&gt;The API Docs talk mentioned that you should give your user the data they will be working with as a top level priority instead of an after
thought.
This will definitely be a priority for me.
I already try to give plenty of examples (since I speak example natively), but I&#x27;ll be more Conscience of it.&lt;&#x2F;li&gt;
&lt;li&gt;The Design Docs with Disability in Mind was interesting.
The big takeaway for me was keeping the elderly in mind.&lt;&#x2F;li&gt;
&lt;li&gt;The meta talk about crafting a presentation was delivered very well and mentioned adding contrast slide decks... I should have listened to
this advice...&lt;&#x2F;li&gt;
&lt;li&gt;The second to the last talk of the day covered the plethora of rules we place on documentation.
Having just recently helped established some style guides for the OSL docs I think we did a good job of giving some leeway to the writers.
The extreme example of &#x27;Limited rules docs&#x27; (e.g., the Python Documentation) does not really work well for the reader in my experience.&lt;&#x2F;li&gt;
&lt;li&gt;The final talk by some &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;&quot;&gt;MDN&lt;&#x2F;a&gt; writers equated docs to a garden. The metaphor worked surprisingly well.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For a full list of the talks and their descriptions, visit the &lt;a href=&quot;http:&#x2F;&#x2F;www.writethedocs.org&#x2F;conf&#x2F;eu&#x2F;2015&#x2F;schedule&#x2F;&quot;&gt;event&#x27;s schedule&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Day 1 was pretty emojii. We ended the night with emojii at a venue called The Pub.
Many conversations and laughs were had.
I like this crowd.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Prague Day 1</title>
        <published>2015-08-30T00:00:00+00:00</published>
        <updated>2015-08-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-30/"/>
        <id>https://elijah.run/blog/2015-08-30/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-30/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-city-center.jpg&quot; alt=&quot;Prague city center&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I went on a wonderful &lt;a href=&quot;http:&#x2F;&#x2F;www.writethedocs.org&#x2F;conf&#x2F;eu&#x2F;2015&#x2F;#events&quot;&gt;city tour&lt;&#x2F;a&gt; of Prague provided by Write The Docs.
We crossed some bridges, saw some castles, and experienced many wonderful parts of the city.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-gelato.jpg&quot; alt=&quot;My dumb face and a delicious gelato.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Here&#x27;s me in front of a church eating some gelato.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After the tour I was very hungry and tagged along with some folks from my tour group on a journey to get food.
We went to a restaurant that brought us beer on a model train.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-beer-train.jpg&quot; alt=&quot;Choo choo. Here comes the beer train.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;This is the train that brought us beer.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here are some picture I took of the buildings in the city.
I like the architecture a lot.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-city-center.jpg&quot; alt=&quot;Classic architecture in the Prague city center.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-street.jpg&quot; alt=&quot;Even the small regular old streets in Prague are breathtaking.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;They are so cool.&lt;&#x2F;em&gt;
&lt;em&gt;I haven&#x27;t found the words to describe why, but the asthetics please me.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After the tour and food there was a &lt;em&gt;Write the Docs Conference Reception&lt;&#x2F;em&gt; (aka meet &amp;amp; greet) where I got to hang out with many of the attendees of the conference.
There was food and fabulous people.&lt;&#x2F;p&gt;
&lt;p&gt;I did not have a hard time falling asleep that night.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>To Prague!</title>
        <published>2015-08-29T00:00:00+00:00</published>
        <updated>2015-08-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-29/"/>
        <id>https://elijah.run/blog/2015-08-29/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-29/">&lt;h2 id=&quot;i-strongly-dislike-travel&quot;&gt;I Strongly Dislike Travel&lt;&#x2F;h2&gt;
&lt;p&gt;I would say I hate travel, but that level of hyperbole is literally the worst thing on the planet...&lt;&#x2F;p&gt;
&lt;p&gt;My strong dislike for travel comes mostly from my personal inability to trust the systems that will get me to where I am going.
If I have a flight in one week and I have to take a bus or train to the airport, I will spend the entire week running through my head
&quot;When is my flight?
Umm days, yeesh hours, and ack minutes.
How am I getting there?
The oh God bus leaving at some time, somewhere bound.
Once you get there you will go through security which will take between 5 minutes and 2 hours.
Budget your time appropriately.
Any of these systems can fail and based on experience they have&quot;
over and over and over.
The stress is compounded when people don&#x27;t always speak your language and you forgot to eat a proper meal the morning of.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;That&lt;&#x2F;em&gt; is why I am 3 hours early to my flight from Amsterdam to Prague.
I regret nothing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;currency-is-weird&quot;&gt;Currency is Weird&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-conversion-rate.jpg&quot; alt=&quot;1 USD = 24.17 Czech Republic Koruna&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is going to take me forever to remember &lt;em&gt;25 here monies is about 1 home monies&lt;&#x2F;em&gt;.
Everything is gonna feel really expensive I bet...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;i-made-it-to-prague&quot;&gt;I Made it to Prague&lt;&#x2F;h2&gt;
&lt;p&gt;I made it to Prague just fine. They have a cool train system.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;prague-mustek-stop.jpg&quot; alt=&quot;The MUSTEK stop in the Prague underground transit system. Very Soviet-era design.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Way cooler than the underground train systems I&#x27;m used to...&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A very long bike ride</title>
        <published>2015-08-28T00:00:00+00:00</published>
        <updated>2015-08-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-28/"/>
        <id>https://elijah.run/blog/2015-08-28/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-28/">&lt;h2 id=&quot;my-butt-hurts&quot;&gt;My Butt Hurts...&lt;&#x2F;h2&gt;
&lt;p&gt;Today I went on an awesome bike ride all the way to Haarlem (15km west of Amsterdam).
I didn&#x27;t actually do anything there; I just went, picked up snacks, and headed back.
I&#x27;m 99% sure I missed out on an awesome Haarlem exclusive cultural experience, but if was really more about the journey (I originally set out to bike to the coast and Haarlem was my compromise to that).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-huge-park.jpg&quot; alt=&quot;I don&amp;#39;t recall where this park is exactly. I remember i twas east of the city center, many kilometers&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-huge-park-2.jpg&quot; alt=&quot;Another view of the park, this time with a play structure&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;I found a very neat park near the Western edge of Amsterdam; I ended up spending an hour or so there having a picnic.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Dilapidated&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-dilapidated-building.jpg&quot; alt=&quot;An old and dilapiddated building. It&amp;#39;s hard to tell the building original purpose...&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;This was a cool abandoned building I found.&lt;&#x2F;em&gt;
&lt;em&gt;I like abandoned buildings.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-travelers-trash-can.jpg&quot; alt=&quot;A large ice-cream cone shaped trashcan at a 45 degree angle for cyclists to dispose of trash into.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;I also found this awesome trash can for people riding bikes.&lt;&#x2F;em&gt;
&lt;em&gt;It&#x27;s genius.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-ponies.jpg&quot; alt=&quot;Ponies!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;PONIES&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After the bike ride I was very tired.
I slept a lot.
And yet not enough...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;small-and-large-appreciations&quot;&gt;Small (and Large) Appreciations&lt;&#x2F;h2&gt;
&lt;p&gt;Here is a list of some of the traits of Amsterdam (and what I have experienced of the Netherlands at large) which I appreciate.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;They have signs that tell you you&#x27;re going the wrong direction.&lt;&#x2F;li&gt;
&lt;li&gt;You can bike to another city and be on bike paths the whole time!&lt;&#x2F;li&gt;
&lt;li&gt;Bikes are easy to use and aren&#x27;t shoe-horned in as a second class mode of transportation.&lt;&#x2F;li&gt;
&lt;li&gt;The trains are so quiet. Why can&#x27;t America have quiet trains?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This list will probably grow as I remember things.
All in all I like the city and the country.
You should visit if you haven&#x27;t already.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Van Vough museum</title>
        <published>2015-08-27T00:00:00+00:00</published>
        <updated>2015-08-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-27/"/>
        <id>https://elijah.run/blog/2015-08-27/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-27/">&lt;p&gt;TodayI visited the Van Gough museum.
I tried to get in using my mom&#x27;s Amsterdam Museum Pass, but it didn&#x27;t fly there like it did at the Rijks.&lt;&#x2F;p&gt;
&lt;p&gt;It was pretty fun, but the entire experience felt very artificial and plastic.
The paintings were great to see in person, but everything around the pieces felt a little tacky.
My opinion will likely change about it, but I did not enjoy the Van Gough museum nearly as much as I enjoyed the Rijks Museum, despite my love for Van Gough and his works.&lt;&#x2F;p&gt;
&lt;p&gt;I spent the rest of the day walking around and cashed in early.
Jetlag + lots of walking = ready for bed by 3pm.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The Rijks museum and travel tips</title>
        <published>2015-08-26T00:00:00+00:00</published>
        <updated>2015-08-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-26/"/>
        <id>https://elijah.run/blog/2015-08-26/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-26/">&lt;h2 id=&quot;the-rijks-museum&quot;&gt;The Rijks Museum&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-canal.jpg&quot; alt=&quot;A panorama of an Amsterdam canal&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;I&#x27;m not sure which street I took this panorama on, but I think it looks awesome.&lt;&#x2F;em&gt;
&lt;em&gt;It captures the Amsterdam canal street pretty well.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Today I went to the Rijks Museum and had a bit of a culture overload.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-milk-maid.jpg&quot; alt=&quot;Chilling with the milk maid.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Everybody got selfies with Van Gough, so I got a selfie The Milkmaid.
I realize in retrospect that it doesn&#x27;t work as well.&lt;&#x2F;p&gt;
&lt;p&gt;In other news, this is my face when I realized the bathroom stalls go from floor to ceiling.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-all-the-way.jpg&quot; alt=&quot;Surprise and joy&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Yes, this photo was taken in the bathroom stall.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And this is a classy restaurant I found with classy lamps.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-cute-lamp.jpg&quot; alt=&quot;A lamp with a cute switch&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;They were closed, otherwise I would have gone in.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;some-travel-tips&quot;&gt;Some Travel Tips&lt;&#x2F;h2&gt;
&lt;p&gt;Although I have not completed my trip, I have some tips to share with you about travel.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Always bring a &#x27;Go Bag&#x27; when you go out for the day.
Fill it with snacks and necessities and leave plenty of room for memorabilia you get while out and about.&lt;&#x2F;li&gt;
&lt;li&gt;Try something new before defaulting to your comfort zone.
This is true for food as well as experiences.&lt;&#x2F;li&gt;
&lt;li&gt;Always being plenty of snacks and water.
You will regret it if you don&#x27;t.&lt;&#x2F;li&gt;
&lt;li&gt;Be patient.
You invested a lot to get here, make it count.&lt;&#x2F;li&gt;
&lt;li&gt;At a museum, take a picture of the plackard after taking a picture of the piece so you don&#x27;t forget what it&#x27;s called.&lt;&#x2F;li&gt;
&lt;li&gt;Don&#x27;t be afraid to sit in a café and just read for a bit.
Sometimes that&#x27;s as culturally diversifying as a day in a museum or city tour.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>To Amsterdam!</title>
        <published>2015-08-25T00:00:00+00:00</published>
        <updated>2015-08-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-24-2015-08-25/"/>
        <id>https://elijah.run/blog/2015-08-24-2015-08-25/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-24-2015-08-25/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-view.jpg&quot; alt=&quot;A view of amsterdam&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pdx-ams&quot;&gt;PDX -&amp;gt; AMS&lt;&#x2F;h2&gt;
&lt;p&gt;The flight was uneventful.
It was the longest one I&#x27;ve ever been on, which is always a rough milestone to overcome, but actually one of the
better flights I&#x27;ve taken.
TIL Delta&#x27;s service does not suck.&lt;&#x2F;p&gt;
&lt;p&gt;I usually sleep the entire way to &amp;lt;insert location here&amp;gt;, but I managed to stay productive (coding, reading, writing) for the majority of flight.
I must say, it was nice to have my own personal screen to catch up on Last Week Tonight.
I&#x27;ve wanted to watch that show for ages...&lt;&#x2F;p&gt;
&lt;p&gt;[&lt;em&gt;Lazy bliss not pictured&lt;&#x2F;em&gt;]&lt;&#x2F;p&gt;
&lt;p&gt;So good.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;day-0-part-1&quot;&gt;Day 0: Part 1&lt;&#x2F;h2&gt;
&lt;p&gt;So I wrote down some thoughts about Amsterdam thus far:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;People keep using fake made up words. What&#x27;s up with that?&lt;&#x2F;li&gt;
&lt;li&gt;The roads are tiny but people keep driving on them.
It looks like chaos but I haven&#x27;t seen an accident yet.
I&#x27;m kinda impressed.
People aren&#x27;t even yelling at each other about almost getting hit.&lt;&#x2F;li&gt;
&lt;li&gt;The toilet paper squares are actually rectangles.
It might just be the toilet paper at the place I am staying.
Either way, I can&#x27;t deal with this aspect ratio change. I might not be able to poop in Amsterdam.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;COFFEE COFFEE COFFEE COFFEE COFFEE COFFEE COFFEE COFFEE COFFEE&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The trains are so quiet.
I didn&#x27;t want to get off...&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;BIKES BIKES BIKES BIKES BIKES BIKES BIKES BIKES BIKES BIKES&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here&#x27;s some pictures I took:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-view.jpg&quot; alt=&quot;Mostly trees and sky.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;The view from the location I am staying at.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-park-panorama.jpg&quot; alt=&quot;Panorama of an amsterdam park&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;A panorama from the park outside of where I am staying.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-goats.jpg&quot; alt=&quot;Goats!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Some goats I found.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Aaaaaaaand naptime.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;day-0-part-2&quot;&gt;Day 0: Part 2&lt;&#x2F;h2&gt;
&lt;p&gt;I finished today by going to the Red Light District. There were a lot of half naked ladies in windows.
They kept winking at me. I&#x27;m pretty sure they liked me; it&#x27;s not like they &lt;em&gt;definitely&lt;&#x2F;em&gt; have a monetary incentive to get my attention or anything.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up finding a bar and enjoying a Belgian White Beer.
It tasted &lt;a href=&quot;https:&#x2F;&#x2F;xkcd.com&#x2F;1534&#x2F;&quot;&gt;surprisingly good&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;amsterdam-beer.jpg&quot; alt=&quot;A belgium white beer&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;So this is what it feels like to drink in a bar... neat.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Packed and Ready to Fly</title>
        <published>2015-08-23T00:00:00+00:00</published>
        <updated>2015-08-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-23/"/>
        <id>https://elijah.run/blog/2015-08-23/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-23/">&lt;h2 id=&quot;all-packed&quot;&gt;All Packed&lt;&#x2F;h2&gt;
&lt;p&gt;So I&#x27;m all packed up and ready to go.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;europe-2015&#x2F;packed.jpg&quot; alt=&quot;Three weeks of supplies neatly displayed on a pink bed&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Left:&lt;&#x2F;strong&gt; Chargers, electronics, entertainment, toiletries, water bottle, wallet, etc.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Center:&lt;&#x2F;strong&gt; The bag, the &lt;em&gt;Write the Docs&lt;&#x2F;em&gt; shirt I&#x27;ll be wearing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Right:&lt;&#x2F;strong&gt; Clothing. Gameboy SP at the top.&lt;&#x2F;p&gt;
&lt;p&gt;Not the &lt;em&gt;perfect&lt;&#x2F;em&gt; bag of things to bring to Europe, but certainly solid and most of it practical.
I&#x27;m packing an extra bag for all of the trinkets I&#x27;ll bring back.&lt;&#x2F;p&gt;
&lt;p&gt;Let me know if you want anything (if you know how to contact me we&#x27;re close enough for you to ask.)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Dominos are setup</title>
        <published>2015-08-02T00:00:00+00:00</published>
        <updated>2015-08-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-02/"/>
        <id>https://elijah.run/blog/2015-08-02/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-02/">&lt;p&gt;All of my travel is booked, plane tickets are bought, and vacation time gotten.&lt;&#x2F;p&gt;
&lt;p&gt;The only thing left to do now is to write the talk. Easy-peasy.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>About the blog (this is a test)</title>
        <published>2015-08-01T00:00:00+00:00</published>
        <updated>2015-08-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Elijah Voigt
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://elijah.run/blog/2015-08-01/"/>
        <id>https://elijah.run/blog/2015-08-01/</id>
        
        <content type="html" xml:base="https://elijah.run/blog/2015-08-01/">&lt;p&gt;This blog was created in preparation for my trip to Europe in about 3 weeks.
I wanted to see how difficult it would be to make a blog that could be updated on the go, version controlled with git, and would not require me to log into a laptop or server to make changes.&lt;&#x2F;p&gt;
&lt;p&gt;I ended up using PageUp (link in the footer), along with Github Gists (also linked in the footer) to make a mostly useful platform.
New changes are pushed to Github, my personal server pulls those changes every 10 minutes, and this page is rebuilt pretty painlessly.&lt;&#x2F;p&gt;
&lt;p&gt;Best of all: with a git client on my phone I can make updates anywhere that has a signal and I don&#x27;t need to bust my laptop out.
I wrote this post while I was on the toilet!&lt;&#x2F;p&gt;
&lt;p&gt;It wasn&#x27;t as easy as using an established platform like Twitter, but just like with everything I try to make, I put something together I would want to use and interact with.
If a friend started a liveblog for a specific event I would follow it over their Twitter feed any day.
Plus I don&#x27;t have to deal with the character limit of Twitter.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
