<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Lord.io</title>
  <link href="https://lord.io/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://lord.io"/>
  <updated>2026-01-23T00:00:00+00:00</updated>
  <id>https://lord.io</id>
  <entry xml:lang="en">
    <title>A Programmer&#x27;s Guide to Leaving GitHub</title>
    <published>2026-01-23T00:00:00+00:00</published>
    <updated>2026-01-23T00:00:00+00:00</updated>
    <link href="https://lord.io/leaving-github/" type="text/html"/>
    <id>https://lord.io/blog/2026/leaving-github/</id>
    <content type="html">&lt;p&gt;If you subscribe to many programming blogs, chances are you&#x27;ve come across a post describing someone&#x27;s move off GitHub. They started as far back as the Microsoft acquisition in 2018, but they&#x27;ve increased in frequency recently. Both the &lt;a href=&quot;https:&#x2F;&#x2F;ziglang.org&#x2F;news&#x2F;migrating-from-github-to-codeberg&#x2F;&quot;&gt;Zig&lt;&#x2F;a&gt; programming language and &lt;a href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;leiningen&#x2F;leiningen&#x2F;src&#x2F;branch&#x2F;main&#x2F;.github&#x2F;README.md&quot;&gt;Leiningen&lt;&#x2F;a&gt; build tool wrote about their move to other platforms late last year. I&#x27;ve drawn inspiration from these posts, and the countless similar posts from individual programmers. However, since they&#x27;re mostly informational announcements telling people to update their repository URLs, they tend to only briefly mention the reasons the author chose to leave. They don&#x27;t try too hard to convince a skeptical reader that perhaps they could leave GitHub too.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m going to migrate all my personal projects off of GitHub this weekend, in support of today&#x27;s general strike in Minnesota. Instead of the traditional brief message, I&#x27;ll instead try to record my thought process a little more deeply: my research into which groups have active protests of GitHub, why I think GitHub is a particularly suitable target, and what makes a boycott more or less effective. Migrating your open source projects off GitHub is obviously not the most radical, impactful action you could be taking right now, but also it&#x27;s pretty easy! If you happen across this blog post, I hope you will consider it.&lt;&#x2F;p&gt;
&lt;p&gt;There are many groups protesting GitHub and Microsoft, but I&#x27;ll discuss these four in this post:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;sfconservancy.org&#x2F;GiveUpGitHub&#x2F;&quot;&gt;&amp;quot;Give Up GitHub&amp;quot;&lt;&#x2F;a&gt; campaign kicked off in 2022. The Software Freedom Conservatory (the non-profit that provides legal support for Wine, Inkscape, QEMU, Git, and many more free software projects) organized this . They cite how the GitHub platform itself is closed source software, instances of Copilot spitting out verbatim GPL code (a form of plagiarism), and fears over Microsoft&#x27;s reorganization of all of GitHub under a &amp;quot;CoreAI&amp;quot; product division. They also point to GitHub&#x27;s 2020 contracts with ICE, the controversial and violent immigration police here in the United States.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;www.fsf.org&#x2F;blogs&#x2F;community&#x2F;keep-putting-pressure-on-microsoft&quot;&gt;Free Software Foundation&lt;&#x2F;a&gt; since at least 2024 have told the free software community to move projects off of GitHub to apply pressure on Microsoft, pointing again to Github&#x27;s proprietary server code, as well as Microsoft&#x27;s decision to require computers running Windows 11 to have a &amp;quot;Trusted Platform Module&amp;quot;; I&#x27;ll let the FSF post explain why you might want to protest that.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;bdsmovement.net&#x2F;microsoft&quot;&gt;Palestinian BDS National Committee&lt;&#x2F;a&gt; upgraded Microsoft from a &amp;quot;pressure&amp;quot; target to a &amp;quot;priority&amp;quot; boycott target in 2025, describing Microsoft as &amp;quot;perhaps the most complicit tech company&amp;quot; in Israel&#x27;s apartheid. BDS has already claimed two major wins here. In 2020, controversy forced Microsoft to divest its stake in AnyVision, a Israeli facial recognition startup used at checkpoints in the West Bank. Then, in 2025, Microsoft terminated Azure services for a subagency of the Israeli military called Unit 8200; this was right after a news article revealed they used Azure to process millions of intercepted phone call recordings from Palestinian civilians to determine where to fire lethal airstrikes in Gaza. BDS and the 2000+ Microsoft employees that signed &lt;a href=&quot;https:&#x2F;&#x2F;noazureforapartheid.com&#x2F;&quot;&gt;No Azure For Apartheid&lt;&#x2F;a&gt;, along with many other organizations (including a global network of MSFT-shareholding &lt;a href=&quot;https:&#x2F;&#x2F;afsc.org&#x2F;newsroom&#x2F;unprecedented-investor-action-demands-microsoft-answer-reported-involvement-gaza-genocide&quot;&gt;catholic nuns&lt;&#x2F;a&gt;) continue to protest the Azure services Microsoft provides to the rest of the Israeli military.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.beyondtheballot.org&#x2F;iceout&quot;&gt;&amp;quot;ICE Out of My Wallet&amp;quot;&lt;&#x2F;a&gt; launched in 2025, listing Microsoft as one of just seven top targets for a consumer boycott. Their goal is to put pressure on the $20M+ in Azure services Microsoft provides annually to ICE. (The official boycott currently just lists Microsoft devices as targets, not GitHub.) Back in 2019, there were also mass protests against GitHub&#x27;s direct contracts with ICE to host their code; as far as I&#x27;m aware, they still host code for ICE today.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I&#x27;ve personally chosen to leave GitHub this weekend in support of today&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;2026_Minnesota_general_strike&quot;&gt;general strike&lt;&#x2F;a&gt; in Minnesota, and in protest of ICE&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Killing_of_Ren%C3%A9e_Good&quot;&gt;murder of Renée Good&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;github-s-weaknesses&quot;&gt;GitHub&#x27;s weaknesses&lt;&#x2F;h2&gt;
&lt;p&gt;I have four reasons why I want to specifically target GitHub in this post. First, for independent programmers, I think it&#x27;s incredibly simple and straightforward to move your personal open source projects off of GitHub. Unlike quitting, say, Instagram or TikTok, which centralize and tightly control content discovery, the network effects keeping projects on GitHub are substantially weaker. When you quit Instagram, you become invisible; when you quit GitHub, you instead just add a small speed-bump for contributors. I also see particular ease when migrating a &lt;em&gt;small&lt;&#x2F;em&gt; project. Your small project has no CTO you need to convince, no 400-engineer monorepo, and no half-forgotten custom scripts calling GitHub&#x27;s APIs, written by a coworker who quit a year ago. If your project depends on many strangers submitting drive-by pull requests, moving off GitHub will impose extra costs on you, and you may want to consider more carefully whether this is a cost you&#x27;re willing to pay. But the vast majority of public repos — personal projects with few external contributors — will find leaving GitHub to be relatively frictionless.&lt;&#x2F;p&gt;
&lt;p&gt;Second, although you likely don&#x27;t pay GitHub to host your open-source projects, they still make money from them! When my blog links to an open source project I&#x27;ve published GitHub, they don&#x27;t just get to put their logo in front of some eyeballs for free; they also get my implicit endorsement, helping establish GitHub as the default choice for companies deciding where to put their internal repos and who to pay for LLM autocomplete. You might find this point kind of banal, but I really just want to emphasize it: by putting your personal projects on GitHub, you are providing them a valuable service! If your account is small, it may just be a tiny amount of value. But they find it valuable nonetheless, and I think this small amount of value matches the very small amount of effort it takes to move most of your code somewhere else.&lt;&#x2F;p&gt;
&lt;p&gt;Third, GitHub&#x27;s web interface has been in a steepening decline since the Microsoft acquisition in 2018, making it a less appealing place to put your code even without these ongoing protests. Why does an uncached page load of my repository&#x27;s root take 2500ms, from New York City no less, with gigabit, 17ms ping internet? Why does GitHub Actions choose jobs to run &amp;quot;seemingly at random&amp;quot;, causing &lt;a href=&quot;https:&#x2F;&#x2F;ziglang.org&#x2F;news&#x2F;migrating-from-github-to-codeberg&#x2F;&quot;&gt;Zig&#x27;s&lt;&#x2F;a&gt; CI to not even run on the main branch? Why does the settings page for enabling and disabling the 16 available LLM models take up two vertical laptop screens, and why, instead of a simple checkbox, does each dropdown have three possible states: &amp;quot;enabled&amp;quot;, &amp;quot;disabled&amp;quot;, and the mysterious &amp;quot;Select an option&amp;quot;?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2026&#x2F;github-settings.png&quot; alt=&quot;a screenshot of a fragment of github&#x27;s settings page, showing various models taking up a lot of vertical space, with redundant text under each one saying &amp;quot;You can use the latest Google Gemini 2.5 Pro model. Learn more about how GitHub Copilot serves Google Gemini 2.5 Pro&amp;quot;, &amp;quot;You can use the latest Google Gemini 3 Pro model. Learn more about how GitHub Copilot serves Google Gemini 3 Pro.&amp;quot; etc again and again. next to each repeated paragraph is a dropdown, one reads &#x27;enabled&#x27;, one &#x27;disabled&#x27;, and one &#x27;select an option&#x27;.&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally, I think open source communities, with roots in hacker culture from the 80s and 90s, form a particularly fertile soil for this sort of action. Many programmers contribute to open source projects for non-commercial reasons: out of a deep love for programming, or an ethical belief everyone should have the right to read and modify the code on their computer. Hackers also have a long history of general repulsion from Microsoft.&lt;&#x2F;p&gt;
&lt;p&gt;This history, however, is a double edged sword. As programmers, we are primed by this history to think individually instead of collectively. I have many friends who would agree with the causes above, and yet might resist participation in a GitHub protest. Even if you are someone who in general might join a boycott, once you hear that the plan is to convince a bunch of &lt;em&gt;programmers&lt;&#x2F;em&gt; — good luck, but clearly that plan won&#x27;t work. Here, I think the choice of Microsoft is helpful, because I don&#x27;t &lt;em&gt;need&lt;&#x2F;em&gt; to convince some critical mass of programmers. Instead, I get to play a tiny part in a large and global movement that already has momentum, made up of people who have never been burdened by the words &amp;quot;rebase merge conflict&amp;quot; before. I&#x27;ve chosen GitHub as a target so that my action mirrors the already-successful efforts of many others.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;some-strategies-are-better-than-others&quot;&gt;Some strategies are better than others&lt;&#x2F;h2&gt;
&lt;p&gt;I have a vivid memory from a little over a decade ago, when I saw Richard Stallman speak about free software at an auditorium in lower Manhattan. In this speech, he cast as wide a net as he could, listing off the misdeeds of tech company after tech company and describing how we should stop using their products. (When one or two people in the audience quietly made their way to the exit — he had been talking long past the allotted time — he started castigating them for leaving before he was done.) His personal website today continues the tradition:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2026&#x2F;stallman-website.png&quot; alt=&quot;a screenshot of Richard Stallman&#x27;s personal site. the bottom half of the screenshot shows a navigation bar that reads &#x27;whats bad about: airbnb | amazon | amtrak | ancestry | apple | change.org | chatgpt ... it continues but i will spare you from having to listen to the entire list&quot; style=&quot;width: 500px; border: 1px solid rgba(0,0,0,0.1)&quot;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If my understanding of boycotts came from this speech, I would absolutely lean anti-boycott, but I&#x27;d like to convince you that there is another way! Boycott strategy makes a massive difference in efficacy. Stallman could learn a lot from the &lt;a href=&quot;https:&#x2F;&#x2F;bdsmovement.net&#x2F;BDS-Guide-Strategic-Campaigning&quot;&gt;BDS National Committee&lt;&#x2F;a&gt;, whose approach in turn was inspired by the highly visible South African anti-apartheid movement. Here&#x27;s my own list of what has resonated with me:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don&#x27;t protest everything all at once&lt;&#x2F;strong&gt;: We call it a &amp;quot;targeted boycott&amp;quot; for a reason. Target just a handful of companies with the most egregious violations, and in the common situation where you have complaints against all major vendors offering some service, don&#x27;t boycott all of them. Make it easy for people to switch to an alternative, even if you&#x27;re implicitly advocating for an imperfect company. Here, GitHub is a great target because many movements list Microsoft as a top target, and we have many free, open source alternatives.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Build cross-movement coalitions&lt;&#x2F;strong&gt;: BDS chose Chevron as a priority target in part because many climate activist groups already have active protests against oil companies. The Software Freedom Conservatory chose GitHub as a primary target in part because anti-ICE activists protested it in 2020. When you boycott GitHub, you get to participate in several boycotts all at once.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Cite specific, achievable goals&lt;&#x2F;strong&gt;: unfortunately free software boycotts sometimes have vague goals, like &amp;quot;stop discrediting the GPL&amp;quot;. At other times, they cite specific goals that existentially threaten a company, like &amp;quot;release the source code to &lt;em&gt;all&lt;&#x2F;em&gt; of your software&amp;quot; or &amp;quot;only train your language models on public domain code.&amp;quot; I think asking for Microsoft to cancel their contracts with the IDF and ICE are concrete goals, and Microsoft could do it without completely destroying itself.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Protest publicly&lt;&#x2F;strong&gt;: I&#x27;ve seen some programmers delete their GitHub accounts silently, saying that their choice to leave is a personal one. I definitely can empathize with this sentiment — this feeling was hard for me to get over when writing this post. I feared it self-aggrandized what is truly a microscopic drop in the bucket. At the same time, I think there is incredible value to speaking publicly about why you&#x27;re leaving, assuming it&#x27;s safe for you to do so. In addition to this post, I also plan to not delete any repositories, instead replacing their contents with a README that explains my departure.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Don&#x27;t worry about perfection&lt;&#x2F;strong&gt;: I&#x27;ve seen some worry online that it&#x27;s impossible to delete your GitHub account when there are still so many open source projects that use it. I agree! I plan to still use GitHub if I need it to contribute to other projects.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That&#x27;s all I&#x27;ve got to say! What follows is some optional resources that you might find useful if you decide to make the move yourself. Thanks for reading this far, and if you&#x27;re in Minnesota today, I hope you stay warm out there. ∎&lt;&#x2F;p&gt;
&lt;h2 id=&quot;appendix-a-table-of-github-alternatives&quot;&gt;Appendix A: Table of GitHub alternatives&lt;&#x2F;h2&gt;
&lt;div class=&quot;data-table-wrapper&quot;&gt;
&lt;table class=&quot;data-table&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;  style=&quot;min-width: 800px;&quot;&gt;&lt;thead&gt;
    &lt;tr&gt;&lt;th&gt;name&lt;&#x2F;th&gt;&lt;th&gt;license&lt;&#x2F;th&gt;&lt;th&gt;who is behind it&lt;&#x2F;th&gt;&lt;th&gt;code review&lt;&#x2F;th&gt;&lt;th style=&quot;min-width: 140px;&quot;&gt;is it objectively ugly&lt;&#x2F;th&gt;&lt;th&gt;notes&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;thead&gt;&lt;tbody&gt;
    &lt;tr&gt;&lt;th colspan=&quot;6&quot;&gt;Centrally hosted (with self-hosting as an option)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;&quot;&gt;Codeberg&lt;&#x2F;a&gt;&#x2F;&lt;a href=&quot;https:&#x2F;&#x2F;forgejo.org&#x2F;&quot;&gt;Forgejo&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;GPL&lt;&#x2F;td&gt;&lt;td&gt;nonprofit based in Germany&lt;&#x2F;td&gt;&lt;td class=&quot;data-table-mute&quot;&gt;branch-based&lt;&#x2F;td&gt;&lt;td class=&quot;data-table-mute&quot;&gt;no&lt;&#x2F;td&gt;&lt;td&gt;FOSS or noncommercial projects only; fork of gitea&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;sourcehut.org&#x2F;&quot;&gt;SourceHut&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;AGPL&lt;&#x2F;td&gt;&lt;td&gt;indie for-profit, not VC funded&lt;&#x2F;td&gt;&lt;td&gt;git send-email&lt;&#x2F;td&gt;&lt;td&gt;ugly (in a good way)&lt;&#x2F;td&gt;&lt;td&gt;costs $4–12&#x2F;month, financial aid available&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;about.gitea.com&#x2F;&quot;&gt;Gitea&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;MIT&lt;&#x2F;td&gt;&lt;td&gt;small startup, VC backed&lt;&#x2F;td&gt;&lt;td class=&quot;data-table-mute&quot;&gt;branch-based&lt;&#x2F;td&gt;&lt;td&gt;ugly (some parts)&lt;&#x2F;td&gt;&lt;td&gt;weird vibes, and the free cloud hosting seems sort of like a demo instance; fork of Gogs&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;rluna-gitlab&#x2F;gitlab-ce&quot;&gt;GitLab CE&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;MIT&lt;&#x2F;td&gt;&lt;td&gt;publicly traded company&lt;&#x2F;td&gt;&lt;td&gt;branch-based with stacking&lt;&#x2F;td&gt;&lt;td&gt;just ugly&lt;&#x2F;td&gt;&lt;td&gt;limited features for free accounts&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;th colspan=&quot;6&quot;&gt;Decentralized&#x2F;federated&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.tangled.org&#x2F;intro&quot;&gt;Tangled&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;MIT&lt;&#x2F;td&gt;&lt;td&gt;small startup, $300k+ in VC funding&lt;&#x2F;td&gt;&lt;td&gt;patch-based with stacking&lt;&#x2F;td&gt;&lt;td class=&quot;data-table-mute&quot;&gt;no&lt;&#x2F;td&gt;&lt;td&gt;no private repos, built on ATProtocol&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;radicle.xyz&#x2F;&quot;&gt;Radicle&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;MIT+Apache&lt;&#x2F;td&gt;&lt;td&gt;some ethereum thing, $12M+ in VC funding&lt;&#x2F;td&gt;&lt;td&gt;patch-based&lt;&#x2F;td&gt;&lt;td class=&quot;data-table-mute&quot;&gt;no&lt;&#x2F;td&gt;&lt;td&gt;private repos must be self-hosted&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;th colspan=&quot;6&quot;&gt;Self-hosted only&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;code.lord.io&#x2F;j3&#x2F;&quot;&gt;j3&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;GPL&lt;&#x2F;td&gt;&lt;td&gt;i wrote it myself last week&lt;&#x2F;td&gt;&lt;td&gt;no code review&lt;&#x2F;td&gt;&lt;td&gt;i like to think not&lt;&#x2F;td&gt;&lt;td&gt;barebones read-only web ui&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.gerritcodereview.com&#x2F;&quot;&gt;Gerrit&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;Apache&lt;&#x2F;td&gt;&lt;td&gt;Google&lt;&#x2F;td&gt;&lt;td&gt;patch-based with stacking&lt;&#x2F;td&gt;&lt;td&gt;ugly&lt;&#x2F;td&gt;&lt;td&gt;code hosting&#x2F;review only; no issues, etc&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gogs.io&#x2F;&quot;&gt;Gogs&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;MIT&lt;&#x2F;td&gt;&lt;td&gt;single maintainer&lt;&#x2F;td&gt;&lt;td class=&quot;data-table-mute&quot;&gt;branch-based&lt;&#x2F;td&gt;&lt;td class=&quot;data-table-mute&quot;&gt;no&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;My personal take on these options: since these days my projects mostly don&#x27;t have external contributors, I&#x27;ve chosen to move them to &lt;a href=&quot;https:&#x2F;&#x2F;code.lord.io&#x2F;j3&#x2F;&quot;&gt;j3&lt;&#x2F;a&gt;, a small local binary I wrote in Rust that lets you use an s3 bucket as a Git remote, and automatically pushes a read-only web UI to the bucket&#x27;s &lt;code&gt;index.html&lt;&#x2F;code&gt;. If I had a startup that needed private code hosting, I would probably set up a Gerrit instance. If I was working on an open source project that wanted to make it easy for people in the open-source community to contribute, I would probably choose Codeberg, assuming I was not tempted by Tangled&#x27;s code review workflow.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What is &amp;quot;patch-based&amp;quot; code review?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re familiar with GitHub&#x27;s pull request workflow, you&#x27;ve done &lt;em&gt;branch&lt;&#x2F;em&gt;-based merges before. You prepare a branch with your changes, and then submit a pull request asking to merge your branch into &lt;code&gt;main&lt;&#x2F;code&gt;. If somebody gives you feedback, you push additional commits on top of your base commit. In contrast, with the &lt;em&gt;patch&lt;&#x2F;em&gt;-based merge workflow originally popularized by Gerrit, you amend the existing commit and push it — something like &lt;code&gt;git commit --amend &amp;amp;&amp;amp; git push --force&lt;&#x2F;code&gt;. If you try this in GitHub, this would make the original commit you pushed disappear, but in patch-based review tools, your reviewers will instead see a diff from the original commit to the new one. In general, I&#x27;m trying to move towards patch-based workflows, since they work better with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jj-vcs&#x2F;jj&quot;&gt;jiujutsu&lt;&#x2F;a&gt;. &amp;quot;Stacking&amp;quot; here means it&#x27;s easy to submit multiple pull requests for simultaneous code review, where each pull request builds upon the changes from the prior one in a chain. On GitHub, this is very difficult!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;appendix-b-migration-bash-scripts&quot;&gt;Appendix B: Migration bash scripts&lt;&#x2F;h2&gt;
&lt;p&gt;To do the migration, I used the &lt;code&gt;gh&lt;&#x2F;code&gt; GitHub CLI (&lt;code&gt;brew install gh &amp;amp;&amp;amp; gh auth login&lt;&#x2F;code&gt; on mac) extensively. To start, I cloned all my repos into three folders: &lt;code&gt;migrate&lt;&#x2F;code&gt; holds non-fork public repos, &lt;code&gt;archive&lt;&#x2F;code&gt; holds public forks, and &lt;code&gt;private&lt;&#x2F;code&gt; holds all private repos. The plan is to migrate public repos to a publicly visible host, migrate private repos to somewhere else, and archive most forks in-place on GitHub after adding a notice to the readme.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffd580;&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span&gt; migrate archive private
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; migrate &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&amp;amp;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span&gt; repo list&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --visibility&lt;&#x2F;span&gt;&lt;span&gt; public&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --source --json&lt;&#x2F;span&gt;&lt;span&gt; sshUrl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --limit&lt;&#x2F;span&gt;&lt;span&gt; 10000&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --jq &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;.[].sshUrl&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -I &lt;&#x2F;span&gt;&lt;span&gt;{} git clone {})
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; archive &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&amp;amp;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span&gt; repo list&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --visibility&lt;&#x2F;span&gt;&lt;span&gt; public&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --fork --json&lt;&#x2F;span&gt;&lt;span&gt; sshUrl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --limit&lt;&#x2F;span&gt;&lt;span&gt; 10000&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --jq &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;.[].sshUrl&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -I &lt;&#x2F;span&gt;&lt;span&gt;{} git clone {})
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; private &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&amp;amp;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span&gt; repo list&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --visibility&lt;&#x2F;span&gt;&lt;span&gt; private&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --json&lt;&#x2F;span&gt;&lt;span&gt; sshUrl&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --limit&lt;&#x2F;span&gt;&lt;span&gt; 10000&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --jq &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;.[].sshUrl&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -I &lt;&#x2F;span&gt;&lt;span&gt;{} git clone {})
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point, I sorted through the list of repos, moving any that needed individual attention out of these three folders. I also skimmed through the &lt;code&gt;archive&lt;&#x2F;code&gt; folder to see if there were any forks that deserved to be moved to &lt;code&gt;migrate&lt;&#x2F;code&gt; instead of just getting archived. This script prints which repos have external collaborators, which was useful here:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffd580;&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span&gt; repo list&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --visibility&lt;&#x2F;span&gt;&lt;span&gt; public&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --json&lt;&#x2F;span&gt;&lt;span&gt; nameWithOwner&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --limit&lt;&#x2F;span&gt;&lt;span&gt; 10000&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --jq &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;.[].nameWithOwner&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;|
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -I &lt;&#x2F;span&gt;&lt;span&gt;{} gh api &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;repos&#x2F;{}&#x2F;collaborators&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --jq &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;if length &amp;gt; 1 then &amp;quot;{}: \([.[].login] | join(&amp;quot;, &amp;quot;))&amp;quot; else empty end&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, for every repo to migrate, I pushed all branches and tags to the new site. This script worked for my &lt;a href=&quot;https:&#x2F;&#x2F;code.lord.io&#x2F;j3&#x2F;&quot;&gt;j3&lt;&#x2F;a&gt; remote, where
pushing to a new remote implicitly creates a repo, but if you&#x27;re uploading to codeberg or similar you&#x27;ll need to change
neworigin&#x27;s url, and probably add a command to actually create the repo.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffd580;&quot;&gt;pushd&lt;&#x2F;span&gt;&lt;span&gt; migrate
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; dir &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;pushd &lt;&#x2F;span&gt;&lt;span&gt;$dir
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; remote add neworigin j3:&#x2F;&#x2F;$ID_KEY:$ID_SECRET@$BUCKET_REMOTE&#x2F;code&#x2F;$dir
&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:#5c6773;&quot;&gt;# per https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;59745167
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; symbolic-ref&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --delete&lt;&#x2F;span&gt;&lt;span&gt; refs&#x2F;remotes&#x2F;origin&#x2F;HEAD
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; push neworigin&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --tags &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;refs&#x2F;remotes&#x2F;origin&#x2F;*:refs&#x2F;heads&#x2F;*&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:#ffd580;&quot;&gt;popd
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;done
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;popd
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, I replaced the repos on GitHub with a notice. I created a new &lt;code&gt;migration-notice&lt;&#x2F;code&gt; orphan
branch in the hope that this reduces the risk of downstream problems. I ran a similar script
on the &lt;code&gt;archive&lt;&#x2F;code&gt; directory; I decided to leave existing branches in-place there, since I wasn&#x27;t
migrating them.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffd580;&quot;&gt;pushd&lt;&#x2F;span&gt;&lt;span&gt; migrate
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; dir &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;ls&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;pushd &lt;&#x2F;span&gt;&lt;span&gt;$dir
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# mark as unarchived if its archived rn, so we can add the notice
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span&gt; repo unarchive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --yes
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; switch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --orphan&lt;&#x2F;span&gt;&lt;span&gt; migration-notice
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;cat &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; readme.md &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;lt;&amp;lt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;I have chosen to migrate my projects off of GitHub until Microsoft terminates its contracts with ICE and
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;the IDF. A [read-only archive](https:&#x2F;&#x2F;code.lord.io&#x2F;$&lt;&#x2F;span&gt;&lt;span&gt;dir&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&#x2F;) of this repo is still available.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;You can read more about my decision to leave on [my blog](https:&#x2F;&#x2F;lord.io&#x2F;leaving-github&#x2F;).
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;EOF
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; add readme.md
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; commit&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -m &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;add migration readme&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; push origin migration-notice
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span&gt; repo edit&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --default-branch&lt;&#x2F;span&gt;&lt;span&gt; migration-notice
&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:#5c6773;&quot;&gt;# delete branches that aren&amp;#39;t migration-notice
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; branch&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -r &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;grep &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39; origin&#x2F;&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -v &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;migration-notice$&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -v&lt;&#x2F;span&gt;&lt;span&gt; HEAD &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;cut&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -f2- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;xargs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -I &lt;&#x2F;span&gt;&lt;span&gt;{} git push origin :heads&#x2F;{}
&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:#5c6773;&quot;&gt;# mark the repo as archived
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span&gt; repo archive&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; --yes
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;popd
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;done
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;popd
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;appendix-c-github-stars-and-network-effects&quot;&gt;Appendix C: GitHub stars and network effects&lt;&#x2F;h2&gt;
&lt;p&gt;If you want people to discover your personal projects, you might say that GitHub stars, forks, and followers are a great way to enable this. While this is an interesting question, and I&#x27;m sure some people find these tools valuable, my personal experience has been that few people look at their GitHub feed, and this was before the Copilot prompt box pushed it further down the homepage. I&#x27;ve also heard it got diluted by LLM-generated bug reports, but honestly, I don&#x27;t look at it any more.&lt;&#x2F;p&gt;
&lt;p&gt;To show one data point using star counts as a proxy for attention, I had a little over 700 followers in 2020, so while I wasn&#x27;t one of the most followed users on GitHub, I still had more followers than the vast majority of GitHub users. Throughout 2020, I worked publicly on a Rust side project called Anchors, which by October had accrued a grand total of 4 stars. On November 9th, I published &lt;a href=&quot;&#x2F;spreadsheets&#x2F;&quot;&gt;How to Recalculate a Spreadsheet&lt;&#x2F;a&gt;, a tedious and technical blog post which discussed Anchors starting about 2000 words in. By the next day, Anchors jumped to 19 stars, and then (despite essentially zero code changes to the Anchors project itself) slowly climbed up to ~130 stars by late 2023. Clearly the blog post was the catalyst for these stars, and without it, Anchors would still have single digit stars today. That said, I can&#x27;t prove to you that GitHub&#x27;s feed didn&#x27;t &lt;em&gt;multiply&lt;&#x2F;em&gt; the attention the repo got from the blog post. But at an average rate of 1 star every 10 days, and given the minimal stars the project had prior to the blog post, I guess it&#x27;s hard for me to imagine GitHub&#x27;s feed played a major role.&lt;&#x2F;p&gt;
&lt;p&gt;Assuming it&#x27;s even your goal for your project to get discovered by others (for most of my projects it is not!) I think your side project will likely reach orders of magnitude more people on Bluesky, Twitter, or your personal blog than they will via GitHub. GitHub stars are a good sign of social proof, but I would argue they don&#x27;t serve this role substantially better than stars on Codeberg.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;appendix-d-further-reading&quot;&gt;Appendix D: Further reading&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve already mentioned &lt;a href=&quot;https:&#x2F;&#x2F;ziglang.org&#x2F;news&#x2F;migrating-from-github-to-codeberg&#x2F;&quot;&gt;Zig&#x27;s&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;leiningen&#x2F;leiningen&#x2F;src&#x2F;branch&#x2F;main&#x2F;.github&#x2F;README.md&quot;&gt;Leiningen&#x27;s&lt;&#x2F;a&gt; posts, but if you want to read what individual people have said about leaving GitHub, here is what I could find:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;ratfactor.com&#x2F;leaving-github&quot;&gt;Dave Gauer&lt;&#x2F;a&gt; (2023)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;davideisinger.com&#x2F;journal&#x2F;migrating-from-github-to-sourcehut&#x2F;&quot;&gt;David Eisinger&lt;&#x2F;a&gt; (2024)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;jamesbrind.uk&#x2F;posts&#x2F;sourcehut&#x2F;&quot;&gt;James Brind&lt;&#x2F;a&gt; (2022)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;kordex.dev&#x2F;blog&#x2F;2025-09-08&#x2F;moving-to-codeberg&quot;&gt;Kord Extensions&lt;&#x2F;a&gt; (2025)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;janikvonrotz.ch&#x2F;2025&#x2F;08&#x2F;20&#x2F;migrate-from-github-to-codeberg&#x2F;&quot;&gt;Janik von Rotz&lt;&#x2F;a&gt; (2025)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;loganconnolly.com&#x2F;post&#x2F;goodbye-github&#x2F;&quot;&gt;Logan Connolly&lt;&#x2F;a&gt; (2023)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;macoy.me&#x2F;blog&#x2F;programming&#x2F;LeavingGitHub&quot;&gt;Macoy Madson&lt;&#x2F;a&gt; (2022)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;ntietz.com&#x2F;blog&#x2F;moving-off-github&#x2F;&quot;&gt;Nicole Tietz-Sokolskaya&lt;&#x2F;a&gt; (2022)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;nilsnh.no&#x2F;2024&#x2F;07&#x2F;15&#x2F;divesting-from-github-and-going-self-hosted&#x2F;&quot;&gt;Nils Norman Haukås&lt;&#x2F;a&gt; (2024)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;samthursfield.wordpress.com&#x2F;2025&#x2F;11&#x2F;27&#x2F;bollocks-to-github&#x2F;&quot;&gt;Sam Thursfield&lt;&#x2F;a&gt; (2025)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.chiark.greenend.org.uk&#x2F;~sgtatham&#x2F;quasiblog&#x2F;git-no-forge&#x2F;&quot;&gt;Simon Tatham&lt;&#x2F;a&gt; (2025)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;tomscii.sig7.se&#x2F;2024&#x2F;01&#x2F;Ditching-GitHub&quot;&gt;Tom Szilagyi&lt;&#x2F;a&gt; (2024)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;appendix-e-richard-stallman-a-free-digital-society-new-york-2014&quot;&gt;Appendix E: Richard Stallman, &amp;quot;A Free Digital Society&amp;quot; (New York, 2014)&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2026&#x2F;stallman-speech.jpg&quot; alt=&quot;a screenshot from a youtube video of richard stallman speaking in front of an audience; he is sitting in a chair, and has no shoes on. the subtitle reads &amp;quot;why are people all leaving? did they think the talk was going to be over this soon?&amp;quot; the video timestamp shows we are 1 hour 36 minutes into a 2 hour, 44 minute speech.&quot;&gt;&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>How to Recalculate a Spreadsheet</title>
    <published>2020-11-09T00:00:00+00:00</published>
    <updated>2020-11-09T00:00:00+00:00</updated>
    <link href="https://lord.io/spreadsheets/" type="text/html"/>
    <id>https://lord.io/blog/2020/spreadsheets/</id>
    <content type="html">&lt;p&gt;Let&#x27;s say I&#x27;m ordering burritos for my two friends while they quarantine in Jersey City, and want to calculate the total price of my order:&lt;&#x2F;p&gt;
&lt;div style=&quot;max-width: 439px;&quot;&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_0_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&quot;screenshot of spreadsheet; burrito price is listed as $7, burrito price w ship as burrito price plus $3, num burritos is 2, and total is num burritos times burrito price w ship, for a total of $20&quot; src=&quot;&#x2F;images&#x2F;2020&#x2F;anchors_0.png&quot;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;div&gt;
&lt;p&gt;It&#x27;s a little confusing to follow the flow of data in a spreadsheet when it&#x27;s written like that, so I hope you don&#x27;t mind this equivalent diagram that represents it as a graph:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_1_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;the previous spreadsheet represented as a graph, with arrows from one cell to another replacing the spreadsheet cell references&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_1.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;re rounding the cost of an El Farolito super vegi burrito to $8, so assuming the per-burrito delivery toll remains at just $2 per burrito, it looks like the total for our two burritos will be $20.&lt;&#x2F;p&gt;
&lt;p&gt;Oh no, I completely forgot! One of my friends loves to wolf down multiple burritos at a time, so I actually want to place an order for three burritos. If I update &lt;code&gt;Num Burritos&lt;&#x2F;code&gt;, a naïve spreadsheet engine might recompute the entire document, recalculating first the cells with no inputs, and then recalculating any cell whose inputs are ready until we&#x27;ve finished every cell. In this case, we&#x27;d first calculate &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; and &lt;code&gt;Num Burritos&lt;&#x2F;code&gt;, then &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt;, and then a new final &lt;code&gt;Total&lt;&#x2F;code&gt; of $30.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_2_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same as previous graph, but num burritos is updated to 3, and every cell is tagged as &quot;recalc&quot;&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_2.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This simple strategy of recalculating the whole document may sound wasteful, but it&#x27;s actually already &lt;em&gt;better&lt;&#x2F;em&gt; than VisiCalc, the first spreadsheet software ever made, and the first so-called &amp;quot;killer app&amp;quot;, responsible for popularizing the Apple II. VisiCalc would repeatedly recalculate cells from left-to-right and top-to-bottom, sweeping over them again and again until none of them changed. Despite this &amp;quot;interesting&amp;quot; algorithm, VisiCalc remained the dominant spreadsheet software for four years. Its reign ended in 1983, when Lotus 1-2-3 swept the market with &amp;quot;natural-order recalculation&amp;quot;, &lt;a href=&quot;https:&#x2F;&#x2F;aresluna.org&#x2F;attached&#x2F;computerhistory&#x2F;articles&#x2F;spreadsheets&#x2F;tenyearsofrowsandcolumns&quot;&gt;as described by Tracy Robnett Licklider in Byte Magazine&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lotus 1-2-3 exploited natural-order recalculation, although it also supported VisiCalc’s row- and column-order modes. Natural-order recalculation maintained a cell dependency list and recalculated a cell before recalculating cells that depended on it.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Lotus 1-2-3 implemented the &amp;quot;recalculate everything&amp;quot; strategy we&#x27;ve shown above, and for the first decade of spreadsheets, that was as good as it got. Yes, we recalculate every cell in the document, but at least we only recalculate every cell once.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;but-what-about-burrito-price-w-ship&quot;&gt;but what about &amp;quot;burrito price w ship&amp;quot;&lt;&#x2F;h2&gt;
&lt;p&gt;Great point, header 2. In my three burrito example there&#x27;s no reason to recompute &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt;, because changing the number of burritos we order can&#x27;t possibly influence the per-burrito price. In 1989, one of Lotus&#x27; competitors realized this, and created SuperCalc5, presumably naming it after the theory of super burritos at the core of this algorithm. SuperCalc5 recalculated &amp;quot;only cells dependent on changed cells&amp;quot;, which would make updating the burrito count look more like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_3_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same as prior graph, with burrito count updated from 2 to 3, but now only the two affected cells &quot;num burritos&quot; and &quot;total&quot; are tagged as recalc&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_3.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;By only updating a cell when one of its inputs changes, we can avoid recalculating &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt;. In this case, it saves just a single addition, but on larger spreadsheets it can save quite a bit of time! Unfortunately, we now have another problem. Let&#x27;s say my friends now want meat burritos, which cost a dollar more, and simultaneously El Farolito adds a $2 fee paid per-order, regardless of how many burritos you order. Before any formula outputs are recalculated, our graph might look like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_4_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same as prior graph (after burrito count update finished calculation), but now burrito price is being updated from $8 to $9, and simultaneously total is updated from &quot;burrito price w ship * num burritos&quot; to &quot;burrito price w ship * num burritos + $2 fee&quot;&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_4.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Since there are two updated cells here, we have a problem. Should we recalculate &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; first, or &lt;code&gt;Total&lt;&#x2F;code&gt;? Ideally, we first calculate &lt;code&gt;Burrito Price&lt;&#x2F;code&gt;, notice that its output has changed, then recalculate &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt;, and finally recalculate &lt;code&gt;Total&lt;&#x2F;code&gt;. However, if we instead recalculate &lt;code&gt;Total&lt;&#x2F;code&gt; first, we&#x27;ll have to recalculate it a second time once the new $9 burrito price propagates down. If we don&#x27;t calculate cells in the right order, this algorithm isn&#x27;t better than recalculating the whole document. In some cases, it&#x27;s as slow as VisiCalc!&lt;&#x2F;p&gt;
&lt;p&gt;Clearly, it&#x27;s important for us to figure out the right order to update our cells. Broadly, there are two solutions to this problem: dirty marking and topological sorting.&lt;&#x2F;p&gt;
&lt;p&gt;This first solution involves marking all cells downstream from an edit as dirty. For instance, when we update &lt;code&gt;Burrito Price&lt;&#x2F;code&gt;, we would mark the downstream cells &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt; and &lt;code&gt;Total&lt;&#x2F;code&gt; as dirty, even before doing any recalculations:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_5_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same as prior graph with the two updates, but now three nodes are tagged as dirty: &quot;burrito price&quot;, &quot;burrito price w ship&quot;, and &quot;total&quot;. would also like to apologize for the rather confusing image alt text so far; it&#x27;s really hard to write these for graph diagrams!! if you are a screen reader user and have advice on better ways to do this, would love to hear from you.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_5.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Then, in a loop, we find a dirty cell that has no dirty inputs, and recalculate it. When there are no dirty cells left, we&#x27;re done! This solves our ordering problem. There&#x27;s one downside though — if a cell is recalculated and we find its new output to be the same as its previous output, we&#x27;ll still recalculate downstream cells! A little bit of extra logic can avoid actually running the formula trouble in this case, but we unfortunately still waste time marking and unmarking a lot of cells as dirty.&lt;&#x2F;p&gt;
&lt;p&gt;The second solution is topological sorting. If a cell has no inputs, we mark its height as 0. If a cell has inputs, we mark its height as the maximum of the heights of its inputs, plus one. This guarantees all cells have a greater height than any of their inputs, so we just keep track of all cells with a changed input, always choosing the cell with the lowest height to recalculate first:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_6_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same as prior graph with the two updates, but instead of dirty tags, now every node has a height tag. &quot;burrito price&quot; and &quot;num burritos&quot;, the two cells with no in-nodes, have height 0. &quot;burrito price w ship&quot; has height 1. &quot;total&quot; has height 2.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_6.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In our double-update example, &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; and &lt;code&gt;Total&lt;&#x2F;code&gt; would be initially added to the recalculation heap. &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; has lesser height, and would be recalculated first. Since its output changes, we then would add &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt; to the recalculation heap, and since it too has less height than &lt;code&gt;Total&lt;&#x2F;code&gt;, it would be recalculated before we finally recalculate &lt;code&gt;Total&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This has a big advantage over the first solution: no cell is ever marked dirty unless one of its inputs actually change. However, it requires we keep all cells pending recalculation in sorted order. If we use a heap, this results in an &lt;code&gt;O(n log n)&lt;&#x2F;code&gt; slowdown, so in the worst case, asymptotically slower than Lotus 1-2-3&#x27;s strategy of recalculating everything.&lt;&#x2F;p&gt;
&lt;p&gt;Modern-day Excel uses &lt;a href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;office&#x2F;client-developer&#x2F;excel&#x2F;excel-recalculation&quot;&gt;a combination of dirty marking and topological sorting&lt;&#x2F;a&gt;, which you can read more about in their docs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;demand-driven-complications&quot;&gt;demand-driven complications&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ve now more or less reached the algorithms used in modern-day spreadsheet recalculation. Unfortunately, I suspect there is basically no business case to be made for ever improving it further. The few people with the problem &amp;quot;my Excel spreadsheet is too slow&amp;quot; have already written enough Excel formulas that migration to any other platform is impossible. Fortunately, I have no understanding of business, and so we&#x27;re going to look at further improvements anyway.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond caching, one of the cool aspects of a spreadsheet-style computation graph is we can only calculate the cells that we&#x27;re interested in. This is sometimes called lazy computation, or demand-driven computation. As a more concrete example, here&#x27;s a slightly expanded burrito spreadsheet graph. This example is the same as before, but we&#x27;ve added what is best described as &amp;quot;salsa calculations&amp;quot;. Each burrito contains 40 grams of salsa, and we perform a quick multiplication to know how much salsa is in our entire order. In this case, since our order has three burritos, there&#x27;s a total of 120 grams of salsa in our entire order.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_7_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;a new graph. similar structure to the old graph, but there are two new nodes: &quot;salsa per burrito&quot;, which is set to the constant &quot;40 grams&quot;, and &quot;salsa in order&quot;, which is &quot;salsa per burrito&quot; times &quot;num burritos&quot;&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_7.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Of course, astute readers will have spotted the problem here already: knowing the total weight of salsa in an order is a pretty useless measurement. Who cares that it&#x27;s 120 grams? What am I supposed to do with this information?? Unfortunately, a regular spreadsheet would waste cycles calculating &lt;code&gt;Salsa In Order&lt;&#x2F;code&gt;, even if we don&#x27;t want it recalculated most of the time.&lt;&#x2F;p&gt;
&lt;p&gt;This is where demand-driven recalculation can help. If we could somehow specify that we&#x27;re only interested in the output of &lt;code&gt;Total&lt;&#x2F;code&gt;, we could only recompute that cell and its dependencies, and skip touching &lt;code&gt;Salsa In Order&lt;&#x2F;code&gt; and &lt;code&gt;Salsa Per Burrito&lt;&#x2F;code&gt;. Let&#x27;s call &lt;code&gt;Total&lt;&#x2F;code&gt; an &lt;em&gt;observed&lt;&#x2F;em&gt; cell, since we&#x27;re trying to look at its output. We can also call both &lt;code&gt;Total&lt;&#x2F;code&gt; and its three dependencies &lt;em&gt;necessary&lt;&#x2F;em&gt; cells, since they&#x27;re necessary to compute some observed cell. &lt;code&gt;Salsa In Order&lt;&#x2F;code&gt; and &lt;code&gt;Salsa Per Burrito&lt;&#x2F;code&gt; would be aptly described as &lt;em&gt;unnecessary&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Some folks on the Rust team created the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;salsa-rs&#x2F;salsa&quot;&gt;Salsa&lt;&#x2F;a&gt; framework to solve this problem, clearly naming it after the unnecessary salsa calculations their computers were wasting cycles on. Salsa is really cool, and I&#x27;m sure &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=i_IhACacPRY&quot;&gt;they can explain&lt;&#x2F;a&gt; how it works better than I can. Very roughly, they use revision numbers to track whether a cell needs recalculation. Any mutation to a formula or input increments the global revision number, and every cell tracks two revisions: &lt;code&gt;verified_at&lt;&#x2F;code&gt; to track the revision its output was last brought up-to-date, and &lt;code&gt;changed_at&lt;&#x2F;code&gt; to track the revision its output last actually changed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_8_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;our new graph, but now there&amp;#39;s a title of &quot;current revision: R6&quot;. each cell is tagged with a change revision and verified at revision. all change revisions are R1, except &quot;salsa per burrito&quot;, which is R6. all verified at revisions are R6, except &quot;salsa in order&quot;, which is R1.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_8.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When the user indicates they&#x27;d like a fresh value for &lt;code&gt;Total&lt;&#x2F;code&gt;, we&#x27;d first recursively recalculate any cell necessary to &lt;code&gt;Total&lt;&#x2F;code&gt;, skipping cells if their &lt;code&gt;last_updated&lt;&#x2F;code&gt; revision is equal to the global revision. Once the dependencies of &lt;code&gt;Total&lt;&#x2F;code&gt; are up-to-date, we only rerun the actual formula in &lt;code&gt;Total&lt;&#x2F;code&gt; if either &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt; or &lt;code&gt;Num Burrito&lt;&#x2F;code&gt; have a &lt;code&gt;changed_at&lt;&#x2F;code&gt; revision greater than the &lt;code&gt;verified_at&lt;&#x2F;code&gt; revision of &lt;code&gt;Total&lt;&#x2F;code&gt;. This is great for Salsa&#x27;s purposes in the rust-analyzer, where simplicity is important and each cell takes a significant amount of time to compute. However, we can see the disadvantages in our burrito graph above — if &lt;code&gt;Salsa Per Burrito&lt;&#x2F;code&gt; constantly changes, our global revision number will frequently tick up. This will make each observation of &lt;code&gt;Total&lt;&#x2F;code&gt; walk the three cells necessary to it, even though none of those cells have actually changed. No formulas will be recalculated, but if the graph is large, repeatedly walking all of a cell&#x27;s dependencies could get expensive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;faster-demand-driven-solutions&quot;&gt;faster demand-driven solutions&lt;&#x2F;h2&gt;
&lt;p&gt;Instead of inventing new algorithms for demand-driven spreadsheets, what if we instead draw from the two classical spreadsheet algorithms mentioned earlier: dirty marking and topological sorting? As you might imagine, a demand-driven model complicates both of these, but both are still viable.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s first look at dirty marking. As before, when we change a cell&#x27;s formula, we mark all downstream cells as dirty. So if we update &lt;code&gt;Salsa Per Burrito&lt;&#x2F;code&gt;, it would look something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_9_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same salsa graph, but no revision tags. instead, &quot;salsa per burrito&quot; is updating from 40 grams to 45 grams, and &quot;salsa per burrito&quot; and &quot;salsa in order&quot; are both tagged as &quot;dirty&quot;&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_9.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However, instead of immediately recomputing &lt;em&gt;all&lt;&#x2F;em&gt; cells that are dirty, we wait for the user to observe a cell. Then we run Salsa&#x27;s algorithm on the observed cell, but instead of reverifying dependencies with outdated &lt;code&gt;verified_at&lt;&#x2F;code&gt; revision numbers, we instead only reverify cells marked as dirty. This is the technique used by &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Adapton&#x2F;adapton.rust&quot;&gt;Adapton&lt;&#x2F;a&gt;. You&#x27;ll note that when we observe &lt;code&gt;Total&lt;&#x2F;code&gt;, we&#x27;ll find it isn&#x27;t dirty, and so we can skip the graph walk that Salsa would have performed!&lt;&#x2F;p&gt;
&lt;p&gt;If we instead decide to observe &lt;code&gt;Salsa In Order&lt;&#x2F;code&gt;, we&#x27;ll find it &lt;em&gt;is&lt;&#x2F;em&gt; marked as dirty, and so we&#x27;ll reverify and recompute both &lt;code&gt;Salsa Per Burrito&lt;&#x2F;code&gt; and &lt;code&gt;Salsa In Order&lt;&#x2F;code&gt;. Even here, there are benefits over using just revision numbers, since we&#x27;ll be able to skip a recursive walk on the still-clean &lt;code&gt;Num Burritos&lt;&#x2F;code&gt; cell.&lt;&#x2F;p&gt;
&lt;p&gt;Demand-driven dirty marking performs fantastically when the set of cells we&#x27;re trying to observe changes frequently. Unfortunately, this has the same downsides as the dirty marking algorithm from before. If a cell with many downstream cells changes, we may waste a lot of time marking and unmarking cells as dirty, even if their inputs won&#x27;t actually have changed when we go to recalculate them. In the worst case, each changes causes us to mark the entire graph as dirty, which would give us the same ~order of magnitude performance as Salsa&#x27;s algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;Moving on from dirty marking, we can also adapt topological sorting for demand-driven computations. This is the technique used by Jane Street&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;janestreet&#x2F;incremental&quot;&gt;Incremental&lt;&#x2F;a&gt; library, and requires &lt;a href=&quot;https:&#x2F;&#x2F;www.janestreet.com&#x2F;tech-talks&#x2F;seven-implementations-of-incremental&#x2F;&quot;&gt;major tricks&lt;&#x2F;a&gt; to get right. Before we added demand-driven computations, our topological sorting algorithm used a heap to determine which cell would be recomputed next. But now, we only want to recompute cells that are &lt;em&gt;necessary&lt;&#x2F;em&gt;. How? We don&#x27;t want to walk the entire tree from our observed cells like Adapton, since a complete tree walk defeats the entire purpose of topological sorting, and would give us performance characteristics similar to Adapton.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, Incremental maintains a set of cells that the user has marked &lt;em&gt;observed&lt;&#x2F;em&gt;, as well as the set of cells that are &lt;em&gt;necessary&lt;&#x2F;em&gt; to any observed cell. Whenever a cell is marked observed or unobserved, Incremental walks that cell&#x27;s dependencies to make sure the necessary marks are applied correctly. Then, we only add cells to the recalculation heap if they&#x27;re marked necessary. In our burrito graph, if only &lt;code&gt;Total&lt;&#x2F;code&gt; is part of the observed set, changing &lt;code&gt;Salsa in Order&lt;&#x2F;code&gt; would not result in any walking of the graph, since only necessary cells are recomputed:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_10_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same graph as before; &quot;salsa per burrito&quot; is being updated from 40 to 45 grams, and is tagged as &quot;dirty&quot;. &quot;total&quot; and its dependencies &quot;burrito price&quot;, &quot;num burritos&quot;, and &quot;burrito price w ship&quot; are tagged as &quot;necessary&quot;. &quot;total&quot; is also tagged as &quot;observed&quot;.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_10.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This solves our problem without eagerly walking the graph to mark cells as dirty! We still have to remember that &lt;code&gt;Salsa per Burrito&lt;&#x2F;code&gt; is dirty, since if it later becomes necessary, we will need to recompute it. But unlike Adapton&#x27;s algorithm, we don&#x27;t need to push this single dirty mark down the entire graph.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;anchors-a-hybrid-solution&quot;&gt;anchors, a hybrid solution&lt;&#x2F;h2&gt;
&lt;p&gt;Both Adapton and Incremental walk the graph, even when not recomputing cells. Incremental walks the graph upstream when the set of observed cells changes, and Adapton walks the graph downstream when a formula changes. With these small graphs, it may not be immediately apparent that this graph walking is expensive. However, if your graph is large and your cells are relatively cheap to compute — often the case with spreadsheets — you&#x27;ll find that most of your costs come from wasted graph walking! When cells are cheap, marking a bit on a cell can cost roughly the same as just recomputing the cell from scratch. So ideally, if we want our algorithm to be substantially faster than computing from scratch, we&#x27;ve got to avoid unnecessarily walking the graph as best we can.&lt;&#x2F;p&gt;
&lt;p&gt;The more I thought about the problem, the more I realized that they waste time walking the graph in roughly opposite situations. In our burrito graph, let&#x27;s imagine cell formulas rarely change, but we rapidly switch between first observing &lt;code&gt;Total&lt;&#x2F;code&gt;, and then observing &lt;code&gt;Salsa in Order&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_11_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same graph as before, but arrows pointing to &quot;total&quot; and &quot;salsa in order&quot; indicate we&#x27;re rapidly switching which of the two we are observing&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_11.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this case, Adapton will never walk the tree. No inputs are changing, and so we never need to mark anything as dirty. Since nothing is dirty, each observation is cheap as well, since we can simply return the cached value from a clean cell immediately. However, Incremental performs poorly in this example. Even though no values are ever recomputed, Incremental will repeatedly mark and unmark many cells as necessary and unnecessary.&lt;&#x2F;p&gt;
&lt;p&gt;In the opposite case, let&#x27;s imagine a graph where our formulas are rapidly changing, but we don&#x27;t change which cells we&#x27;re observing. For instance, we could imagine we&#x27;re observing &lt;code&gt;Total&lt;&#x2F;code&gt; while rapidly changing &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; from &lt;code&gt;4+4&lt;&#x2F;code&gt; to &lt;code&gt;2*4&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_12_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same graph as before, arrow pointing to &quot;burrito price&quot; indicates its value is rapidly switching.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_12.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Just like the previous example, we aren&#x27;t really recomputing many cells. &lt;code&gt;4+4&lt;&#x2F;code&gt; and &lt;code&gt;2*4&lt;&#x2F;code&gt; both equal &lt;code&gt;8&lt;&#x2F;code&gt;, so ideally we only recompute that one bit of arithmetic when the user makes this change. However, unlike the previous example, Incremental is now the library that avoids tree walking. With Incremental, we&#x27;ve cached the fact that &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; is a necessary cell, and so when it changes, we can recalculate it without walking the graph. With Adapton, we waste time marking &lt;code&gt;Burrito Price w Ship&lt;&#x2F;code&gt; and &lt;code&gt;Total&lt;&#x2F;code&gt; as dirty, even though the output of &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; won&#x27;t have changed.&lt;&#x2F;p&gt;
&lt;p&gt;Given each algorithm performs well in the other&#x27;s degenerate cases, wouldn&#x27;t it be ideal if we could just detect those degenerate cases, and switch to the faster algorithm? This is what I have attempted to do with my own library, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;anchors&quot;&gt;Anchors&lt;&#x2F;a&gt;. Anchors runs both algorithms simultaneously on the same graph! If this sounds wild and unnecessary and overly complicated, that&#x27;s probably because it is.&lt;&#x2F;p&gt;
&lt;p&gt;In many cases, Anchors follows Incremental&#x27;s algorithm exactly, which avoids Adapton&#x27;s degenerate case above. But when cells are marked as unobserved, its behavior diverges slightly. Let&#x27;s look at what happens. We start with marking &lt;code&gt;Total&lt;&#x2F;code&gt; as observed:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_13_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same as &quot;rapidly switching which is observed&quot; graph but now total and its dependencies are marked as &quot;necessary&quot;. total is marked as &quot;observed&quot;.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_13.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we then mark &lt;code&gt;Total&lt;&#x2F;code&gt; as unobserved and &lt;code&gt;Salsa in Order&lt;&#x2F;code&gt; as observed, the traditional Incremental algorithm would alter the graph to look like this, walking through every cell in the process:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_14_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same graph as above, but now &quot;salsa in order&quot; and its dependencies are marked as &quot;necessary&quot;. &quot;salsa in order&quot; is also marked as observed.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_14.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Anchors also walks every cell for this change, but instead produces a graph that looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_15_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same graph as above with &quot;salsa in order&quot; observed, but now additionally &quot;total&quot;, &quot;burrito price w ship&quot;, and &quot;burrito price&quot; are all marked as &quot;clean&quot;.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_15.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note the &amp;quot;clean&amp;quot; flags! When a cell is no longer necessary, we mark it as &amp;quot;clean&amp;quot;. Let&#x27;s look at what happens when we switch from observing &lt;code&gt;Salsa in Order&lt;&#x2F;code&gt; to &lt;code&gt;Total&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_16_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;All nodes in the graph are now tagged as &quot;clean&quot;. also, &quot;total&quot; is marked as &quot;observed&quot;&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_16.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s right — our graph now has &lt;em&gt;no&lt;&#x2F;em&gt; necessary cells. If a cell has a &amp;quot;clean&amp;quot; flag, we never mark it as observed. At this point, no matter what cell we mark as observed or unobserved, Anchors will never waste time walking the graph — it knows that none of the inputs have changed.&lt;&#x2F;p&gt;
&lt;p&gt;Looks like there&#x27;s a discount at El Farolito! Let&#x27;s drop &lt;code&gt;Burrito Price&lt;&#x2F;code&gt; by a dollar. How does Anchors know &lt;code&gt;Total&lt;&#x2F;code&gt; needs to be recomputed? Before we recompute any formulas, let&#x27;s look at how Anchors will see the graph right after we change just &lt;code&gt;Burrito Price&lt;&#x2F;code&gt;, before recomputing anything:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_17_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same graph as above, but now &quot;total&quot;, &quot;burrito price w ship&quot;, and &quot;burrito price&quot; are tagged as &quot;dirty&quot; instead of &quot;clean&quot;.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_17.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If a cell has a clean flag, we run the traditional Adapton algorithm on it, eagerly marking downstream cells as dirty. When we later run the Incremental algorithm, we can quickly tell that there is an observed cell marked as dirty, and know we need to recompute its dependencies. After that&#x27;s finished, the final graph will look like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_18_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;same graph as above, but now &quot;total&quot;, &quot;burrito price w ship&quot;, and &quot;burrito price&quot; are tagged as &quot;necessary&quot; instead of &quot;dirty&quot;.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_18.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We only recompute cells if they&#x27;re necessary, so whenever we recompute a dirty cell, we also mark it as necessary. At a high level, you can imagine these three cell states form a looping state machine:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_19_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&#x27;three states &quot;necessary&quot;, &quot;clean&quot; and &quot;dirty&quot;, with an arrow from &quot;necessary&quot; to &quot;clean&quot;, &quot;clean&quot; to &quot;dirty&quot;, and &quot;dirty&quot; to &quot;necessary&quot;.&#x27; src=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_19.png&#x27;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;p&gt;
&lt;p&gt;On necessary cells, we run the Incremental&#x27;s topological sorting algorithm. On unnecessary cells, we run the Adapton algorithm.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;burrito-syntax&quot;&gt;burrito syntax&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;d like to finish up by answering a final question: so far, we&#x27;re been discussing the many problems the demand-driven model causes for our recomputation strategy. But the problems aren&#x27;t just for the algorithm: there are syntactic problems to solve too. For instance, let&#x27;s make a spreadsheet to select a burrito emoji for our customer. We&#x27;d write an &lt;code&gt;IF&lt;&#x2F;code&gt; statement in the spreadsheet like this:&lt;&#x2F;p&gt;
&lt;div style=&quot;max-width: 439px;&quot;&gt;&lt;picture&gt;&lt;source srcset=&#x27;&#x2F;images&#x2F;2020&#x2F;anchors_20_dark.png&#x27; media=&quot;(prefers-color-scheme: dark)&quot;&gt;&lt;img alt=&quot;a new spreadsheet. vegetarian customer is set to YES, vegi burrito is an emoji of a broccoli, meat burrito is an emoji of a meat, and burrito for customer is &amp;quot;=IF(B1=YES, B2, B3)&amp;quot;&quot; src=&quot;&#x2F;images&#x2F;2020&#x2F;anchors_20.png&quot;&gt;&lt;&#x2F;picture&gt;&lt;&#x2F;div&gt;
&lt;p&gt;Because traditional spreadsheets aren&#x27;t demand-driven, we can compute &lt;code&gt;B1&lt;&#x2F;code&gt;, &lt;code&gt;B2&lt;&#x2F;code&gt;, and &lt;code&gt;B3&lt;&#x2F;code&gt; in any order, so long as we compute our &lt;code&gt;IF&lt;&#x2F;code&gt; cell after all three inputs are ready. In a demand-driven world however, if we can calculate the value of &lt;code&gt;B1&lt;&#x2F;code&gt; first, we can peek at the value to know which of &lt;code&gt;B2&lt;&#x2F;code&gt; or &lt;code&gt;B3&lt;&#x2F;code&gt; we need to recalculate. Unfortunately, a traditional spreadsheet&#x27;s &lt;code&gt;IF&lt;&#x2F;code&gt; has no way to express this!&lt;&#x2F;p&gt;
&lt;p&gt;The problem: &lt;code&gt;B2&lt;&#x2F;code&gt; simultaneously references cell &lt;code&gt;B2&lt;&#x2F;code&gt; and retrieves its value, 🥦. Most demand-driven libraries mentioned in this post instead explicitly distinguish between a reference to a cell and the act of retrieving its actual value. In Anchors, we call this cell reference an &lt;code&gt;Anchor&lt;&#x2F;code&gt;. Much like a burrito in real life wraps a bunch of ingredients together, the &lt;code&gt;Anchor&amp;lt;T&amp;gt;&lt;&#x2F;code&gt; type wraps &lt;code&gt;T&lt;&#x2F;code&gt; — which I suppose makes our vegi burrito cell &lt;code&gt;Anchor&amp;lt;Burrito&amp;gt;&lt;&#x2F;code&gt;, a sort of ridiculous burrito of burritos. Functions can pass around our &lt;code&gt;Anchor&amp;lt;Burrito&amp;gt;&lt;&#x2F;code&gt; as much as they&#x27;d like — it&#x27;s only when they actually unwrap the burrito to access the &lt;code&gt;Burrito&lt;&#x2F;code&gt; inside that we create a dependency edge in our graph, indicating to the recomputation algorithm that the cell may be necessary and need recomputing.&lt;&#x2F;p&gt;
&lt;p&gt;The approach taken by Salsa and Adapton is to use function calls and normal control flow as a way to unwrap these values. For instance, in Adapton, we might write our &amp;quot;Burrito for Customer&amp;quot; cell something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; burrito_for_customer &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;cell!&lt;&#x2F;span&gt;&lt;span&gt;({
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;get!&lt;&#x2F;span&gt;&lt;span&gt;(is_vegetarian) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;get!&lt;&#x2F;span&gt;&lt;span&gt;(vegi_burrito)
&lt;&#x2F;span&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&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:#f28779;&quot;&gt;get!&lt;&#x2F;span&gt;&lt;span&gt;(meat_burrito)
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By distinguishing between a cell reference (&lt;code&gt;vegi_burrito&lt;&#x2F;code&gt; here) and the act of unwrapping its value (&lt;code&gt;get!&lt;&#x2F;code&gt;), Adapton can piggy-back on top of Rust&#x27;s control flow operators like &lt;code&gt;if&lt;&#x2F;code&gt;. This is a great solution! However, a little bit of magical global state is needed to correctly connect the &lt;code&gt;get!&lt;&#x2F;code&gt; calls to the &lt;code&gt;cell!&lt;&#x2F;code&gt; that needs recomputing when &lt;code&gt;is_vegetarian&lt;&#x2F;code&gt; changes. The approach I&#x27;ve taken with Anchors, inspired by Incremental, is a slightly less magical system. Similar to a pre-async&#x2F;await &lt;code&gt;Future&lt;&#x2F;code&gt;, Anchors allows you to use operations like &lt;code&gt;map&lt;&#x2F;code&gt; and &lt;code&gt;then&lt;&#x2F;code&gt; on an &lt;code&gt;Anchor&amp;lt;T&amp;gt;&lt;&#x2F;code&gt;. For instance, the example above would look something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; burrito_for_customer&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;Anchor&amp;lt;Burrito&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; is_vegetarian&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;then&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;is_vegetarian&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;Anchor&amp;lt;Burrito&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; is_vegetarian {
&lt;&#x2F;span&gt;&lt;span&gt;      vegi_burrito
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;      meat_burrito
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;further reading&lt;&#x2F;h2&gt;
&lt;p&gt;In this already long and winding blog post, there is so much I didn&#x27;t have space to talk about. Hopefully these resources can shed a little bit more light on this very interesting problem.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;blog.janestreet.com&#x2F;seven-implementations-of-incremental&#x2F;&quot;&gt;Seven Implementations of Incremental&lt;&#x2F;a&gt;, a great in-depth look at Incremental internals, as well as a bunch of optimizations like always-increasing heights I didn&#x27;t have time to talk about, as well as clever ways to handle cells that change dependencies. Also worth reading from Ron Minsky: &lt;a href=&quot;https:&#x2F;&#x2F;blog.janestreet.com&#x2F;breaking-down-frp&#x2F;&quot;&gt;Breaking down FRP&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Salsa&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;salsa-rs.github.io&#x2F;salsa&#x2F;videos.html&quot;&gt;explanation videos&lt;&#x2F;a&gt; explains how it works quite well.&lt;&#x2F;li&gt;
&lt;li&gt;This &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;salsa-rs&#x2F;salsa&#x2F;issues&#x2F;41&quot;&gt;Salsa issue&lt;&#x2F;a&gt;, where you can watch Matthew Hammer, creator of Adapton, patiently explain cutoffs to some rando (me) who repeatedly fails to understand how they work.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=DSuX-LIAU-I&quot;&gt;Raph Levien&#x27;s Rustlab keynote&lt;&#x2F;a&gt; has some really interesting stuff about this topic in the context of GUIs. In response to this post, he says &lt;a href=&quot;https:&#x2F;&#x2F;www.pzuraq.com&#x2F;how-autotracking-works&#x2F;&quot;&gt;How Autotracking Works&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;v5.chriskrycho.com&#x2F;journal&#x2F;autotracking-elegant-dx-via-cutting-edge-cs&#x2F;&quot;&gt;Autotracking: Elegant DX Via Cutting-Edge CS&lt;&#x2F;a&gt; are great resources.&lt;&#x2F;li&gt;
&lt;li&gt;I have to admit I don&#x27;t actually understand &lt;a href=&quot;http:&#x2F;&#x2F;michaelisard.com&#x2F;pubs&#x2F;differentialdataflow.pdf&quot;&gt;Differential Dataflow&lt;&#x2F;a&gt;, but it&#x27;s the backbone of the &lt;a href=&quot;https:&#x2F;&#x2F;materialize.io&#x2F;&quot;&gt;Materialize&lt;&#x2F;a&gt; database. Query planning in general seems like maybe a solution to the big cache missing problems that many of these frameworks suffer from? It doesn&#x27;t have built-in demand-driven computation, but Jamie Brandon (thanks!) kindly pointed me to their blog post &lt;a href=&quot;https:&#x2F;&#x2F;materialize.com&#x2F;lateral-joins-and-demand-driven-queries&#x2F;&quot;&gt;Lateral Joins and Demand-Driven Queries&lt;&#x2F;a&gt; which explains how you can add demand as an input. Also of relevance is the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mit-pdos&#x2F;noria&quot;&gt;Noira project&lt;&#x2F;a&gt; from MIT.&lt;&#x2F;li&gt;
&lt;li&gt;Adapton&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;adapton&#x2F;0.3.31&#x2F;adapton&#x2F;&quot;&gt;documentation&lt;&#x2F;a&gt; is very comprehensive.&lt;&#x2F;li&gt;
&lt;li&gt;Turns out this way of thinking also applies to &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;BQVT6wiwCxM&quot;&gt;build systems&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.peterstefek.me&#x2F;incr-ray-tracer.html&quot;&gt;Slightly Incremental Ray Tracing&lt;&#x2F;a&gt; is a slightly incremental ray tracer written in Ocaml.&lt;&#x2F;li&gt;
&lt;li&gt;Just saw &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=GctxvSPIfr8&quot;&gt;Partial State in Dataflow-Based Materialized Views&lt;&#x2F;a&gt; today and it seems relevant.&lt;&#x2F;li&gt;
&lt;li&gt;Gustav Westling (thanks!) pointed out &lt;a href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;uploads&#x2F;prod&#x2F;2018&#x2F;03&#x2F;build-systems.pdf&quot;&gt;Build Systems à la Carte&lt;&#x2F;a&gt; is one of the first papers about the similarities between build systems and spreadsheets.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;skiplang.com&#x2F;blog&#x2F;2017&#x2F;01&#x2F;04&#x2F;how-memoization-works.html&quot;&gt;Skip&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;scattered-thoughts.net&#x2F;writing&#x2F;imp-decorrelation&#x2F;&quot;&gt;Imp&lt;&#x2F;a&gt; also look really interesting.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And of course, you can always check out the framework I built, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;anchors&quot;&gt;Anchors&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Thanks to Syd Botz, Adam Perry, and Peter Stefek for feedback and discussion!&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Invariant Lifetimes as Static, Unique Tokens</title>
    <published>2020-10-12T00:00:00+00:00</published>
    <updated>2020-10-12T00:00:00+00:00</updated>
    <link href="https://lord.io/lifetimes-as-tokens/" type="text/html"/>
    <id>https://lord.io/blog/2020/lifetimes-as-tokens/</id>
    <content type="html">&lt;p&gt;Some of you may know I quit my job to work on a little text editor for fun. Unfortunately, in the process of doing that, I got distracted by the challenging problem of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;anchors&quot;&gt;self-adjusting computation&lt;&#x2F;a&gt;. And unfortunately, to solve that problem in a performant way, you need really fast graphs, a notorious problem in Rust. And to get really fast graphs, I&#x27;ve found this cursed technique that takes advantage of Rust&#x27;s lifetime rules and higher ranked trait bounds, which is what I&#x27;d like to talk about today. Beyond its dubious interpretation of variance, I&#x27;m proud to say this blog post represents an unprecidented achievement in yak-shaving for me, clocking in at four, maybe five levels deep. It&#x27;s remarkable I&#x27;m even still using Rust — the traditional move at this deep level is to &amp;quot;realize&amp;quot; writing your own programming language is just the only reasonable way to build a text editor so you can finally write the code you wanted to write originally.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s first briefly talk about my experimental graph library, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;arena-graph&quot;&gt;arena-graph&lt;&#x2F;a&gt;. To have fast edges in a graph, we want our nodes to have pointers that directly point to other nodes. My understanding is it&#x27;s perfectly safe to cast a &lt;code&gt;*const Node&lt;&#x2F;code&gt; to a &lt;code&gt;&amp;amp;Node&lt;&#x2F;code&gt;, so long as the resource targeted by that raw pointer still exists, has not been moved, and will not be moved so long as &lt;code&gt;&amp;amp;Node&lt;&#x2F;code&gt; exists. Arena allocation gives us these properties! We only store our &lt;code&gt;*const Node&lt;&#x2F;code&gt; in places that will be dropped at the same time as the arena — either inside a node, or alongside the arena in the same struct. We also make sure any &lt;code&gt;&amp;amp;Node&lt;&#x2F;code&gt; we hand out won&#x27;t outlive the arena. This guarantees the raw pointers won&#x27;t outlive the arena they point into.&lt;&#x2F;p&gt;
&lt;p&gt;However, there&#x27;s still one problem. Let&#x27;s say we have a &lt;code&gt;set_parent&lt;&#x2F;code&gt; method like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;TreeNode &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;set_parent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;new_parent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;TreeNode) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;parent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt;(new_parent &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;*const&lt;&#x2F;span&gt;&lt;span&gt; TreeNode)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&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;In this example, there&#x27;s no guarantee that &lt;code&gt;new_parent&lt;&#x2F;code&gt; is a TreeNode in the same graph as &lt;code&gt;self&lt;&#x2F;code&gt;. If these two nodes are part of different arenas, &lt;code&gt;new_parent&lt;&#x2F;code&gt; could be deallocated at a different time from &lt;code&gt;self&lt;&#x2F;code&gt;, &lt;code&gt;self&lt;&#x2F;code&gt; later goes to dereference its parent, and we&#x27;ve hit undefined behavior.&lt;&#x2F;p&gt;
&lt;p&gt;To avoid this, we need to ensure &lt;code&gt;new_parent&lt;&#x2F;code&gt; and &lt;code&gt;self&lt;&#x2F;code&gt; are part of the same tree, so the tree&#x27;s arena drops both nodes at the same time. One way to do this is to have &lt;code&gt;TreeNode&lt;&#x2F;code&gt; have some sort of unique arena ID, and we could compare these IDs any time we add an edge from one graph node to another. This check is frustrating, though. If we&#x27;re already going to all this trouble of avoiding slotmap-style checks, ideally we wouldn&#x27;t have any checks at all, even when adding new edges. Another solution is we could just have the user promise they won&#x27;t do this, but marking &lt;code&gt;set_parent&lt;&#x2F;code&gt; as &lt;code&gt;unsafe&lt;&#x2F;code&gt; will clutter up our users&#x27; code with countless unsafe blocks.&lt;&#x2F;p&gt;
&lt;p&gt;What if instead, we could have the Rust compiler statically check that &lt;code&gt;self&lt;&#x2F;code&gt; and &lt;code&gt;new_parent&lt;&#x2F;code&gt; come from the same graph? The bet of this library is that you maybe can hack this in with Rust&#x27;s lifetime system, if you can guarantee that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;When adding an edge from &lt;code&gt;&amp;amp;&#x27;a TreeNode&lt;&#x2F;code&gt; to &lt;code&gt;&amp;amp;&#x27;b TreeNode&lt;&#x2F;code&gt;, we ensure that &lt;code&gt;&#x27;a&lt;&#x2F;code&gt; and &lt;code&gt;&#x27;b&lt;&#x2F;code&gt; have exactly the same lifetime.&lt;&#x2F;li&gt;
&lt;li&gt;If &lt;code&gt;&amp;amp;&#x27;a TreeNode&lt;&#x2F;code&gt; and &lt;code&gt;&amp;amp;&#x27;b TreeNode&lt;&#x2F;code&gt; came from different graphs, &lt;code&gt;&#x27;a&lt;&#x2F;code&gt; and &lt;code&gt;&#x27;b&lt;&#x2F;code&gt; will be different lifetimes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To get these properties, we have to talk briefly about variance.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-brief-aside-about-variance&quot;&gt;A brief aside about variance&lt;&#x2F;h2&gt;
&lt;p&gt;The following code &lt;a href=&quot;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;?version=stable&amp;amp;mode=debug&amp;amp;edition=2018&amp;amp;gist=22fa15a461255ce17b8acd61e0fef04f&quot;&gt;compiles&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ccc9c2cc;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Debug)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;NoClone&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; num_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; NoClone(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; num_1_ref &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;num_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; num_2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; NoClone(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; num_2_ref &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;num_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;print_numbers&lt;&#x2F;span&gt;&lt;span&gt;(num_1_ref&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; num_2_ref)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;mem&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;drop(num_2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;{:?}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; num_1_ref)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;print_numbers&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;num_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt; NoClone, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;num_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt; NoClone) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;{:?} {:?}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; num_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; num_2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At first, this may seem weird. &lt;code&gt;print_numbers&lt;&#x2F;code&gt; is asking for two numbers with the same lifetime, but the two numbers have different lifetimes — &lt;code&gt;num_2&lt;&#x2F;code&gt; is dropped in &lt;code&gt;main&lt;&#x2F;code&gt; before we print &lt;code&gt;num_1_ref&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The answer is &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;nomicon&#x2F;subtyping.html&quot;&gt;variance&lt;&#x2F;a&gt;. &lt;code&gt;&amp;amp;&#x27;a NoClone&lt;&#x2F;code&gt; is covariant for &lt;code&gt;&#x27;a&lt;&#x2F;code&gt;, which has a complex type theory meaning but for our purposes means you can replace &lt;code&gt;&#x27;a&lt;&#x2F;code&gt; with any lifetime longer than &lt;code&gt;&#x27;a&lt;&#x2F;code&gt;. The two arguments passed into &lt;code&gt;print_numbers&lt;&#x2F;code&gt; can have two different lifetimes, so long as both lifetimes last at least as long as the call to &lt;code&gt;print_numbers&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;However, the following &lt;a href=&quot;https:&#x2F;&#x2F;play.rust-lang.org&#x2F;?version=stable&amp;amp;mode=debug&amp;amp;edition=2018&amp;amp;gist=8fc847fbfef646c11493fd7a81b592dd&quot;&gt;doesn&#x27;t compile&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ccc9c2cc;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Debug)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;NoClone&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; num_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; NoClone(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; num_1_ref &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;num_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; num_2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; NoClone(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; num_2_ref &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;num_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;print_numbers&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; num_1_ref&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; num_2_ref)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;mem&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;drop(num_2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; delete this line to make it compile
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;{:?}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; num_1_ref)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;print_numbers&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;num_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt; NoClone, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;num_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt; NoClone) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;{:?} {:?}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; num_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; num_2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All we&#x27;ve changed here is switched &lt;code&gt;print_numbers&lt;&#x2F;code&gt; to accept &lt;code&gt;&amp;amp;mut &amp;amp;&#x27;a NoClone&lt;&#x2F;code&gt; arguments instead of &lt;code&gt;&amp;amp;&#x27;a NoClone&lt;&#x2F;code&gt;. Why is this invalid? Well, we could add a quick line to &lt;code&gt;print_numbers&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;num_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= *&lt;&#x2F;span&gt;&lt;span&gt;num_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In our &lt;code&gt;main&lt;&#x2F;code&gt; function, this would update &lt;code&gt;num_1_ref&lt;&#x2F;code&gt; to point to &lt;code&gt;num_2&lt;&#x2F;code&gt;. Since &lt;code&gt;num_2&lt;&#x2F;code&gt; is dropped before &lt;code&gt;num_1_ref&lt;&#x2F;code&gt; is printed, this swap would cause undefined behavior, so the compiler is right to complain about this.&lt;&#x2F;p&gt;
&lt;p&gt;How does lifetime variance prevent this second case, but allow the first one? &lt;code&gt;&amp;amp;&#x27;b mut T&lt;&#x2F;code&gt; is (just like &lt;code&gt;&amp;amp;&#x27;b T&lt;&#x2F;code&gt;) covariant for &lt;code&gt;&#x27;b&lt;&#x2F;code&gt;. However, it&#x27;s &lt;em&gt;invariant&lt;&#x2F;em&gt; for &lt;code&gt;T&lt;&#x2F;code&gt;, which means only and exactly a &lt;code&gt;T&lt;&#x2F;code&gt; can be passed in. Since &lt;code&gt;T&lt;&#x2F;code&gt; in this example is &lt;code&gt;&amp;amp;&#x27;a NoClone&lt;&#x2F;code&gt;, our new &lt;code&gt;print_numbers&lt;&#x2F;code&gt; requires the two &lt;code&gt;&amp;amp;&#x27;a NoClone&lt;&#x2F;code&gt; to have exactly the same lifetime &lt;code&gt;&#x27;a&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;applying-this-to-our-graph&quot;&gt;Applying this to our graph&lt;&#x2F;h2&gt;
&lt;p&gt;We mentioned earlier we want our add edge method to have two properties:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;When adding an edge from &lt;code&gt;&amp;amp;&#x27;a TreeNode&lt;&#x2F;code&gt; and &lt;code&gt;&amp;amp;&#x27;b TreeNode&lt;&#x2F;code&gt;, we ensure that &lt;code&gt;&#x27;a&lt;&#x2F;code&gt; and &lt;code&gt;&#x27;b&lt;&#x2F;code&gt; have exactly the same lifetime.&lt;&#x2F;li&gt;
&lt;li&gt;If &lt;code&gt;&amp;amp;&#x27;a TreeNode&lt;&#x2F;code&gt; and &lt;code&gt;&amp;amp;&#x27;b TreeNode&lt;&#x2F;code&gt; came from different graphs, &lt;code&gt;&#x27;a&lt;&#x2F;code&gt; and &lt;code&gt;&#x27;b&lt;&#x2F;code&gt; will be different lifetimes.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To get the first property, we just need to make sure &lt;code&gt;&amp;amp;&#x27;a TreeNode&lt;&#x2F;code&gt; is invariant for &lt;code&gt;&#x27;a&lt;&#x2F;code&gt;. To get this, we can use a &lt;code&gt;PhantomData&lt;&#x2F;code&gt; and a wrapper struct:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;marker&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;PhantomData&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Copy)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;TreeNodeRef&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    inner&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt; TreeNode,
&lt;&#x2F;span&gt;&lt;span&gt;    mark_invariant&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;PhantomData&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a &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 style=&quot;color:#ffa759;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;TreeNodeRef&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;set_parent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;new_parent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;TreeNodeRef&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;parent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt;(new_parent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;inner &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;*const&lt;&#x2F;span&gt;&lt;span&gt; TreeNode)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;get_parent&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;TreeNodeRef&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        TreeNodeRef {
&lt;&#x2F;span&gt;&lt;span&gt;            inner&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;*&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;parent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;() }&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            mark_invariant&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; PhantomData&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We still need that second property, though, where two trees always produce &lt;code&gt;TreeNodeRef&lt;&#x2F;code&gt;s with different lifetimes. There&#x27;s a lot here that won&#x27;t work. For instance, this stripped down example initially appears to error correctly:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;marker&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;PhantomData&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;#&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span&gt;(Clone&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Copy&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; Debug)]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;TreeNodeRef&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; inner node data ommited for brevity
&lt;&#x2F;span&gt;&lt;span&gt;    mark_invariant&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;PhantomData&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a &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 style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;same_lifetime&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;TreeNodeRef&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;TreeNodeRef&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; two nodes have same lifetime; set recursive pointers here
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;Tree &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;-&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;TreeNodeRef&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        TreeNodeRef {
&lt;&#x2F;span&gt;&lt;span&gt;            mark_invariant&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; PhantomData&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tree_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; root_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; tree_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tree_2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; root_2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; tree_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;same_lifetime&lt;&#x2F;span&gt;&lt;span&gt;(root_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; root_2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;{:?}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; root_1)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This fails because &lt;code&gt;root_1&lt;&#x2F;code&gt; and &lt;code&gt;root_2&lt;&#x2F;code&gt; have different lifetimes. But move the creation of &lt;code&gt;root_1&lt;&#x2F;code&gt; into the block, and we can get this to incorrectly compile:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tree_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tree_2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; root_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; tree_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; root_2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; tree_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;same_lifetime&lt;&#x2F;span&gt;&lt;span&gt;(root_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; root_2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;{:?}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; tree_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;root&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now root_1 and root_2 are created at the same time, and so share the same lifetime. How do we make this impossible? Initially it may seem we could use a closure to force the &lt;code&gt;root()&lt;&#x2F;code&gt; calls to be in different scopes:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;Tree &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;with_root&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;, F&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;FnOnce&lt;&#x2F;span&gt;&lt;span&gt;(TreeNodeRef&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;)&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; F) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;(TreeNodeRef {
&lt;&#x2F;span&gt;&lt;span&gt;            mark_invariant&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; PhantomData&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tree_1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tree_2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; Tree&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    tree_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;with_root&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;root_1&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;        tree_2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;with_root&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;root_2&lt;&#x2F;span&gt;&lt;span&gt;| {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;same_lifetime&lt;&#x2F;span&gt;&lt;span&gt;(root_1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; root_2)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, you&#x27;ll find that this actually compiles! How is this possible? My understanding gets a little fuzzier here, but I&#x27;m pretty sure since &lt;code&gt;with_root&lt;&#x2F;code&gt;&#x27;s &lt;code&gt;&amp;amp;&#x27;a self&lt;&#x2F;code&gt; is covariant for &lt;code&gt;&#x27;a&lt;&#x2F;code&gt;, it allows the constructed &lt;code&gt;TreeNodeRef&amp;lt;&#x27;a&amp;gt;&lt;&#x2F;code&gt; to also have an arbitrarily long lifetime. How can we make this correctly error? Ideally we need some way to express that the &lt;code&gt;FnOnce&lt;&#x2F;code&gt; passed to &lt;code&gt;with_root&lt;&#x2F;code&gt; should &lt;em&gt;not&lt;&#x2F;em&gt; have a lifetime selected by the caller, but instead some unique lifetime determined by &lt;code&gt;with_root&lt;&#x2F;code&gt;. Fortunately for us, Rust has a bit of magic called &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;nomicon&#x2F;hrtb.html&quot;&gt;higher ranked trait bounds&lt;&#x2F;a&gt; that does exactly that:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;Tree &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;with_root&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;F&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; for &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;any&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;FnOnce&lt;&#x2F;span&gt;&lt;span&gt;(TreeNodeRef&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;any&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;)&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; F) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;(TreeNodeRef {
&lt;&#x2F;span&gt;&lt;span&gt;            mark_invariant&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; PhantomData&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With the code above, our &lt;code&gt;main&lt;&#x2F;code&gt; will correctly fail to compile, since &lt;code&gt;root_1&lt;&#x2F;code&gt; and &lt;code&gt;root_2&lt;&#x2F;code&gt; will be guaranteed to have different lifetimes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-not-cell-a-node-a&quot;&gt;Why not &lt;code&gt;Cell&amp;lt;&amp;amp;&#x27;a Node&amp;lt;&#x27;a&amp;gt;&amp;gt;&lt;&#x2F;code&gt;?&lt;&#x2F;h2&gt;
&lt;p&gt;Some ppl construct graphs using a node that looks something like this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;Node&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    parent&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;Cell&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a Self&lt;&#x2F;span&gt;&lt;span&gt;&amp;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;While this has the advantage of not needing unsafe, it unfortunately means your graph struct has a lifetime in it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;Graph&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    arena&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;Arena&amp;lt;Node&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;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;I&#x27;ve found that this lifetime gets in the way a lot, and results in unergonomic interfaces. It also means the &lt;code&gt;Graph&lt;&#x2F;code&gt; can never be moved after a node is inserted, which is an unnecessary requirement, given how arena allocated nodes are always on the heap.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;is-this-really-a-good-idea&quot;&gt;Is this really a good idea??&lt;&#x2F;h2&gt;
&lt;p&gt;Sometimes we don&#x27;t do things because they&#x27;re good. We do them because they are bad.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;see-also&quot;&gt;See also&lt;&#x2F;h2&gt;
&lt;p&gt;Just minutes after publishing this, I came &lt;a href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=19701425&quot;&gt;across&lt;&#x2F;a&gt; Alexis Beingessner&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;raw.githubusercontent.com&#x2F;Gankro&#x2F;thesis&#x2F;master&#x2F;thesis.pdf&quot;&gt;thesis&lt;&#x2F;a&gt;, which describes this exact technique in section 6.3, although  &lt;code&gt;PhantomData&amp;lt;Cell&amp;lt;&#x27;a u8&amp;gt;&amp;gt;&lt;&#x2F;code&gt; is used to make the lifetime invariant instead of my &lt;code&gt;PhantomData&amp;lt;&amp;amp;&#x27;a mut &amp;amp;&#x27;a ()&amp;gt;&lt;&#x2F;code&gt;. To quote Alexis:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;we &lt;em&gt;really&lt;&#x2F;em&gt; don’t recommend doing this&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I guess this is just one more post to add to the &lt;a href=&quot;https:&#x2F;&#x2F;lord.io&#x2F;blog&#x2F;2019&#x2F;text-editing-hates-you-too&#x2F;&quot;&gt;pile of evidence&lt;&#x2F;a&gt; that my blog is just a cheap ripoff of &lt;a href=&quot;https:&#x2F;&#x2F;gankra.github.io&#x2F;&quot;&gt;Alexis&#x27;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Identity Beyond Usernames</title>
    <published>2020-07-07T00:00:00+00:00</published>
    <updated>2020-07-07T00:00:00+00:00</updated>
    <link href="https://lord.io/usernames/" type="text/html"/>
    <id>https://lord.io/blog/2020/usernames/</id>
    <content type="html">&lt;p&gt;In 2006, Robert Andersen sent &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;rsa&#x2F;status&#x2F;55281&quot;&gt;the first tweet that @mentioned another user&lt;&#x2F;a&gt;, and an internet convention was born.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2020&#x2F;usernames_1.png&quot; alt=&quot;A screenshot of a tweet reading &amp;quot;@ buzz - you broke your thumb and youre still twittering? that&#x27;s some serious devotion&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In a world without smartphones, Twitter&#x27;s primary interface was SMS. There were no threads, no @username autocomplete. If a user said something and you wanted to reply, your only option was to compose a new text to 40404, manually typing the @mention into your phone&#x27;s SMS text box. SMS was also the origin of Twitter&#x27;s original &lt;a href=&quot;https:&#x2F;&#x2F;developer.twitter.com&#x2F;en&#x2F;docs&#x2F;basics&#x2F;counting-characters&quot;&gt;140 character&lt;&#x2F;a&gt; limit:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Twitter began as an SMS text-based service. This limited the original Tweet length to 140 characters (which was partly driven by the 160 character limit of SMS, with 20 characters reserved for commands and usernames).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Also a holdover from the SMS days, Twitter does not allow any formatted or rich text. Users today work around this limitation by using the wide array of possibilities that Unicode affords. &lt;a href=&quot;https:&#x2F;&#x2F;technastic.com&#x2F;bold-text-twitter-mobile-web&#x2F;#List_of_Online_Text_Generators&quot;&gt;Text generators&lt;&#x2F;a&gt; convert ASCII characters into 𝔲𝔫𝔲𝔰𝔲𝔞𝔩 𝔘𝔫𝔦𝔠𝔬𝔡𝔢 𝔠𝔥𝔞𝔯𝔞𝔠𝔱𝔢𝔯𝔰. Memes take advantage of repeated spaces to position text, or to draw Unicode houses. (All of that is, of course, completely inaccessible to screen readers.) Emoji modifiers allow expressing a wide range of emotions with modifiers for skin tones and gender.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2020&#x2F;usernames_5.png&quot; alt=&quot;two screenshots, one of a unicode house reading &amp;quot;in this house we worship unicode&amp;quot; and another with a tweet from @helllzgirl that say &amp;quot;cashiers 🤝 ariana grande ... thank u, next&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Critically, this &amp;quot;plain&amp;quot; text is fully copy-pastable into any app with Unicode support. While many Twitter users from 2006 were likely limited to the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;GSM_03.38#GSM_8_bit_data_encoding&quot;&gt;GSM-7 encoding&lt;&#x2F;a&gt;, the limitations of the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;T9_(predictive_text)&quot;&gt;T9 keyboard&lt;&#x2F;a&gt;, and their phone&#x27;s limited text rendering and shaping, modern users have found new ways to express themselves using the full Unicode character space. Nowadays, tweets, names, URLs, hashtags, basically &lt;em&gt;everything&lt;&#x2F;em&gt; can contain Unicode characters. Of course, everything except the @mention.&lt;&#x2F;p&gt;
&lt;p&gt;Usernames on Twitter have more or less the same requirements as during the SMS era — up to 15 letters from &lt;code&gt;a-z&lt;&#x2F;code&gt;, numbers from &lt;code&gt;0-9&lt;&#x2F;code&gt; and the underscore &lt;code&gt;_&lt;&#x2F;code&gt;. This requirement is similar to many other websites: GitHub only allows alphanumeric characters and non-repeating hyphens, and Facebook allows just alphanumeric characters and the period.&lt;&#x2F;p&gt;
&lt;p&gt;As we will see, this limitation is one of several problems with usernames.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unicode-usernames&quot;&gt;Unicode Usernames&lt;&#x2F;h2&gt;
&lt;p&gt;Imagine if instead of alphanumerics, GitHub allowed usernames to only be made up of the numbers &lt;code&gt;0-9&lt;&#x2F;code&gt; and Chinese characters. It would be pretty frustrating, right? If forced to use a system like this, we would likely ignore the Chinese characters, and just use the numbers as usernames. This is often what happens on social media platforms in countries that don&#x27;t use Latin script. In China, the QQ instant messaging service (originally started in 1999) completely got rid of usernames used by similar services like AOL. Instead, each user is assigned a unique number, their QQ ID. This number cannot be chosen by the user, and is immutable. WeChat similarly assigns users a random number when they sign up, although it does allow each user exactly one opportunity to change it to an alphanumeric string of their choice. Typing long numbers isn&#x27;t particularly ergonomic, which could help explain the widespread use of QR codes in China.&lt;&#x2F;p&gt;
&lt;p&gt;Even in Latin-speaking countries, AOL-style usernames had issues. By requiring a username when logging in, and &lt;em&gt;also&lt;&#x2F;em&gt; requiring usernames to be unique among all users, users are often forced to use different usernames on different services, creating a second password that they had to memorize. Thankfully, most services have fixed at least this small problem by having login be email- instead of username-based.&lt;&#x2F;p&gt;
&lt;p&gt;Throughout the world, usernames are alphanumeric only. Why can&#x27;t we just allow Unicode, so that usernames could contain Chinese, Cyrillic, or other non-Latin alphabets? Unfortunately Unicode usernames have their own issues — just look at the largest username system in the world, the domain name system and the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Internationalized_domain_name&quot;&gt;extension that allowed non-ASCII characters&lt;&#x2F;a&gt;. This was an essential upgrade, and yet it has inperfections, allowing the &lt;a href=&quot;https:&#x2F;&#x2F;www.wordfence.com&#x2F;blog&#x2F;2017&#x2F;04&#x2F;chrome-firefox-unicode-phishing&#x2F;&quot;&gt;registration of websites&lt;&#x2F;a&gt; such as this one:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2020&#x2F;usernames_2.png&quot; alt=&quot;screenshot of browser window, URL bar reads &amp;quot;epic.com&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is latest Firefox, as of July 2020, displaying what appears to be &amp;quot;epic.com&amp;quot;, the website of a large healthcare company. However, as you can see, the content is actually some random blog reminding people to drink water. How is this possible? If we stick the code into a Unicode character inspector, we can see what&#x27;s going on:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2020&#x2F;usernames_3.png&quot; alt=&quot;screenshot of unicode character inspector revealing &amp;quot;epic&amp;quot; to actually be &amp;quot;еріс&amp;quot;. of course you, a screen reader user, aren&#x27;t fooled.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Byte-wise, the real &amp;quot;epic.com&amp;quot; and the false website &amp;quot;еріс.com&amp;quot; are completely different. But visually, they&#x27;re indistinguishable from each other in the URL bar, allowing phishing problems to run amock. Unicode &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unicode_equivalence&quot;&gt;canonicalization and normalization&lt;&#x2F;a&gt; can help with certain cases of this problem, but does nothing for our epic.com example.&lt;&#x2F;p&gt;
&lt;p&gt;This particular example isn&#x27;t visible in Chrome, which instead shows &lt;code&gt;https:&#x2F;&#x2F;xn--e1awd7f.com&#x2F;&lt;&#x2F;code&gt;, the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Punycode&quot;&gt;&amp;quot;punycode&amp;quot;&lt;&#x2F;a&gt; representation of the domain name. This is thanks to Chrome&#x27;s complex, &lt;a href=&quot;https:&#x2F;&#x2F;chromium.googlesource.com&#x2F;chromium&#x2F;src&#x2F;+&#x2F;76be97d896f266d6b73b2fe0af5d6d479ca31306&#x2F;docs&#x2F;idn.md&quot;&gt;13 step process&lt;&#x2F;a&gt; for detecting if a domain name is likely to be a Unicode phish or not. &amp;quot;Well, it may be complex,&amp;quot; you tell me, &amp;quot;but at least it solves the phishing problem!&amp;quot; Unfortunately it does not.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Specific instances of IDN homograph attacks have been reported to Chrome, and we continually update our IDN policy to prevent against these attacks.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The Unicode spec is apparently too large to solve this problem 100% perfectly, and so their &amp;quot;solution&amp;quot; is to pay $2000 to anybody who finds new edge cases. This also doesn&#x27;t actually solve the problem for non-Latin alphabets — if for example, I own a Chinese domain name, it will never show punycode, and attackers can phish my site using duplicate encodings for those Chinese characters. Chrome just attempts to solve the much smaller problem of the numerous Unicode characters that visually look like the Latin alphabet.&lt;&#x2F;p&gt;
&lt;p&gt;This is probably frustrating to read, and you may want to point fingers at Unicode, for failing to provide canonical encodings for a series of graphemes. Or perhaps we can blame the domain name registrars, for allowing visually identical registrations. But I think the real culprit here is the incorrect assumption we Latin script users have when we build usernames into our systems. We assume that two visually-identical printed text tokens will have the same bytewise encoding. This is simply not true for a huge portion of computer users, and is a root failing with username-based systems today. The only solution is to develop systems that don&#x27;t have usernames.&lt;&#x2F;p&gt;
&lt;p&gt;Even in a trusted system with no bad actors, there is no guarantee a user retyping a non-Latin username from a printed document will end up with the same bytes as the original document.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;changing-usernames&quot;&gt;Changing Usernames&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s say you&#x27;re building a site for English use only, and so even after reading all of this, you think perhaps it&#x27;s ok to have usernames. After all, you&#x27;ll probably find, like Twitter did, that this makes text entry for @mentions &lt;em&gt;much&lt;&#x2F;em&gt; simpler to implement. You get to use just a plain text field, instead of building an input field that can insert custom @mention objects.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, you will still run into the issue of somebody &lt;em&gt;changing&lt;&#x2F;em&gt; their username. This is often an extremely complex problem. Take &lt;a href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;github&#x2F;setting-up-and-managing-your-github-user-account&#x2F;changing-your-github-username&quot;&gt;GitHub&lt;&#x2F;a&gt; for example. Changing your username there will redirect your old repository links to new ones. However, somebody else can come in and use your old username. What happens if they create a repo with the same name as your old one?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the new owner of your old username creates a repository with the same name as your repository, that will override the redirect entry and your redirect will stop working.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;URLs aren&#x27;t the only place GitHub usernames are used. Using the web interface, in some cases, will create commits with the email &lt;code&gt;myusername@users.noreply.github.com&lt;&#x2F;code&gt;. These commits will permanantly be disconnected from your account, unless you somehow are able to force push edited commit headers to every repository you&#x27;ve ever contributed to. Good luck with that.&lt;&#x2F;p&gt;
&lt;p&gt;Instagram has issues with changing usernames, too. Up until 2015, updating your username would cause you to lose all your previous @mentions. They&#x27;ve since fixed this; old @mentions eventually update. Twitter supposedly will also preserve your replies, although my testing shows this is an unreliable feature at best. Updating the actual @mention as it&#x27;s listed in the Tweet would have other issues, since if a user mentioned in a 280-character tweet adds 5 characters to their username, you&#x27;d suddenly get a 285-character tweet. Hope your Twitter clients can all support that.&lt;&#x2F;p&gt;
&lt;p&gt;The final example of username switching pains I have is from my year at Google. I was fortunate enough to never switch my username, perfectly satisfied every morning when I opened my laptop and saw &lt;code&gt;lard@google.com&lt;&#x2F;code&gt; on the login screen. But countless internal systems used by engineers there assume usernames are immutable, making a username switch a multi-day process that is never really complete.&lt;&#x2F;p&gt;
&lt;p&gt;There is one easy &amp;quot;solution&amp;quot; to all of this, of course, which is to make it impossible to change your username. This is &lt;a href=&quot;https:&#x2F;&#x2F;support.google.com&#x2F;accounts&#x2F;answer&#x2F;19870?co=GENIE.Platform%3DAndroid&amp;amp;hl=en&quot;&gt;what gmail does&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If your account&#x27;s email address ends in @gmail.com, you usually can&#x27;t change it.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I love the &amp;quot;usually&amp;quot;. I guess in certain, mysterious cases it&#x27;s possible to change it? In any case, making a random, numeric user ID immutable is fine. But if that user ID contains letters and is user-selected, making it immutable is an unacceptable solution for real-world situations. Whether it contains a user&#x27;s deadname, or an old nickname they don&#x27;t go by any longer, or even for those of us who, in sixth grade, decided &amp;quot;lordjubjub&amp;quot; would be an excellent and professional email address (just a hypothetical example, of course), usernames need to be editable. If they&#x27;re editable, why not avoid all these username troubles and just go for a fully-Unicode, non-unique display name instead?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;username-alternatives&quot;&gt;Username Alternatives&lt;&#x2F;h2&gt;
&lt;p&gt;250 million people have registered for Discord, a chat app similar to Slack or IRC. However, unlike Slack and IRC whose usernames are local to a particular server, Discord has just one server, and usernames are universal. With 250 million users in a single username space, collisions become a massive problem, finding short or reasonable usernames becomes nearly impossible, and you start to see users mass-registering accounts to sell the usernames for Bitcoin.&lt;&#x2F;p&gt;
&lt;p&gt;To avoid all these issues, Discord dropped uniqueness requirements. Multiple users can all have the same username, although they aren&#x27;t quite a display name, since a Discord-generated &lt;code&gt;#1234&lt;&#x2F;code&gt; discriminator number appears at the end of usernames in certain contexts. This even allows them to have &lt;a href=&quot;https:&#x2F;&#x2F;discord.com&#x2F;developers&#x2F;docs&#x2F;resources&#x2F;user&quot;&gt;fully-Unicode usernames&lt;&#x2F;a&gt;; username phishing is less of a problem when users expect duplicate usernames, and none of your systems depend on username uniqueness.&lt;&#x2F;p&gt;
&lt;p&gt;Slack went futher than this, and in 2017 decided to &lt;a href=&quot;https:&#x2F;&#x2F;api.slack.com&#x2F;changelog&#x2F;2017-09-the-one-about-usernames#happens&quot;&gt;phase out usernames completely&lt;&#x2F;a&gt; in favor of display names only. Users @mention each other by typing an &lt;code&gt;@&lt;&#x2F;code&gt;, a few characters of a person&#x27;s name, and clicking on the dropdown. In some cases when there are duplicate display names, not selecting from the dropdown will result in an error:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2020&#x2F;usernames_4.png&quot; alt=&quot;a screenshot of slack docs reading &amp;quot;If there are multiple matches for a display name, you’ll see a dotted blue box around the name you’ve entered. Click the question mark to select the person you’d like to mention in your message.&amp;quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As a text editing engineer, I also can&#x27;t help but look at this through the lens of text editing technologies. (Yes, that&#x27;s right! It&#x27;s always about text editing.) Usernames are a product of the text input and encoding systems used in decades past — just look at how Twitter&#x27;s username needs were influenced by SMS protocols. The username advances made by Slack and Discord are only possible because they&#x27;re able to build rich text editors (&lt;a href=&quot;&#x2F;blog&#x2F;2019&#x2F;selecting-across-components&#x2F;&quot;&gt;difficult with modern frameworks!&lt;&#x2F;a&gt;) that allow embedded, autocompleted @mentions that don&#x27;t rely on the uniqueness of text tokens. You might be surprised just how much of the UI landscape is driven by these changes and advances in text editing.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve just got one final note: while they&#x27;re extremely common, usernames are far from the only example of text as a unique token. JSON APIs use text tokens everywhere; we&#x27;ve only recently seen protocols with renamable fields like &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;protocol-buffers&quot;&gt;protobuf&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;capnproto.org&#x2F;&quot;&gt;capnproto&lt;&#x2F;a&gt; gain popularity. Variables in programming languages are also common text tokens, and while arguably changing a name isn&#x27;t a large deal for local variables, changing the name of a public class in most languages I know is a breaking change. Filesystem directories, too, are unique text tokens, and can suffer from naming conflicts where two bits of software have the same command name, or store their settings in the same directory.&lt;&#x2F;p&gt;
&lt;p&gt;Proposing to get rid of variable labels or filenames may sound impossible, or wild, or unnecessary, but our industry&#x27;s waning love for the username shows there are numerous benefits to avoiding text-based unique tokens. If we want to move onward from these limitations, we shouldn&#x27;t look toward fixing the tokens themselves. We already know technically how to generate unique numeric identifiers, and we could easily just generate unique numbers for directories or programming language entities. Instead, Slack and Discord show us the main problem — plain text editing forces us to conflate our model of identity with our model for labels.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out this isn&#x27;t a text token problem. It&#x27;s a text editing problem.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Text Editing Hates You Too</title>
    <published>2019-10-28T00:00:00+00:00</published>
    <updated>2019-10-28T00:00:00+00:00</updated>
    <link href="https://lord.io/text-editing-hates-you-too/" type="text/html"/>
    <id>https://lord.io/blog/2019/text-editing-hates-you-too/</id>
    <content type="html">&lt;p&gt;Alexis Beingessner&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;gankra.github.io&#x2F;blah&#x2F;text-hates-you&#x2F;&quot;&gt;Text Rendering Hates You&lt;&#x2F;a&gt;, published exactly a month ago today, hits very close to my heart.&lt;&#x2F;p&gt;
&lt;p&gt;Back in 2017, I was building a rich text editor in the browser. Unsatisfied with existing libraries that used ContentEditable, I thought to myself &amp;quot;hey, I&#x27;ll just reimplement text selection myself! How difficult could it possibly be?&amp;quot; I was young. Naive. I estimated it would take two weeks. In reality, attempting to solve this problem would consume several years of my life, and even landed me a full time job for a year implementing text editing for a new operating system.&lt;&#x2F;p&gt;
&lt;p&gt;While on the job, I was lucky enough to learn from mentors&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; who had tons of experience in this field. I heard many, many horror stories, including of one person maintaining a Windows application that had a custom text field implementation. They wanted to upgrade from the legacy Windows text input API to a newer version. Let&#x27;s look at &lt;a href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;windows&#x2F;win32&#x2F;tsf&#x2F;text-services-framework-interfaces&quot;&gt;the interface list&lt;&#x2F;a&gt; for that newer version:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_1.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_1.png 2x&quot; alt=&quot;a massive list of obscure sounding interface names&quot;&gt;
&lt;p&gt;That&#x27;s right, the Windows text input APIs contain 128 interfaces. I&#x27;m pretty sure there are also eight (8!) different types of locks to fix concurrency issues, although I honestly haven&#x27;t read their documentation, so don&#x27;t quote me on that. Anyway, this engineer I heard about spent a year and a half (full-time!) attempting the upgrade, and in the end, their efforts ended in failure. They ended up staying on the legacy API.&lt;&#x2F;p&gt;
&lt;p&gt;Text input is difficult.&lt;&#x2F;p&gt;
&lt;p&gt;Alexis already touches on selection in a couple places, but as she mentions in her article, her experience is with working on text rendering. From the perspective of somebody who worked on the editing side of things, I have just a few points to add.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;vertical-cursor-movement&quot;&gt;Vertical Cursor Movement&lt;&#x2F;h2&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_9.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_9.png 2x&quot; alt=&quot;a screenshot of a caret in the top middle of a textbox&quot;&gt;
&lt;p&gt;In this example, if the user presses up, the caret will go to the beginning of the line, before &amp;quot;hello&amp;quot;. This is pretty reasonable so far. However, if the user presses up and then down, the caret will first jump before &amp;quot;hello&amp;quot;, and then after the word &amp;quot;some&amp;quot;.&lt;&#x2F;p&gt;
&lt;p&gt;This may seem unintuitive. Why does it jump rightward? Well, each caret remembers an x-position in pixels that is used for vertical movements, and this position is only updated when the user presses left or right, &lt;em&gt;not&lt;&#x2F;em&gt; up and down. This is the same behavior that prevents carets from migrating left when vertically moving past short lines.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;affinity&quot;&gt;Affinity&lt;&#x2F;h2&gt;
&lt;p&gt;Ok, so we now know that a text selection has &lt;em&gt;two&lt;&#x2F;em&gt; chunks of state, the byte offsets of its position inside the string and the x-position in pixels mentioned above. Problem solved? Well, no.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s look at two caret positions on a very long line:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_2.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_2.png 2x&quot; alt=&quot;a textbox with a very long soft-wrapped line, and a caret right before and after the soft line break&quot;&gt;
&lt;p&gt;Since &amp;quot;loooooooooong&amp;quot; is a single word, the two caret positions have &lt;em&gt;exactly the same byte offset in the string&lt;&#x2F;em&gt;. There&#x27;s no newline character between them, since the line is soft wrapped. Our carets will need an extra bit that tells them which line to tend towards. Most systems call this bit &amp;quot;affinity&amp;quot;. This same bit is also used in mixed bidirectional text, which we&#x27;ll get to in a moment.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;emoji-modifiers&quot;&gt;Emoji Modifiers&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s say I&#x27;m sending a message to my friend. To emphasize my excitement, I want to add in a fun lil emoji. I fill a textarea with a thumbs up, the letter &lt;code&gt;a&lt;&#x2F;code&gt;, and an emoji skin tone modifier. It looks like this:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_10.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_10.png 2x&quot; alt=&quot;a text field containing a yellow thumbs up, the letter a, and a light skin tone emoji modifier&quot;&gt;
&lt;p&gt;Whoops, I didn&#x27;t mean to put the &lt;code&gt;a&lt;&#x2F;code&gt; there. I position the caret after the &lt;code&gt;a&lt;&#x2F;code&gt; and press backspace. What happens? I&#x27;ve seen several outcomes, depending on the editor.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_11.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_11.png 2x&quot; alt=&quot;three text fields, all labeled bad. the first has a yellow thumbs up and skin tone modifier, the second has just a yellow thumbs up, and the third has just a light skin tone thumbs up emoji&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bad #1&lt;&#x2F;strong&gt; may &lt;em&gt;look&lt;&#x2F;em&gt; correct. But this is what happens in a text editor that has outdated emoji rendering support, like Sublime Text. This is bad because a light skin tone thumbs up emoji is encoded as the yellow thumbs up emoji immediately followed by the light skin tone modifier. Byte-wise, this should be rendered as a single emoji. Even if I copy-pasted one from another application, it would still be rendered incorrectly like this.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Bad #2&lt;&#x2F;strong&gt; is what Chrome 77 does in the address bar. Not on web pages, just the address bar. This is not a rendering problem, since copy-pasting a emoji with a skin tone works. Instead, Chrome deletes the &lt;code&gt;a&lt;&#x2F;code&gt;, and then noticing that the &lt;code&gt;a&lt;&#x2F;code&gt; is modified by a skin tone, deletes the skin tone too. Whoops.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Bad #3&lt;&#x2F;strong&gt; is &amp;quot;correct&amp;quot; according to the Unicode spec in that the two emoji merge into one. But it&#x27;s pretty confusing for users, and bytewise, our caret has to move in order to not be stuck halfway inside a single emoji.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Those options are all bad, so you&#x27;re probably hoping there&#x27;s some fourth option. There is! Many editors, like TextEdit, won&#x27;t even allow us to put a caret after the &lt;code&gt;a&lt;&#x2F;code&gt;, since the skin tone modifier is treated as a single unit with its previous character. This makes sense in the emoji context, and even works alright for this &lt;code&gt;a&lt;&#x2F;code&gt;. However, what happens when the emoji modifier is the first character on a line?&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_12.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_12.png 2x&quot; alt=&quot;a textedit screenshot, with a thumbs down emoji on the first line and an emoji skin tone modifier on the second line&quot;&gt;
&lt;p&gt;The emoji modifier is now modifying the newline character. TextEdit won&#x27;t let us place a caret at the start of the second line! I&#x27;d personally consider this solution &amp;quot;also bad&amp;quot;.&lt;&#x2F;p&gt;
&lt;p&gt;You also may have noticed that the thumbs up has switched to a thumbs down. I changed that myself to reflect my feelings about this whole situation.&lt;&#x2F;p&gt;
&lt;p&gt;As an aside, TextEdit specifically makes carets on the first line &lt;em&gt;very&lt;&#x2F;em&gt; buggy. For instance, guess what happens if I press &lt;code&gt;4&lt;&#x2F;code&gt; here?&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_13.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_13.png 2x&quot; alt=&quot;a textedit screenshot, with a thumbs down emoji, 1, 2, and 3 on the first line and thenan emoji skin tone modifier on the second line. the caret is at the beginning of the document, before the thumbs down emoji, but typing a 4 inserts the four at the end of the line&quot;&gt;
&lt;p&gt;Yup. You also may think there are spaces between those numbers. There aren&#x27;t.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bidirectional-text&quot;&gt;Bidirectional Text&lt;&#x2F;h2&gt;
&lt;p&gt;Alexis mentions disconnected selections in mixed bi-directional text, like this example from TextEdit:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_3.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_3.png 2x&quot; alt=&quot;some mixed bidirectional text, with a split selection&quot;&gt;
&lt;p&gt;This actually makes sense, since Arabic in strings is encoded from right to left, so this selection appears disconnected, but byte-wise represents a contiguous range of the string.&lt;&#x2F;p&gt;
&lt;p&gt;This makes it a little surprising, then, that we can get &lt;em&gt;this&lt;&#x2F;em&gt; selection:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_4.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_4.png 2x&quot; alt=&quot;some mixed bidirectional text, with a contiguous selection that crosses a bidirectional boundary&quot;&gt;
&lt;p&gt;Yes, that is a visually contiguous, byte-wise disconnected selection. Yes, this is bad. Some text editing engines do this when you select with the arrow keys instead of the mouse. The alternative is flipping left&#x2F;right arrow keys inside the RTL range, which is also bad. There are no good solutions here.&lt;&#x2F;p&gt;
&lt;p&gt;For extra credit, you can try to figure out what&#x27;s going on here:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_5.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_5.png 2x&quot; alt=&quot;oh god&quot;&gt;
&lt;p&gt;I don&#x27;t want to talk about that selection.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;input-methods-are-a-thing&quot;&gt;Input Methods are a Thing&lt;&#x2F;h2&gt;
&lt;p&gt;The software that translates keypresses into input is called an &amp;quot;input method&amp;quot; or &amp;quot;input method editor&amp;quot;. For the Latin alphabet used by English speakers, this isn&#x27;t terribly interesting software, since each keypress gets directly mapped to inserting a single character. But quite a few languages have too many characters for a single keyboard, and so they need to get creative. For instance, with some Chinese input methods, the user types the pronounciation of what they&#x27;re trying to say, and get a list of characters that match phonetically:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_6.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_6.png 2x&quot; alt=&quot;an example of pinyin input on macOS&quot;&gt;
&lt;p&gt;This is sometimes called a composing region, and it often appears as underlined text. Sometimes the input method needs to style this region. This Japanese input method on Android, for example, uses background color to create a split suggestion region:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_8.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_8.png 2x&quot; alt=&quot;a screenshot of a split composition region on android&quot;&gt;
&lt;p&gt;&lt;small class=&quot;faded center&quot;&gt;(Thanks to Shae for the screenshot!)&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Do all these various highlight and compose ranges interact with bidirectional text? Let&#x27;s not think about that.&lt;&#x2F;p&gt;
&lt;p&gt;Input methods have to work everywhere, &lt;em&gt;even inside a terminal&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;editing_7.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;editing_7.png 2x&quot; alt=&quot;an example of pinyin input in a terminal on macOS&quot;&gt;
&lt;p&gt;Nothing is actually sent to Vim until the Chinese character is selected from the list. You&#x27;re probably thinking &amp;quot;but how would that work with Vim&#x27;s command mode?&amp;quot; Not very well. This is why, on the web, text input and keypresses are separate events. Terminals conflate these two, causing problems.&lt;&#x2F;p&gt;
&lt;p&gt;This is just one example of the many, many different ways that people input text. (Don&#x27;t forget about non-keyboard methods like voice and handwriting input!) Fortunately for text field implementors, the operating system provides all these input methods for you. Unfortunately for text field implementors, you have to get your text field to speak the common text input protocol used by all these input methods. For Windows, that&#x27;s those 128 interfaces listed at the beginning of this article. Other operating systems have simpler interfaces, but usually they&#x27;re still tricky to implement.&lt;&#x2F;p&gt;
&lt;p&gt;You also may have noticed that the input method is a separate process from our text field, and since both the input method and application can make modifications to the state of the text field, this protocol is a concurrent editing protocol. Windows solves this with its eight (8!) types of locks. Although holding a lock across process boundaries may sound questionable to you, most other platforms try to use imperfect heuristics to fix concurrency issues. Or they just hope race conditions don&#x27;t happen. In my experience, prayers are not a very effective concurrency primitive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-is-this-so-complicated&quot;&gt;Why is this so complicated??&lt;&#x2F;h2&gt;
&lt;p&gt;Jonathan Blow, in a talk about how software is getting worse, points to the example of &lt;a href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;pW-SOdj4Kkk?t=2116&quot;&gt;Ken Thompson&#x27;s text editor&lt;&#x2F;a&gt;, which Ken built in a single week. Plenty of the code in this blog post is accidental complexity. Does Windows need 128 interfaces and 8 kinds of locks to provide text input? Absolutely not. Are the bugs we&#x27;ve found in TextEdit disappointing, and a result of a complicated editing model? Yes. Are the wealth of bugs in modern programs something we should be worried about? I&#x27;m worried, at least.&lt;&#x2F;p&gt;
&lt;p&gt;But at the same time, Ken Thompson&#x27;s editor was much, much simpler than what we expect from our text editors today. Unicode supports almost every one of the ~7000 living languages used around the world, and plenty more dead languages too. These use a variety of scripts, directions, and input methods that each impose tricky (and in some cases, unsolved) problems on any editor we&#x27;d like to make. Our editor also needs to be usable by vision-impaired folks who use screen readers.&lt;&#x2F;p&gt;
&lt;p&gt;The necessary complexity here is &lt;em&gt;immense&lt;&#x2F;em&gt;, and this post only scratches the very surface of it. If anything, it&#x27;s a miracle of the simplicity of modern programming that we&#x27;re able to just slap down a &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;&#x2F;code&gt; on a web page and instantly provide a text input for every internet user around the globe.&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;Thanks, as always, to Raph Levien and Yohei Yukawa, who taught me everything I know about text input.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Hatched Icosahedron</title>
    <published>2019-10-23T00:00:00+00:00</published>
    <updated>2019-10-23T00:00:00+00:00</updated>
    <link href="https://lord.io/hatched-icosahedron/" type="text/html"/>
    <id>https://lord.io/blog/2019/hatched-icosahedron/</id>
    <content type="html">&lt;style&gt;
  canvas {
    width: 100vw;
    height: 100vh;
    display: block;
  }
&lt;&#x2F;style&gt;
&lt;p&gt;&lt;canvas id=&quot;c&quot;&gt;&lt;&#x2F;canvas&gt;&lt;&#x2F;p&gt;
&lt;script src=&quot;https:&#x2F;&#x2F;webglfundamentals.org&#x2F;webgl&#x2F;resources&#x2F;webgl-utils.js&quot;&gt;&lt;&#x2F;script&gt;
&lt;!-- vertex shader --&gt;
&lt;script id=&quot;2d-vertex-shader&quot; type=&quot;x-shader&#x2F;x-vertex&quot;&gt;
attribute vec2 a_position;
void main() {
  gl_Position = vec4(a_position, 0.5, 1.);
}
&lt;&#x2F;script&gt;
&lt;script id=&quot;2d-fragment-shader&quot; type=&quot;x-shader&#x2F;x-vertex&quot;&gt;
precision highp float;
uniform sampler2D u_texture;
uniform float u_time;
uniform vec2 u_screenres;
void main() {
  vec2 unmirroredCoords = gl_FragCoord.xy - (u_screenres &#x2F; 2.0);
  float sqscreen = min(u_screenres.x*2.5, u_screenres.y);
  float spacing = 8. + sin(u_time&#x2F;7.) * 3.;
  &#x2F;&#x2F; adjust spacing for screen size
  spacing *= sqscreen &#x2F; 800.;

  vec2 normalizedCoords = unmirroredCoords;
  normalizedCoords.y = abs(sqscreen&#x2F;15. + unmirroredCoords.y + sqscreen&#x2F;14.) - sqscreen&#x2F;14.;
  normalizedCoords.x += step(unmirroredCoords.y, -sqscreen&#x2F;7.) * sqscreen&#x2F;150. * sin(u_time + (normalizedCoords.y &#x2F; sqscreen * 80.));

  const float SQUARE_ROOT_2 = 1.414213576;

  float manhattanHashDist = mod(float(normalizedCoords.x + normalizedCoords.y), (spacing&#x2F;SQUARE_ROOT_2) * 2.);
  normalizedCoords.x -= manhattanHashDist &#x2F; 2.;
  normalizedCoords.y -= manhattanHashDist &#x2F; 2.;
  float hashDist = SQUARE_ROOT_2 * (manhattanHashDist &#x2F; 2.);

  vec2 texCoord = vec2(normalizedCoords &#x2F; sqscreen) + vec2(0.5, 0.5);
  float light = texture2D(u_texture, texCoord).x;
  const int maxSampleCount = 14;
  int sampleCount = int(sin(u_time&#x2F;11.) * 6. + 7.);
  for (int i = 0; i &lt; maxSampleCount; i++) {
    if (i &lt; sampleCount) {
      light += texture2D(u_texture, texCoord - vec2(float(i)&#x2F;700.)).x;
      light += texture2D(u_texture, texCoord + vec2(float(i)&#x2F;700.)).x;
    }
  }
  light &#x2F;= float(sampleCount) * 2.0 + 1.0;

  float width = light * light * light * (spacing-1.5);
  vec3 color = vec3( smoothstep((spacing-width)&#x2F;2., (spacing-width)&#x2F;2.+1.8, hashDist) -
                     smoothstep(spacing-(spacing-width)&#x2F;2., spacing-(spacing-width)&#x2F;2.+1.8, hashDist) );
  color -= color * step(unmirroredCoords.y, -sqscreen&#x2F;7.) * (abs(unmirroredCoords.y &#x2F; sqscreen * 0.8) + 0.6);
  color = max(color, 0.06); &#x2F;&#x2F; background color
  gl_FragColor = vec4(max(color, 0.06), 1);
  &#x2F;&#x2F; gl_FragColor = vec4(vec3(light), 1);
}
&lt;&#x2F;script&gt;
&lt;script id=&quot;3d-vertex-shader&quot; type=&quot;x-shader&#x2F;x-vertex&quot;&gt;
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec4 a_color;
attribute vec2 a_bary;
varying vec3 v_normal;
varying vec2 v_bary;

uniform mat4 u_projection;
uniform mat4 u_world;

varying vec4 v_color;

void main() {
  &#x2F;&#x2F; Multiply the position by the matrix.
  gl_Position = u_projection * a_position;

  &#x2F;&#x2F; Pass the color to the fragment shader.
  v_normal = mat3(u_world) * a_normal;
  v_color = a_color;
  v_bary = a_bary;
}
&lt;&#x2F;script&gt;
&lt;!-- fragment shader --&gt;
&lt;script id=&quot;3d-fragment-shader&quot; type=&quot;x-shader&#x2F;x-fragment&quot;&gt;
#extension GL_EXT_shader_texture_lod : enable
#extension GL_OES_standard_derivatives : enable

precision mediump float;

varying vec3 v_normal;
varying vec4 v_color;
varying vec2 v_bary;

void main() {
  vec3 normal = normalize(v_normal.xyz);
  float light = max(0.2, dot(normal, normalize(vec3(0.5,0.5,1.5))) * 0.6 + 0.4);
  &#x2F;&#x2F; gl_FragColor = max(vec4(vec3(color), 1.0), 0.07);
  gl_FragColor = vec4(vec3(light), 1.);
}
&lt;&#x2F;script&gt;
&lt;script&gt;
  function main() {
    &#x2F;&#x2F; Get A WebGL context
    &#x2F;** @type {HTMLCanvasElement} *&#x2F;
    var canvas = document.getElementById(&quot;c&quot;);
    var gl = canvas.getContext(&quot;webgl&quot;);
    gl.getExtension(&#x27;OES_standard_derivatives&#x27;);
    gl.getExtension(&#x27;EXT_shader_texture_lod&#x27;);
    if (!gl) {
      return;
    }

    &#x2F;&#x2F; setup GLSL program
    var program3d = webglUtils.createProgramFromScripts(gl, [&quot;3d-vertex-shader&quot;, &quot;3d-fragment-shader&quot;]);
    var program2d = webglUtils.createProgramFromScripts(gl, [&quot;2d-vertex-shader&quot;, &quot;2d-fragment-shader&quot;]);

    &#x2F;&#x2F; look up where the vertex data needs to go.
    var positionLocation = gl.getAttribLocation(program3d, &quot;a_position&quot;);
    var normalLocation = gl.getAttribLocation(program3d, &quot;a_normal&quot;);
    var colorLocation = gl.getAttribLocation(program3d, &quot;a_color&quot;);
    var baryLocation = gl.getAttribLocation(program3d, &quot;a_bary&quot;);

    var position2dLocation = gl.getAttribLocation(program2d, &quot;a_position&quot;);
    var textureLocation = gl.getUniformLocation(program2d, &quot;u_texture&quot;);
    var screenResolutionLocation = gl.getUniformLocation(program2d, &quot;u_screenres&quot;);
    var timeLocation = gl.getUniformLocation(program2d, &quot;u_time&quot;);

    &#x2F;&#x2F; lookup uniforms
    var worldMatrixLocation = gl.getUniformLocation(program3d, &quot;u_world&quot;);
    var projectionMatrixLocation = gl.getUniformLocation(program3d, &quot;u_projection&quot;);

    &#x2F;&#x2F; Create a buffer to put positions in
    var screenVertices = gl.createBuffer();
    &#x2F;&#x2F; Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
    gl.bindBuffer(gl.ARRAY_BUFFER, screenVertices);
    &#x2F;&#x2F; Put geometry data into buffer
    gl.bufferData(
        gl.ARRAY_BUFFER,
        new Float32Array(new Float32Array([
          -1, -1, -1, 1, 1, -1,
          1, 1, -1, 1, 1, -1,
        ])),
        gl.STATIC_DRAW);

    &#x2F;&#x2F; Create a buffer to put positions in
    var positionBuffer = gl.createBuffer();
    &#x2F;&#x2F; Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    &#x2F;&#x2F; Put geometry data into buffer
    setGeometry(gl);

    &#x2F;&#x2F; Create a buffer to put positions in
    var normalBuffer = gl.createBuffer();
    &#x2F;&#x2F; Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = normalBuffer)
    gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
    &#x2F;&#x2F; Put geometry data into buffer
    setNormals(gl);

    &#x2F;&#x2F; Create a buffer to put positions in
    var baryBuffer = gl.createBuffer();
    &#x2F;&#x2F; Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = baryBuffer)
    gl.bindBuffer(gl.ARRAY_BUFFER, baryBuffer);
    &#x2F;&#x2F; Put geometry data into buffer
    setBarycentric(gl);

    &#x2F;&#x2F; Create a buffer to put colors in
    var colorBuffer = gl.createBuffer();
    &#x2F;&#x2F; Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = colorBuffer)
    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    &#x2F;&#x2F; Put geometry data into buffer
    setColors(gl);

    &#x2F;&#x2F; create texture to render to
    const targetTextureWidth = 2048;
    const targetTextureHeight = 2048;
    const targetTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, targetTexture);

    {
      &#x2F;&#x2F; define size and format of level 0
      const level = 0;
      const internalFormat = gl.RGBA;
      const border = 0;
      const format = gl.RGBA;
      const type = gl.UNSIGNED_BYTE;
      const data = null;
      gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
                    targetTextureWidth, targetTextureHeight, border,
                    format, type, data);

      &#x2F;&#x2F; set the filtering so we don&#x27;t need mips
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    }

    &#x2F;&#x2F; Create and bind the framebuffer
    const fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

    &#x2F;&#x2F; attach the texture as the first color attachment
    const attachmentPoint = gl.COLOR_ATTACHMENT0;
    const level = 0;
    gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, targetTexture, level);

    &#x2F;&#x2F; create a depth renderbuffer
    const depthBuffer = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);

    &#x2F;&#x2F; make a depth buffer and the same size as the targetTexture
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, targetTextureWidth, targetTextureHeight);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);

    function radToDeg(r) {
      return r * 180 &#x2F; Math.PI;
    }

    function degToRad(d) {
      return d * Math.PI &#x2F; 180;
    }

    var translation = [0, 0, -360];
    var rotation = [degToRad(180), degToRad(0), degToRad(0)];
    var scale = [1, 1, 1];
    var fieldOfViewRadians = degToRad(60);

    drawScene();

    var n = 190;
    function update() {
      n += 1;
      translation[1] = Math.sin(n&#x2F;50)*6 + 50;
      rotation[1] = degToRad(n&#x2F;4);
      rotation[0] = degToRad(180 + Math.sin(n&#x2F;300)*40);
      drawScene();
      requestAnimationFrame(update);
    }

    requestAnimationFrame(update);

    &#x2F;&#x2F; Draw the scene.
    function drawScene() {
      webglUtils.resizeCanvasToDisplaySize(gl.canvas);

      {
        &#x2F;&#x2F; render to our targetTexture by binding the framebuffer
        gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
        &#x2F;&#x2F; Tell WebGL how to convert from clip space to pixels
        gl.viewport(0, 0, targetTextureWidth, targetTextureHeight);
        &#x2F;&#x2F; Clear the attachment(s).
        gl.clearColor(0, 0, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT| gl.DEPTH_BUFFER_BIT);
        const aspect = targetTextureWidth &#x2F; targetTextureHeight;
        drawIcosohedron(aspect)
      }

      &#x2F;&#x2F; render to the canvas
      {
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);


        &#x2F;&#x2F; render cube with our 3x2 texture
        gl.bindTexture(gl.TEXTURE_2D, targetTexture);

        &#x2F;&#x2F; Tell WebGL how to convert from clip space to pixels
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

        &#x2F;&#x2F; Clear the canvas AND the depth buffer.
        gl.clearColor(0.07,0.07,0.07,1);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        &#x2F;&#x2F; Turn on culling. By default backfacing triangles
        &#x2F;&#x2F; will be culled.
        &#x2F;&#x2F; gl.enable(gl.CULL_FACE);

        &#x2F;&#x2F; Enable the depth buffer
        gl.enable(gl.DEPTH_TEST);
        drawScreenStuff(gl);
      }
    }
    function drawIcosohedron() {
      &#x2F;&#x2F; Tell it to use our program3d (pair of shaders)
      gl.useProgram(program3d);

      &#x2F;&#x2F; Turn on the position attribute
      gl.enableVertexAttribArray(positionLocation);

      &#x2F;&#x2F; Bind the position buffer.
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);

      &#x2F;&#x2F; Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
      var size = 3;          &#x2F;&#x2F; 3 components per iteration
      var type = gl.FLOAT;   &#x2F;&#x2F; the data is 32bit floats
      var normalize = false; &#x2F;&#x2F; don&#x27;t positionize the data
      var stride = 0;        &#x2F;&#x2F; 0 = move forward size * sizeof(type) each iteration to get the next position
      var offset = 0;        &#x2F;&#x2F; start at the beginning of the buffer
      gl.vertexAttribPointer(
          positionLocation, size, type, normalize, stride, offset);


      &#x2F;&#x2F; Turn on the position attribute
      gl.enableVertexAttribArray(normalLocation);

      &#x2F;&#x2F; Bind the position buffer.
      gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);

      &#x2F;&#x2F; Tell the position attribute how to get data out of normalBuffer (ARRAY_BUFFER)
      var size = 3;          &#x2F;&#x2F; 3 components per iteration
      var type = gl.FLOAT;   &#x2F;&#x2F; the data is 32bit floats
      var normalize = false; &#x2F;&#x2F; don&#x27;t normalize the data
      var stride = 0;        &#x2F;&#x2F; 0 = move forward size * sizeof(type) each iteration to get the next position
      var offset = 0;        &#x2F;&#x2F; start at the beginning of the buffer
      gl.vertexAttribPointer(
          normalLocation, size, type, normalize, stride, offset);

      &#x2F;&#x2F; Turn on the color attribute
      gl.enableVertexAttribArray(colorLocation);

      &#x2F;&#x2F; Bind the color buffer.
      gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);

      &#x2F;&#x2F; Tell the attribute how to get data out of colorBuffer (ARRAY_BUFFER)
      var size = 3;                 &#x2F;&#x2F; 3 components per iteration
      var type = gl.UNSIGNED_BYTE;  &#x2F;&#x2F; the data is 8bit unsigned values
      var normalize = true;         &#x2F;&#x2F; normalize the data (convert from 0-255 to 0-1)
      var stride = 0;               &#x2F;&#x2F; 0 = move forward size * sizeof(type) each iteration to get the next position
      var offset = 0;               &#x2F;&#x2F; start at the beginning of the buffer
      gl.vertexAttribPointer(
          colorLocation, size, type, normalize, stride, offset);


      &#x2F;&#x2F; Turn on the color attribute
      gl.enableVertexAttribArray(baryLocation);

      &#x2F;&#x2F; Bind the bary buffer.
      gl.bindBuffer(gl.ARRAY_BUFFER, baryBuffer);

      &#x2F;&#x2F; Tell the attribute how to get data out of baryBuffer (ARRAY_BUFFER)
      var size = 2;                 &#x2F;&#x2F; 3 components per iteration
      var type = gl.FLOAT;  &#x2F;&#x2F; the data is 8bit unsigned values
      var normalize = false;         &#x2F;&#x2F; normalize the data (convert from 0-255 to 0-1)
      var stride = 0;               &#x2F;&#x2F; 0 = move forward size * sizeof(type) each iteration to get the next position
      var offset = 0;               &#x2F;&#x2F; start at the beginning of the buffer
      gl.vertexAttribPointer(
          baryLocation, size, type, normalize, stride, offset);

      &#x2F;&#x2F; Compute the projection matrix
      var aspect = 1;
      var zNear = 1;
      var zFar = 2000;
      var matrix = m4.perspective(fieldOfViewRadians, aspect, zNear, zFar);
      matrix = m4.translate(matrix, translation[0], translation[1], translation[2]);
      matrix = m4.xRotate(matrix, rotation[0]);
      matrix = m4.yRotate(matrix, rotation[1]);
      matrix = m4.zRotate(matrix, rotation[2]);
      matrix = m4.scale(matrix, scale[0], scale[1], scale[2]);

      &#x2F;&#x2F; Set the matrix.
      gl.uniformMatrix4fv(projectionMatrixLocation, false, matrix);

      &#x2F;&#x2F; Compute the world matrix
      var aspect = 1;
      var zNear = 1;
      var zFar = 2000;
      var matrix = m4.xRotation(rotation[0]);
      matrix = m4.yRotate(matrix, rotation[1]);
      matrix = m4.zRotate(matrix, rotation[2]);

      &#x2F;&#x2F; Set the matrix.
      gl.uniformMatrix4fv(worldMatrixLocation, false, matrix);

      &#x2F;&#x2F; Draw the geometry.
      var primitiveType = gl.TRIANGLES;
      var offset = 0;
      var count = 20 * 3;
      gl.drawArrays(primitiveType, offset, count);
    }
    var startTime = (new Date()).getTime() - Math.random() * 100000;
    &#x2F;&#x2F; Draw the pixel shader
    function drawScreenStuff() {
      gl.useProgram(program2d);

      &#x2F;&#x2F; Turn on the position attribute
      gl.enableVertexAttribArray(position2dLocation);

      &#x2F;&#x2F; Bind the position buffer.
      gl.bindBuffer(gl.ARRAY_BUFFER, screenVertices);

      &#x2F;&#x2F; Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
      var size = 2;          &#x2F;&#x2F; 3 components per iteration
      var type = gl.FLOAT;   &#x2F;&#x2F; the data is 32bit floats
      var normalize = false; &#x2F;&#x2F; don&#x27;t positionize the data
      var stride = 0;        &#x2F;&#x2F; 0 = move forward size * sizeof(type) each iteration to get the next position
      var offset = 0;        &#x2F;&#x2F; start at the beginning of the buffer
      gl.vertexAttribPointer(
          position2dLocation, size, type, normalize, stride, offset);

      gl.uniform2f(screenResolutionLocation, gl.canvas.width, gl.canvas.height);
      gl.uniform1f(timeLocation, ((new Date()).getTime() - startTime)&#x2F;1000);

      &#x2F;&#x2F; Draw the geometry.
      var primitiveType = gl.TRIANGLES;
      var offset = 0;
      var count = 2 * 3;
      gl.drawArrays(primitiveType, offset, count);
    }
  }

  var m4 = {

    perspective: function(fieldOfViewInRadians, aspect, near, far) {
      var f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewInRadians);
      var rangeInv = 1.0 &#x2F; (near - far);

      return [
        f &#x2F; aspect, 0, 0, 0,
        0, f, 0, 0,
        0, 0, (near + far) * rangeInv, -1,
        0, 0, near * far * rangeInv * 2, 0
      ];
    },

    projection: function(width, height, depth) {
      &#x2F;&#x2F; Note: This matrix flips the Y axis so 0 is at the top.
      return [
         2 &#x2F; width, 0, 0, 0,
         0, -2 &#x2F; height, 0, 0,
         0, 0, 2 &#x2F; depth, 0,
        -1, 1, 0, 1,
      ];
    },

    multiply: function(a, b) {
      var a00 = a[0 * 4 + 0];
      var a01 = a[0 * 4 + 1];
      var a02 = a[0 * 4 + 2];
      var a03 = a[0 * 4 + 3];
      var a10 = a[1 * 4 + 0];
      var a11 = a[1 * 4 + 1];
      var a12 = a[1 * 4 + 2];
      var a13 = a[1 * 4 + 3];
      var a20 = a[2 * 4 + 0];
      var a21 = a[2 * 4 + 1];
      var a22 = a[2 * 4 + 2];
      var a23 = a[2 * 4 + 3];
      var a30 = a[3 * 4 + 0];
      var a31 = a[3 * 4 + 1];
      var a32 = a[3 * 4 + 2];
      var a33 = a[3 * 4 + 3];
      var b00 = b[0 * 4 + 0];
      var b01 = b[0 * 4 + 1];
      var b02 = b[0 * 4 + 2];
      var b03 = b[0 * 4 + 3];
      var b10 = b[1 * 4 + 0];
      var b11 = b[1 * 4 + 1];
      var b12 = b[1 * 4 + 2];
      var b13 = b[1 * 4 + 3];
      var b20 = b[2 * 4 + 0];
      var b21 = b[2 * 4 + 1];
      var b22 = b[2 * 4 + 2];
      var b23 = b[2 * 4 + 3];
      var b30 = b[3 * 4 + 0];
      var b31 = b[3 * 4 + 1];
      var b32 = b[3 * 4 + 2];
      var b33 = b[3 * 4 + 3];
      return [
        b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
        b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
        b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
        b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
        b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
        b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
        b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
        b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
        b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
        b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
        b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
        b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
        b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
        b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
        b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
        b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33,
      ];
    },

    translation: function(tx, ty, tz) {
      return [
         1,  0,  0,  0,
         0,  1,  0,  0,
         0,  0,  1,  0,
         tx, ty, tz, 1,
      ];
    },

    xRotation: function(angleInRadians) {
      var c = Math.cos(angleInRadians);
      var s = Math.sin(angleInRadians);

      return [
        1, 0, 0, 0,
        0, c, s, 0,
        0, -s, c, 0,
        0, 0, 0, 1,
      ];
    },

    yRotation: function(angleInRadians) {
      var c = Math.cos(angleInRadians);
      var s = Math.sin(angleInRadians);

      return [
        c, 0, -s, 0,
        0, 1, 0, 0,
        s, 0, c, 0,
        0, 0, 0, 1,
      ];
    },

    zRotation: function(angleInRadians) {
      var c = Math.cos(angleInRadians);
      var s = Math.sin(angleInRadians);

      return [
         c, s, 0, 0,
        -s, c, 0, 0,
         0, 0, 1, 0,
         0, 0, 0, 1,
      ];
    },

    scaling: function(sx, sy, sz) {
      return [
        sx, 0,  0,  0,
        0, sy,  0,  0,
        0,  0, sz,  0,
        0,  0,  0,  1,
      ];
    },

    translate: function(m, tx, ty, tz) {
      return m4.multiply(m, m4.translation(tx, ty, tz));
    },

    xRotate: function(m, angleInRadians) {
      return m4.multiply(m, m4.xRotation(angleInRadians));
    },

    yRotate: function(m, angleInRadians) {
      return m4.multiply(m, m4.yRotation(angleInRadians));
    },

    zRotate: function(m, angleInRadians) {
      return m4.multiply(m, m4.zRotation(angleInRadians));
    },

    scale: function(m, sx, sy, sz) {
      return m4.multiply(m, m4.scaling(sx, sy, sz));
    },

  };

  function rot(arr, n) {
    let myarr = arr.slice(0);
    for (var i = 0; i &lt; n; i++) {
      myarr.unshift(myarr.pop())
    }
    return myarr
  }

  function icosohedron() {
    const N = 30.0;
    const PHI = 1.618033988 * N;
    var a = []
    ;[1, -1].forEach((i2) =&gt; {
     ;[1, -1].forEach((i1) =&gt; {
       ;[0, 1, 2].forEach((r) =&gt; {
         a = a.concat(rot([0, -N,  PHI*i2], r))
         a = a.concat(rot([ 0,  N,  PHI*i2], r))
         a = a.concat(rot([PHI * i1, 0, N*i2], r))
         &#x2F;&#x2F; a = a.concat([0,0,0])
         &#x2F;&#x2F; a = a.concat([0,0,0])
         &#x2F;&#x2F; a = a.concat([0,0,0])
       })
     })
    })
    ;[1, -1].forEach((i3) =&gt; {
     ;[1, -1].forEach((i2) =&gt; {
       ;[1, -1].forEach((i1) =&gt; {
         a = a.concat([0,  N*i2,  PHI*i3])
         a = a.concat([N*i1, PHI*i2,  0])
         a = a.concat([PHI*i1,  0,  N*i3])
       })
     })
    })
    return a
  }

  &#x2F;&#x2F; Fill the buffer with the values that define a letter &#x27;F&#x27;.
  function setGeometry(gl) {
    gl.bufferData(
        gl.ARRAY_BUFFER,
        new Float32Array(icosohedron()),
        gl.STATIC_DRAW);
  }

  function setBarycentric(gl) {
    let a = icosohedron();
    let barys = [];
    for (var i = 0; i &lt; a.length; i+=9) {
      let bary = [
        0.,0.,
        1.,0.,
        0.,1.,
      ];
      barys.push(...bary);
    }
    gl.bufferData(
        gl.ARRAY_BUFFER,
        new Float32Array(barys),
        gl.STATIC_DRAW);
  }

  &#x2F;&#x2F; Fill the buffer with the values that define a letter &#x27;F&#x27;.
  function setNormals(gl) {
    let a = icosohedron();
    let normals = [];
    for (var i = 0; i &lt; a.length; i+=9) {
      let normal = [
        a[i+0] + a[i+3] + a[i+6],
        a[i+1] + a[i+4] + a[i+7],
        a[i+2] + a[i+5] + a[i+8],
      ];
      normals.push(...normal);
      normals.push(...normal);
      normals.push(...normal);
    }
    gl.bufferData(
        gl.ARRAY_BUFFER,
        new Float32Array(normals),
        gl.STATIC_DRAW);
  }
  &#x2F;&#x2F; Fill the buffer with colors for the &#x27;F&#x27;.
  function setColors(gl) {
    var a = []
    for (var i = 0; i &lt; 20; i++) {
      a = a.concat([
        &#x2F;&#x2F; face 1
        200, Math.random()*200, Math.random()*200,
        100, Math.random()*200, Math.random()*200,
        50, Math.random()*200, Math.random()*200,
      ]);
    }
    gl.bufferData(
        gl.ARRAY_BUFFER,
        new Uint8Array(a),
        gl.STATIC_DRAW);
  }

  main();
&lt;&#x2F;script&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Notes on Splicing CRDTs for Structured Hypertext</title>
    <published>2019-10-20T00:00:00+00:00</published>
    <updated>2019-10-20T00:00:00+00:00</updated>
    <link href="https://lord.io/splicing-crdts/" type="text/html"/>
    <id>https://lord.io/blog/2019/splicing-crdts/</id>
    <content type="html">&lt;p&gt;&amp;quot;Come back to Recurse Center!&amp;quot; they told me. &amp;quot;You&#x27;ll get to write all sorts of cool code!&amp;quot; they said. Well I just spent two weeks writing exactly zero lines of code. It&#x27;s a great feeling, seeing everyone around you create beautiful 3D graphical masterpieces or fully complete web applications while you spend twelve hours a day struggling to read technical papers that you don&#x27;t even understand. This is what happens when you attempt to do things with CRDTs.&lt;&#x2F;p&gt;
&lt;p&gt;CRDT stands for &amp;quot;conflict-free replicated data type&amp;quot;. Do not ask me why they aren&#x27;t called CFRDTs, that is just yet another ineffable mystery that you can add to the pile. A CRDT is kinda like a normal data structure, like a string or a map. However, unlike normal strings and maps, a CRDT is designed to be shared between multiple computers in a mesh network. Any computer can make changes to the CRDT locally, and the concurrent changes from multiple computers will be seamlessly merged together. This property makes CRDTs useful for building Google Docs-style collaborative editors! It also makes a simple-sounding operation like &amp;quot;insert character in string&amp;quot; require a ten page technical document to describe correctly! Alexei Baboulevitch&#x27;s &lt;a href=&quot;http:&#x2F;&#x2F;archagon.net&#x2F;blog&#x2F;2018&#x2F;03&#x2F;24&#x2F;data-laced-with-history&#x2F;&quot;&gt;fantastic blog post&lt;&#x2F;a&gt; on collaborative document editing is &lt;em&gt;20 thousand words long&lt;&#x2F;em&gt;. Four of these blog posts would be longer than the first Harry Potter novel. I hope he wrote the blog post using his own collaborative editor, since it would prove its performance for editing immense documents.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, the operation that have been attempting to implement is string splicing. If I have a string &lt;code&gt;foobar&lt;&#x2F;code&gt;, and I cut the &lt;code&gt;foo&lt;&#x2F;code&gt; out and paste it at the end, I get &lt;code&gt;barfoo&lt;&#x2F;code&gt;. That&#x27;s a splice. If there was only one user, this would be equivalent to just deleting the characters &lt;code&gt;foo&lt;&#x2F;code&gt; and reinserting them at a new location. However — since there are multiple users of this program, we&#x27;d like any concurrent changes inside of &lt;code&gt;foo&lt;&#x2F;code&gt; to be copied over to the new location as well. For instance, if I move &lt;code&gt;foo&lt;&#x2F;code&gt; to the end and you simultaneously replace &lt;code&gt;oo&lt;&#x2F;code&gt; with &lt;code&gt;aa&lt;&#x2F;code&gt;, we&#x27;d expect the result to be &lt;code&gt;barfaa&lt;&#x2F;code&gt;. All CRDTs that I&#x27;ve seen so far would instead merge those two edits into &lt;code&gt;aabarfoo&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t actually have a working splice operation yet, but these are my rough, in-progress notes on the problem and my thoughts so far.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;splicing-is-important-for-structured-hypertext&quot;&gt;Splicing is important for structured hypertext&lt;&#x2F;h2&gt;
&lt;p&gt;Considering the difficulty of implementing a new CRDT operation, you&#x27;re probably thinking: do we really need a splice? If we already have insertion and deletion operations for sequences, that gets us most of the way, right? In fact, there&#x27;s even a CRDT that allows a single node of a tree — so a character or a struct — to be moved to another place in the tree. So why bother adding splice?&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s look at todo lists. Everybody likes todo lists, right? It seems like every CRDT and UI framework under the sun implements one, so let&#x27;s try to implement our own. Here&#x27;s one from Dropbox Paper:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_1.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_1.png 2x&quot; alt=&quot;A todo list with two items, the cursor positioned halfway through the first item&quot;&gt;
&lt;p&gt;The CRDT schema I often see for this list looks somewhat like:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;    {checked: false, contents: &amp;quot;Hello World&amp;quot;},
&lt;&#x2F;span&gt;&lt;span&gt;    {checked: false, contents: &amp;quot;This is a todo item&amp;quot;},
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Assuming the contents strings in this schema are actually a CRDT sequence of characters, this should work great, right? Well looking back at the example above, what happens when we press return? In many text editors, we get an image that looks like this:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_2.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_2.png 2x&quot; alt=&quot;The same todo list as before, but the user has pressed return, splitting the first item in half to create a third item.&quot;&gt;
&lt;p&gt;If you&#x27;ve read the CRDT literature, you may recognize that this presents a problem for how we&#x27;ve set up our schema. We can individually delete the characters in &lt;code&gt;World&lt;&#x2F;code&gt; and put them in our newly created item, but if another user concurrently inserted &lt;code&gt;!&lt;&#x2F;code&gt; after &lt;code&gt;World&lt;&#x2F;code&gt;, the &lt;code&gt;!&lt;&#x2F;code&gt; would remain in the first item instead of correctly moving to the second.&lt;&#x2F;p&gt;
&lt;p&gt;One solution to this is to treat the entire document as a single sequence of characters and objects. For instance, our initial schema for this list could instead look like&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;&amp;quot;{inline object checkbox}Hello World\n{inline object checkbox}This is a todo item&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This certainly solves the return-problem, since we can just insert &lt;code&gt;\n{inline object checkbox}&lt;&#x2F;code&gt; when the user presses return. Our second user&#x27;s &lt;code&gt;!&lt;&#x2F;code&gt; will get inserted in the correct place. Problem solved? Well, we now have another issue. What do we do when users reorder items?&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_3.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_3.png 2x&quot; alt=&quot;The user is now dragging the second todo item to a different spot in the list&quot;&gt;
&lt;p&gt;As far as I can tell, the single continuous sequence is ~roughly what Dropbox Paper does (although I believe they use operational transform instead of CRDTs), since they tend to have sync errors when todo items are concurrently edited and moved around. In the above example, if one user inserts &lt;code&gt;!&lt;&#x2F;code&gt; at the end of &lt;code&gt;World&lt;&#x2F;code&gt; and another user moves &lt;code&gt;World&lt;&#x2F;code&gt; to a different spot in the list, there will be nothing associating the &lt;code&gt;!&lt;&#x2F;code&gt; with the &lt;code&gt;World&lt;&#x2F;code&gt;. In Dropbox Paper, this is what you get:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_4.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_4.png 2x&quot; alt=&quot;Two todo items. In between them is a bare paragraph reading &amp;quot;!this is a todo item&amp;quot;&quot;&gt;
&lt;p&gt;I never deleted any checkboxes, but by some gimmick of the synchronization, one of our checkboxes has disappeared. If your list allows both splitting a text object in half and reordering objects, neither of these two solutions will work well. However, if we had a &lt;em&gt;splice&lt;&#x2F;em&gt; operation that moved both existing characters as well as &lt;em&gt;future inserts&lt;&#x2F;em&gt; within the range, suddenly both work! In the continuous sequence case, we can splice todo items from one part of the list to another. And in the structured case, we can splice the second half of one todo item into the string for a newly created todo item.&lt;&#x2F;p&gt;
&lt;p&gt;Splicing CRDTs could also be effectively used to better merge cut&#x2F;paste operations with concurrent edits, and to track the original author of any particular character.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;prior-art&quot;&gt;Prior art&lt;&#x2F;h2&gt;
&lt;p&gt;Although I haven&#x27;t found any prior art that implements a splicing operation, there &lt;em&gt;are&lt;&#x2F;em&gt; multiple examples of trees that allow moving nodes around, which is at least a first step. We&#x27;ll look at two examples here.&lt;&#x2F;p&gt;
&lt;p&gt;Several months after Data Laced with History was written, in May 2018, some Cambridge researchers published a new CRDT called an &lt;a href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1805.04263&quot;&gt;OpSet&lt;&#x2F;a&gt;. This is the first CRDT that allows for node movement, where a single character or item in the tree can be moved to another spot in the tree. This isn&#x27;t quite the splice function we&#x27;re looking for, but it&#x27;s a great starting point. Let&#x27;s look at their implementation. The authors identify two major issues with moving a node:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;We must ensure the resulting structure is a tree, so we have to prevent cycles.&lt;&#x2F;li&gt;
&lt;li&gt;A node moved twice should not be duplicated in two locations.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The OpSet CRDT takes a very different approach to concurrency than Causal Trees. Rather than use an add-only tree of operations, OpSet keeps its operations as a list, ordered by logical timestamp. To get the current state of the system, the client takes an initial state and applies each operation to the state one by one. This operation list &lt;em&gt;isn&#x27;t&lt;&#x2F;em&gt; append only — an edit coming in from another client will often have a timestamp prior to the most recent local one. In this case, the client state must be &amp;quot;rewound&amp;quot; back to that point in the operation list, the new operation must be added and applied, and then subsequent operations must be replayed to get the final current state of the document.&lt;&#x2F;p&gt;
&lt;p&gt;This does seem somewhat slower than Causal Trees, but allows us to support more complex editing operations. Persistent data structures also makes this rewinding faster than you might think.&lt;&#x2F;p&gt;
&lt;p&gt;OpSet defines an &lt;code&gt;Assign&lt;&#x2F;code&gt; operation to move nodes, which takes a number of arguments:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;&#x2F;code&gt;: the node ID of a parent map or list&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;obj&lt;&#x2F;code&gt;: the ID of the node being moved&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;key&lt;&#x2F;code&gt;: for maps, this is the map key, some literal value; for lists, this is the ID of the node immediately prior to the insertion point, or in the case where the insert is at the beginning of the list, the node ID of the list itself repeated&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;val&lt;&#x2F;code&gt;: the IDs of the previous values assigned to that key, which are deleted&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So how does this prevent our two issues?&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;To prevent cycles, any time the Assign operation would create a cycle, it instead becomes a no-op. This isn&#x27;t a commutative operation, but it works because OpSets linearizes the operations, so they don&#x27;t need to commute with each other. If we were using a Causal Tree, our operations would be applied in arbitrary order, and we wouldn&#x27;t be able to do this.&lt;&#x2F;li&gt;
&lt;li&gt;To prevent duplication, any time the Assign operation moves a node twice, the last Assign operation wins.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;My friend Kyle also sent me a &lt;a href=&quot;https:&#x2F;&#x2F;www.figma.com&#x2F;blog&#x2F;how-figmas-multiplayer-technology-works&#x2F;#the-details-of-figma-s-multiplayer-system&quot;&gt;recent blog post from Figma&lt;&#x2F;a&gt; that explains how their CRDTs resolve the cycle problem. Figma also linearizes edits according to timestamps, but their approach has a central server that determines the timestamp of each operation. They also use this central server to resolve cycles:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Figma’s solution is to temporarily parent these objects to each other and remove them from the tree until the server rejects the client’s change and the object is reparented where it belongs. This solution isn’t great because the object temporarily disappears, but it’s a simple solution to a very rare temporary problem so we didn’t feel the need to try something more complicated here such as breaking these temporary cycles on the client.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I&#x27;ve been exploring more down the SpliceOp path, since I&#x27;d optimally like the resulting CRDTs to work in the absence of a central server, but it&#x27;s perhaps an approach worth looking into, especially considering how many people use Figma&#x27;s CRDTs every day. They also have some interesting notes on undo&#x2F;redo, a topic I still have to research further.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;splicing-is-harder-than-node-reparenting&quot;&gt;Splicing is harder than node reparenting&lt;&#x2F;h2&gt;
&lt;p&gt;Splicing presumably would be a valid operation on a JSON array as well as a string. This means all the node reparenting issues are issues for splicing as well: we have to prevent duplication and prevent cycles of parents. There are also some unique issues with  splicing:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;How are the ends of the splice operation specified? by character ID?&lt;&#x2F;li&gt;
&lt;li&gt;How are concurrent edits in that range moved to the new location?&lt;&#x2F;li&gt;
&lt;li&gt;How do we resolve overlapping splices? What about nested splices?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Let&#x27;s first look at the actual schema of a splice operation, and how the start and end of the range are specified. Initially, I thought we could just keep character IDs consistent across moves, and then specify splices in terms of a starting character ID and an ending character ID. This approach unfortunately has bad repercussions! Let&#x27;s look at two simultaneous edits on the string &#x27;&amp;quot;hi mom 1234&amp;quot;&#x27;.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_5.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_5.png 2x&quot; alt=&quot;a list of characters reading &amp;quot;hi mom 1234&amp;quot;&quot;&gt;
&lt;p&gt;User A splices &lt;code&gt;12&lt;&#x2F;code&gt; to the beginning of the string.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_6.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_6.png 2x&quot; alt=&quot;a modified list of characters: &amp;quot;12hi mom 34&amp;quot;&quot;&gt;
&lt;p&gt;Concurrently, user B splices &lt;code&gt;23&lt;&#x2F;code&gt; to the end of the string.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_7.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_7.png 2x&quot; alt=&quot;a modified list of characters: &amp;quot;hi mom 1423&amp;quot;&quot;&gt;
&lt;p&gt;Let&#x27;s say OpSet&#x27;s timestamp resolution algorithm determines that user A&#x27;s edit occurs after user B&#x27;s. This means we apply the second edit to the output of the first, which results in this definitely &lt;em&gt;very&lt;&#x2F;em&gt; wrong edit:&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_8.png&quot; srcset=&quot;&#x2F;images&#x2F;2019&#x2F;splicing_8.png 2x&quot; alt=&quot;a modified list of characters: &amp;quot;142hi mom 3&amp;quot;&quot;&gt;
&lt;p&gt;Thanks to OpSet&#x27;s operation linearization, this is technically a &amp;quot;correct&amp;quot; CRDT from a mathematical standpoint, since all sites will eventually converge onto the same state. That said, it&#x27;s &lt;em&gt;definitely&lt;&#x2F;em&gt; not preserving the user&#x27;s intent, and would result in some very, very wacky splices, since the endpoints of splices can move around through other splices. Instead, we&#x27;d like to specify a splice operation that &lt;em&gt;doesn&#x27;t&lt;&#x2F;em&gt; move with respect to other splices. If our splice operation assigned new IDs to the characters it moves, we could leave the source range as tombstones for future splice operations. But this is tricky! What IDs do we specify for the new characters? A splice doesn&#x27;t have a complete list of characters in its range when it&#x27;s created, since concurrent inserts could put more characters in that range. Perhaps hashing the old character ID with the ID of the splice could work?&lt;&#x2F;p&gt;
&lt;p&gt;Even with IDs for splicing that don&#x27;t move around, there are still issues. If a character was deleted on one site, and then concurrently spliced twice on another site, with the second splice referencing it as a endpoint, we&#x27;d like that second splice to be able to use it as a endpoint in its &lt;em&gt;new&lt;&#x2F;em&gt; location, even though it was deleted in the original location. I think this may be resolved by having splices copy&#x2F;hash even the &lt;em&gt;tombstones&lt;&#x2F;em&gt; in a range. However, this does result in worst case exponential growth of tombstones, which is obviously undesirable, especially in distributed contexts where garbage collection of tombstones is a tricky problem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;future-work&quot;&gt;Future Work&lt;&#x2F;h2&gt;
&lt;p&gt;Are splicing CRDTs possible? I&#x27;m still not 100% sure. I&#x27;m sure my sketch of an idea still has many issues beyond the exponential memory growth problem I mentioned above. Considering how useful a splicing CRDT would be, I still think this is a high value problem even after wading through several weeks of reading paper after paper. The OpSet paper that solved the node reparenting problem was only written in 2018, so clearly this is a field with plenty left to discover!&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m starting work on an open-source implementation of the OpSets paper &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;crudite&quot;&gt;in Rust&lt;&#x2F;a&gt; so that I have some base code to explore splicing CRDTs with. If I manage to make any progress, I&#x27;ll post another update.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>A Plotter Quine</title>
    <published>2019-09-26T00:00:00+00:00</published>
    <updated>2019-09-26T00:00:00+00:00</updated>
    <link href="https://lord.io/plotter-quine/" type="text/html"/>
    <id>https://lord.io/blog/2019/plotter-quine/</id>
    <content type="html">&lt;p&gt;Recurse Center has this fantastic HP7440A plotter from the eighties.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;plotter-quine-1.gif&quot; alt=&quot;a gif of the plotter drawing some letters&quot;&gt;
&lt;p&gt;Using only a few simple commands — select pen, pen up, pen down, and move to position — we can draw very precise shapes with a pen. Yesterday, I wrote a utility in Rust that converts a font file and some text into plotter instructions.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;plotter-quine-2.jpg&quot; alt=&quot;A plotted printing that reads &#x27;hello world&#x27;&quot;&gt;
&lt;p&gt;Once I had that code linted, reviewed, and nicely formatted, I immediately inlined all functions, renamed most variables to be single letters, and removed all those pesky newlines. Forget about readability, we&#x27;re making a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Quine_(computing)&quot;&gt;quine&lt;&#x2F;a&gt;, a program that prints its own source code. The plotter could legibly render ~3000 characters on a page using Inconsolata, but since most quines list their source code twice (once for execution, once as a string) we needed to get the source code &lt;em&gt;without&lt;&#x2F;em&gt; the quine string to be under ~1500 characters to fit on the page.&lt;&#x2F;p&gt;
&lt;img src=&quot;&#x2F;images&#x2F;2019&#x2F;plotter-quine-3.jpg&quot; alt=&quot;The source code of the quine, printed by a plotter on an 8.5x11 sheet of paper and hung on a wall&quot;&gt;
&lt;p&gt;The plotter driver terrifyingly crashed twice during printing, but after a few restarts, it managed to complete in two and a half hours.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;technicalities&quot;&gt;Technicalities&lt;&#x2F;h2&gt;
&lt;p&gt;This isn&#x27;t &lt;em&gt;quite&lt;&#x2F;em&gt; a proper quine, since the Rust executable outputs plotter code, not Rust. We have to run the resulting plotter code to produce the original Rust code. Wikipedia would classify this program as &amp;quot;quine-relay&amp;quot; or an &amp;quot;ouroboros program&amp;quot;.&lt;&#x2F;p&gt;
&lt;p&gt;A proper quine also can&#x27;t load files, but in our case, we load a font file and the &lt;code&gt;rusttype&lt;&#x2F;code&gt; library. That said, we don&#x27;t cheat by loading our &lt;code&gt;main.rs&lt;&#x2F;code&gt; from the filesystem! As mentioned above, the code is replicated twice in the quine, once as a string and once as proper code.&lt;&#x2F;p&gt;
&lt;p&gt;If you ever write your own quine in Rust, be sure to take a look at the &lt;code&gt;format!&lt;&#x2F;code&gt; macro — the &lt;code&gt;{:?}&lt;&#x2F;code&gt; debug representation of a string is conveniently a valid Rust string literal, so you don&#x27;t need to worry about inserting escape characters yourself.&lt;&#x2F;p&gt;
&lt;p&gt;The source code for this quine is &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;plotter-quine&quot;&gt;available on GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>The $15 Sous-Vide Cooker</title>
    <published>2016-12-16T00:00:00+00:00</published>
    <updated>2016-12-16T00:00:00+00:00</updated>
    <link href="https://lord.io/sous-vide/" type="text/html"/>
    <id>https://lord.io/blog/2016/sous-vide/</id>
    <content type="html">&lt;p&gt;Sous-vide cooking is a lot of fun. Food is vacuum sealed and cooked for many hours in a water bath at a specific temperature, usually something like 140°F, far below boiling. Meat becomes really juicy, eggs become creamy, and you can do all sorts of fun precision cooking. However, cookers on Amazon cost $100–200, which if you ask me, is a scam. I&#x27;ve also seen instructions online for Arduino-based cookers that use a relay to control a crock pot, but even those often cost something like $40 &lt;em&gt;plus&lt;&#x2F;em&gt; the cost of a crock pot, and my housemate Adam and I were not about to ruin our co-op&#x27;s only crock pot for some crazy cooking project.&lt;&#x2F;p&gt;
&lt;p&gt;With no cheaper system than a crock pot, I was ready to give up. That is, until I stumbled upon what is now my second-favorite item for sale on Amazon.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2016&#x2F;amazonscreengrab.png&quot; alt=&quot;screenshot of bucket heater on amazon&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s right. If we just sacrifice $8 (plus any concerns we may have about so-called &amp;quot;food safety&amp;quot; and &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;review&#x2F;R3FM5RT2CKG4ZP&#x2F;ref=cm_cr_dp_title?ie=UTF8&amp;amp;ASIN=B00PFZFK78&amp;amp;channel=detail-glance&amp;amp;nodeID=228013&amp;amp;store=hi&quot;&gt;&amp;quot;shock hazards&amp;quot;&lt;&#x2F;a&gt;) we can pump 1000 watts of heat into a old plastic bucket filled with water, more than enough to boil it. Add in a cheap Arduino, a relay, and a $2 one-wire digital temperature sensor, and we&#x27;ve got ourselves a sous-vide machine fit for a king!&lt;&#x2F;p&gt;
&lt;p&gt;(This is a pretty simple, fun, and rewarding project! However, it does use 120V wall power, and I am not to blame if you electrocute or poison yourself.)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;&#x2F;h2&gt;
&lt;p&gt;These are the parts we used:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;Portable-Water-Heater-Aluminum-Watts&#x2F;dp&#x2F;B00PFZFK78&#x2F;&quot;&gt;1000W bucket heater&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.alibaba.com&#x2F;products&#x2F;F0&#x2F;ds18b20_waterproof.html&quot;&gt;DS18B20 waterproof temperature sensor&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;a 4.7k resister, required by the temperature sensor&lt;&#x2F;li&gt;
&lt;li&gt;an Arduino&lt;&#x2F;li&gt;
&lt;li&gt;a relay board — we used &lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;JBtek-Channel-Module-Arduino-Raspberry&#x2F;dp&#x2F;B00KTEN3TM&#x2F;&quot;&gt;a multi-channel one&lt;&#x2F;a&gt; since we also control a bread proofing box with this same setup, but you could use any old cheap relay board.&lt;&#x2F;li&gt;
&lt;li&gt;old 3-prong wall plug, any unused wire will do&lt;&#x2F;li&gt;
&lt;li&gt;a used plastic bucket found in the dumpster behind the dining hall&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can see our electronics setup here (the bucket and the heater are on the shelf below):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2016&#x2F;sousvide1.jpg&quot; alt=&quot;photograph of our sous-vide cooker&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As you can see, we take clean and efficient wiring very seriously. Anyways, we just stuck the resistor between the power and data lines of the temperature sensor, plugged the power, ground, and data into the 5V, ground, and some random input pin (&lt;code&gt;ONE_WIRE_BUS&lt;&#x2F;code&gt; in our code) in our Arduino. We also cut and strip the ends of both the old 3-prong wire and the bucket heater, so we had a bucket heater with no plug, and a wall plug that just led to exposed wires. One of the wall plug&#x27;s wires connected to one of the bucket heater&#x27;s wires, and the other pair went through the relay, so the relay controls power to the heater. Finally, we connect the relay control to some random output pin of the Arduino, &lt;code&gt;HEATER_PIN&lt;&#x2F;code&gt; in our code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-code&quot;&gt;The Code&lt;&#x2F;h2&gt;
&lt;p&gt;This is pretty doable, even if you&#x27;ve never written much Arduino code before. We start by including and initializing the OneWire and DallasTemperature libraries, which need to be installed on your computer from the install library menu option in the Arduino software.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;lt;OneWire.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;#include &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;lt;DallasTemperature.h&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;#define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#73d0ff;&quot;&gt;ONE_WIRE_BUS &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;3
&lt;&#x2F;span&gt;&lt;span&gt;OneWire &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;oneWire&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;ONE_WIRE_BUS&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;DallasTemperature &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;tempSensor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;oneWire&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; HEATER_PIN &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, in our &lt;code&gt;setup&lt;&#x2F;code&gt; function, we start a serial line used for debugging, start the temperature sensor, set the cooker pin to be in output mode, and turn it off by default.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;setup&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  Serial&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;begin&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;9600&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  tempSensor&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;begin&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;pinMode&lt;&#x2F;span&gt;&lt;span&gt;(HEATER_PIN&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; OUTPUT)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;digitalWrite&lt;&#x2F;span&gt;&lt;span&gt;(HEATER_PIN&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; LOW)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, we choose the temperature for our cooker. We are too cheap and lazy to make a LED display&#x2F;temperature dial, so we recompile the code every time we need to change the temperature. This sounds like a hassle, but on the other hand, it feels like I&#x27;m hacking into some industrial control system every time I want to cook eggs, so I consider this a positive feature.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#5c6773;&quot;&gt;&#x2F;&#x2F; cooker turns on when below low temp
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; and turns off when above high temp
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; this prevents it flipping back and
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; forth too rapidly
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; garlic stuff
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; cookerLow &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;88&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;float&lt;&#x2F;span&gt;&lt;span&gt; cookerHigh &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;88&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; best eggs
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; float cookerLow = 62.5; &#x2F;&#x2F; 144.5 F
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; float cookerHigh = 62.8; &#x2F;&#x2F; 145.0 F
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; see http:&#x2F;&#x2F;www.seriouseats.com&#x2F;2013&#x2F;10&#x2F;sous-vide-101-all-about-eggs.html
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This also means your favorite recipes&#x27; temperatures are tracked as C comments in version control. Even so-called &amp;quot;professional&amp;quot; Sous-Vide cookers often don&#x27;t have Git support, which is just another reason our machine is better.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, every two seconds, we check the temperature, and adjust whether the bucket heater is on accordingly.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-c &quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;loop&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:#5c6773;&quot;&gt;&#x2F;&#x2F; Wait a few seconds between measurements.
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;delay&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2000&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  Serial&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;Updating liquid temperature sensor...&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  tempSensor&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;requestTemperatures&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;int&lt;&#x2F;span&gt;&lt;span&gt; t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; tempSensor&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;getTempCByIndex&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  Serial&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(t)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  Serial&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;print&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#95e6cb;&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span&gt;(t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; cookerLow) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; depending on how you connected your relay, you may need
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; to swap HIGH and LOW on this pin.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;digitalWrite&lt;&#x2F;span&gt;&lt;span&gt;(HEATER_PIN&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; HIGH)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  } &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span&gt;(t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; cookerHigh) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;digitalWrite&lt;&#x2F;span&gt;&lt;span&gt;(HEATER_PIN&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; LOW)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&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;h2 id=&quot;things-to-cook&quot;&gt;Things to Cook&lt;&#x2F;h2&gt;
&lt;p&gt;We had a lot of fun cooking eggs. Our favorite was &lt;a href=&quot;http:&#x2F;&#x2F;www.seriouseats.com&#x2F;2013&#x2F;10&#x2F;sous-vide-101-all-about-eggs.html&quot;&gt;at 145°F&lt;&#x2F;a&gt; for 1.25 hours, since the whites were very, very soft but not fully liquid, and the yolk was the consistency of butter. You can cook many eggs all at once in the bucket, which is convenient for a large house like ours; one night for a big party, we cooked 3 or 4 dozen.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2016&#x2F;sousvide2.jpg&quot; alt=&quot;photograph of our sous-vide cooker&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Of course, the main thing that people cook is fish and meat. We also cooked some good garlic confit, although watch out — we ran it overnight, and although the water is not boiling, it steams. The water level dropped below the temperature sensor, which made it activate the bucket heater continuously, which boiled the water away. That&#x27;s probably a fire hazard or something?&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Quadcopter Motor Control with a Raspberry Pi</title>
    <published>2016-04-02T00:00:00+00:00</published>
    <updated>2016-04-02T00:00:00+00:00</updated>
    <link href="https://lord.io/quadcopter-motors/" type="text/html"/>
    <id>https://lord.io/blog/2016/quadcopter-motors/</id>
    <content type="html">&lt;p&gt;Most quadcopters are powered by &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Brushless_DC_electric_motor&quot;&gt;brushless motors&lt;&#x2F;a&gt;. These have major advantages over &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Brushed_DC_electric_motor&quot;&gt;brushed motors&lt;&#x2F;a&gt;: less friction, less noise, and no brushes that need replacement. However, these advantages come at a cost — while brushed motors can be powered by a simple direct current, brushless motors require some sort of complicated, changing AC current. No idea how that works. Fortunately for us, we can just use an electronic speed controller. An ESC accepts a DC voltage, and takes care of running a brushless motor.&lt;&#x2F;p&gt;
&lt;p&gt;ESCs have a signal line to control their speed. It accepts a square wave running up to ~300hz. The speed is controlled with &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Pulse-width_modulation&quot;&gt;pulse-width modulation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2016&#x2F;pwm_graph.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the graph on the left, the power is on for 18% of the cycle, whereas the graph on the right has the power on for 30% of the cycle. This is how the speed is controlled — the frequency of cycles never changes, just the width of the powered pulses within each cycle. If the powered pulses are around ~1ms long, the motor will be off. At ~2ms, it&#x27;ll be at max power. At ~1.5ms, it&#x27;ll be at 50%.&lt;&#x2F;p&gt;
&lt;p&gt;Since this is a binary signal, we could theoretically generate this with our Raspberry Pi&#x27;s GPIO pins. However, the timing of this pulse width needs to be incredibly accurate. Our program running on the Pi could freeze for a moment while the processor switches to the operating system, or depending on our programming language, it could get stuck garbage collecting for a split second. When being a millisecond off is the difference between no power and full power, we need something else than just the Pi to do timing.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve seen guides online that use Arduinos attached to Pis to control motors. This probably works, but having to write and debug code for a second microcontroller seems like a lot of work. Instead, &lt;a href=&quot;http:&#x2F;&#x2F;distantorion.com&#x2F;2014&#x2F;10&#x2F;24&#x2F;motor-control&#x2F;&quot;&gt;distantorion&lt;&#x2F;a&gt; has a post on using a &lt;a href=&quot;https:&#x2F;&#x2F;www.adafruit.com&#x2F;product&#x2F;815&quot;&gt;PCA9685&lt;&#x2F;a&gt; to generate the control signal, but their post is missing large chunks of code. Adafruit has another &lt;a href=&quot;https:&#x2F;&#x2F;learn.adafruit.com&#x2F;downloads&#x2F;pdf&#x2F;adafruit-16-channel-servo-driver-with-raspberry-pi.pdf&quot;&gt;useful post&lt;&#x2F;a&gt; on using the PCA9685, but for servo motors, not ESCs. I&#x27;m building autonomous drones with my friend &lt;a href=&quot;http:&#x2F;&#x2F;blog.adamcanady.com&#x2F;&quot;&gt;Adam&lt;&#x2F;a&gt;, and we merged these two sources together to write this article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-hardware&quot;&gt;The Hardware&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A Raspberry Pi 2&lt;&#x2F;strong&gt; — we &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;wheatco&#x2F;copter&#x2F;blob&#x2F;8745b5467a95695e7f8d80e8e6609ea938debe04&#x2F;README.md&quot;&gt;compile Rust&lt;&#x2F;a&gt; programs on the Pi, and it&#x27;s way faster&#x2F;easier with ARMv7 and a quad core processor.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;PCA9685&lt;&#x2F;strong&gt; — Adam and I got one from &lt;a href=&quot;https:&#x2F;&#x2F;www.adafruit.com&#x2F;product&#x2F;815&quot;&gt;Adafruit&lt;&#x2F;a&gt;. Apparently these were originally for LEDs, since LED brightness is also controlled by pulse wave modulation.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Electronic Speed Controller&lt;&#x2F;strong&gt; — we have a Hobbywing Skywalker, but apparently these somehow all have the same control interface, despite a lack of reasonable documentation online.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Brushless Motor&lt;&#x2F;strong&gt; — we have a A2212 1000KV&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I&#x27;m not going to explain how everything should hook up, but just connect voltages, grounds, SDAs, and SCLs, and you should be good to go. Also, remember that the ESCs should be powered separately from the Pi.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re wondering about SDA and SCL — they&#x27;re part of a system called I2C, which lets you chain together a bunch of different devices to the same SDA (data) and SCL (clock) lines, and talk to all of them, one at a time, with a microcontroller. I haven&#x27;t read the whole documentation, but roughly, every device has an device address and a number of byte registers. If you have the address of a device and the address of a register on that device, you can read and write that register&#x27;s byte. Depending on the device, a register might be any number of things, like a mode flag, or a setting, or a read-only sensor reading.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-code&quot;&gt;The Code&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ll start out by simply importing the i2cdev crate (you&#x27;ll need to add it to your Cargo.toml file), and &lt;code&gt;use&lt;&#x2F;code&gt;ing some things we&#x27;ll need later. We&#x27;ll also add all the constants that I stole from the Adafruit code.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;extern crate&lt;&#x2F;span&gt;&lt;span&gt; i2cdev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;i2cdev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;core&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;I2CDevice&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; needed for trait functions
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;i2cdev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;linux&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;LinuxI2CDevice&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;thread&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; addresses
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;MODE1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x00&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;MODE2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x01&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_ON_L&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x06&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_ON_H &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x07&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_OFF_L&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x08&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_OFF_H&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x09&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; Bits
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;RESTART&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x80&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;SLEEP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;ALLCALL&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x01&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;OUTDRV&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x04&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;TARGET_ADDR&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x40&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We&#x27;ll create a new I2C device, and wait a bit for a connection before sending it any messages.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&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:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; device &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;LinuxI2CDevice&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&#x2F;dev&#x2F;i2c-1&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;TARGET_ADDR&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    thread&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;sleep_ms(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The PCA 9685 needs some modes to be set before it can be used. I took these values again, all from the Adafruit code.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; reset PCA9685
&lt;&#x2F;span&gt;&lt;span&gt;    setPWM(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_write_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;MODE2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;OUTDRV&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_write_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;MODE1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;ALLCALL&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    thread&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;sleep_ms(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; wait for oscillator
&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:#5c6773;&quot;&gt;&#x2F;&#x2F; turn off sleep mode
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; mode1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_read_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;MODE1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp; !&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;SLEEP&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_write_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;MODE1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; mode1)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    thread&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;sleep_ms(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; wait for oscillator
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this next chunk of code, we&#x27;ll use &lt;code&gt;setPWM&lt;&#x2F;code&gt;. We&#x27;ll define it later, but it accepts the I2C address of the PCA9685, a motor number (the PCA9685 can control up to 16 motors), and two values that tell it when in the cycle to turn on and off. These values are between 0 and 4096. You can change exactly how long a cycle of 4096 ticks takes by setting the &#x27;prescale&#x27; value (see the Adafruit link for more info on that), but the default value of ~200hz should work fine for an ESC. A tick frequency of 200hz means each tick is 5ms. If we set the output to be powered for 1610 ticks, we&#x27;ll get a &lt;code&gt;(1610&#x2F;4096)*5ms = ~2ms&lt;&#x2F;code&gt;. Likewise, 810 ticks is &lt;code&gt;(810&#x2F;4096)*5ms = ~1ms&lt;&#x2F;code&gt;. If you remember from way above, these are the approximate minimum and maximum values for controlling the speed of our ESC! In the code below, we&#x27;ll start the power at tick 0, and stop it at either tick 810, tick 1610, or somewhere in between.&lt;&#x2F;p&gt;
&lt;p&gt;We still need to calibrate the ESC, so it knows the &lt;em&gt;exact&lt;&#x2F;em&gt; maximum and minimum widths of the pulse wave. Calibration works like this, according to distantorion:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Unplug the ESC, remove any propellers that may be attached to your motor, and make sure the motor is attached to something. &lt;em&gt;This is important&lt;&#x2F;em&gt; so your motor doesn&#x27;t fly up and cut you. distantorion describes this as a &lt;strong&gt;death machine&lt;&#x2F;strong&gt; that can cut flesh. Be careful.&lt;&#x2F;li&gt;
&lt;li&gt;Send the max pulse wave of 2ms (1610 ticks) to the ESC.&lt;&#x2F;li&gt;
&lt;li&gt;Plug in the ESC. It will beep thrice.&lt;&#x2F;li&gt;
&lt;li&gt;Wait more than 2 seconds, but less than 5.&lt;&#x2F;li&gt;
&lt;li&gt;Switch the pulse wave to the minimum, 1ms (810 ticks).&lt;&#x2F;li&gt;
&lt;li&gt;Wait a bit, and the ESC will do a long beep. You&#x27;re done!&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ESCs remember their calibration, even when unplugged. If you start an ESC with a signal pulse wave around the minimum of 1ms, it will use the previous calibration settings, and skip all the steps above.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, let&#x27;s actually write the calibration code.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; UNPLUG THE ESCS AND REMOVE PROPS BEFORE RUNNING THIS
&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:#5c6773;&quot;&gt;&#x2F;&#x2F; set max value and then wait for battery to be connected
&lt;&#x2F;span&gt;&lt;span&gt;    setPWM(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;1610&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;Get ready to plug in the battery...&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    thread&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;sleep_ms(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2000&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; give the user 2 seconds to get ready
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;Now!&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    thread&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;sleep_ms(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;3000&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; wait 3 seconds after beep to drop pulse length
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    setPWM(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;800&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    thread&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;sleep_ms(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;5000&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; wait 5 seconds and then try powering the motor
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    setPWM(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; device&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;1200&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; this is ~50% power
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All that&#x27;s left is the &lt;code&gt;setPWM&lt;&#x2F;code&gt; function. The PCA9685 has four I2C registers for each of its 16 motor outputs, which is a total of 64 motor control registers. They&#x27;re one right after another, so Motor 2&#x27;s registers are exactly &lt;code&gt;2*4&lt;&#x2F;code&gt; bytes after Motor 0&#x27;s registers. Since both the &lt;code&gt;on&lt;&#x2F;code&gt; tick and the &lt;code&gt;off&lt;&#x2F;code&gt; tick go up to 4096, they&#x27;re each represented by two byte-long registers. The code below does some bitwise manipulation to get the upper byte and the lower byte of each number before sending it off down the I2C bus to the PCA9685.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;setPWM&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;dev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; LinuxI2CDevice, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;chan&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;on&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;off&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    dev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_write_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_ON_L&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;chan&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span&gt;(on &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xFF&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    dev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_write_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_ON_H&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;chan&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span&gt;(on &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    dev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_write_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_OFF_L&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;chan&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span&gt;(off &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xFF&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    dev&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;smbus_write_byte_data&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;LED0_OFF_H&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;chan&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span&gt;(off &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Tips for New Open Source Maintainers</title>
    <published>2014-10-25T00:00:00+00:00</published>
    <updated>2014-10-25T00:00:00+00:00</updated>
    <link href="https://lord.io/oss-tips/" type="text/html"/>
    <id>https://lord.io/blog/2014/oss-tips/</id>
    <content type="html">&lt;p&gt;This November is the one year anniversary of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tripit&#x2F;slate&quot;&gt;Slate&lt;&#x2F;a&gt;, the small open source project I’ve been maintaining. It started off as a sort of toy project from my internship at TripIt, but now that &lt;a href=&quot;http:&#x2F;&#x2F;docs.travis-ci.com&#x2F;api&#x2F;&quot;&gt;real companies&lt;&#x2F;a&gt; use it, I feel an obligation to keep it mostly bug-free. I hadn’t done much open source before, so this year has been a great learning experience for me! That said, there are a couple things I wish someone had told me a year ago.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;know-your-project-s-scope&quot;&gt;Know Your Project’s Scope&lt;&#x2F;h2&gt;
&lt;p&gt;The first feature request I got for Slate was a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tripit&#x2F;slate&#x2F;issues&#x2F;1&quot;&gt;request to add AsciiDoc support&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;slate-should-support-asciidoc.png&quot; alt=&quot;Screenshot of Github issue reading “Slate should support AsciiDoc”&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I fumbled it. I didn’t put in the effort to come up with a complete solution. Instead of a half-assed solution, I wish I had said “I don’t have time for this right now, but I’ll add it to the long term nice-to-have list.” A couple people have requested AsciiDoc support, but there are many more who are perfectly fine with Markdown. People who don’t need a feature don’t speak up about it.&lt;&#x2F;p&gt;
&lt;p&gt;Don’t be afraid to ignore feature suggestions and reject pull requests! I tried to please everyone when I started out, adding whatever people wanted, but I’ve found that features aren’t always appropriate. I think these are all good reasons to close a feature or pull request:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The problem is in one of your project’s dependencies.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#0&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The project would not significantly benefit from having the feature, and adding it would increase the complexity of the code, or add edge-cases.&lt;&#x2F;li&gt;
&lt;li&gt;The feature would be better as a plugin or extension of the project.&lt;&#x2F;li&gt;
&lt;li&gt;The pull request complicates things, or has major problems with how it’s written.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;You don’t have time or energy to implement it properly, and want to leave it as an open task for someone else to do. (In this case, I leave the issue open, perhaps with a “help-wanted” label.)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;As the creator of your project, you’re the expert. That doesn’t mean to &lt;em&gt;ignore&lt;&#x2F;em&gt; suggestions…it just means to think carefully about what should be in your project, and what shouldn’t.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;communicate&quot;&gt;Communicate&lt;&#x2F;h2&gt;
&lt;p&gt;Keeping promises is difficult, especially when I’m trying to please bug reporters. I’ve been guilty of the “I’ll fix it this weekend” lie before.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;this-weekend.png&quot; alt=&quot;Screenshot of a Github message by @lord reading “I’ll try to get to this today or tomorrow”&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ve seen some projects where the maintainer is going to “get to it this weekend” for about six months. It’s something I’m still working on — over-promising is pretty frustrating for others.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t think I do this quite as much (or at least I try not to), but another annoyance for contributors is maintainers who don’t reply. I’ve submitted PRs for a number of projects, only to have them ignored for months and months. In my own projects, I try to at least acknowledge contributions as they come in, even to say “I’ll take a look at this when I have the chance, but I’m pretty busy.” If I no longer want to maintain a project, I’ll make it pretty clear in the &lt;code&gt;readme&lt;&#x2F;code&gt; that the project is unmaintained, so that contributors don’t expect a reply.&lt;&#x2F;p&gt;
&lt;p&gt;Another great way to help your contributors is to write a contributor’s guide. I didn’t actually know this until recently, but Github is nice enough to feature a link to your &lt;code&gt;contributing.md&lt;&#x2F;code&gt; prominently on the PR and issue creation pages. I’ve found that maybe ~80% of the people submitting pull requests for Slate actually read and follow the instructions, which is pretty good! In mine, I usually add a note that PRs should be pointed at the &lt;code&gt;dev&lt;&#x2F;code&gt; branch, and if you’re building out a big new feature, maybe to make an issue first to make sure we agree that the feature is in the scope of the project. It’s also a good place to list browser compatibility requirements.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;contribution-guidelines.png&quot; alt=&quot;Screenshot of Github contribution message&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally — be kind! Contributing to open source can be really scary, especially for people who haven’t done so before. A year ago, I was definitely scared to contribute myself. I was afraid of rejection. This is a real fear, but I think it can be reduced by maintainers who work with contributors to improve their code wherever possible, and thoroughly explain their decisions when they have to reject.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;grow-slowly&quot;&gt;Grow Slowly&lt;&#x2F;h2&gt;
&lt;p&gt;Large changes that take a long time to write are easy to burn out on, since you don’t have the satisfaction of completion every couple of weeks. This is especially true in a branch, because others will be submitting patches to &lt;code&gt;master&lt;&#x2F;code&gt;. Even if you conjure up the energy to finish your big new thing, merging will be…blegh. I try to build my projects incrementally whenever possible, and it’s been relatively successful so far.&lt;&#x2F;p&gt;
&lt;p&gt;As an aside, I’ve noticed this is similar to how many Github projects grow. Nobody really told me this, but I’ve noticed Github projects don’t gain all their popularity all at once. Slate has continued to gain usage at a relatively consistent rate over its life, as have some of my other projects. Repos aren’t like tweets or blog posts that receive all their traffic in a big burst.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-summary&quot;&gt;In Summary&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;Know Your Scope — feel free to reject pull requests and features if they don’t fit in with your project.&lt;&#x2F;li&gt;
&lt;li&gt;Be Kind to Your Community — don’t over promise, acknowledge issues promptly, consider having a &lt;code&gt;contributing.md&lt;&#x2F;code&gt;, and be kind!&lt;&#x2F;li&gt;
&lt;li&gt;Grow Slowly — build features incrementally, and remember that Github projects grow gradually.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;These tips represent my subjective opinion from just a year of maintaining one project, and I &lt;em&gt;definitely&lt;&#x2F;em&gt; still have a lot to learn when it comes to maintaining projects. Nevertheless, if you’re starting your own Github project, hopefully you’ll be able to avoid some of the pitfalls I ran into.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;0&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;With Slate, people would often report that header tags generated by Slate would &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tripit&#x2F;slate&#x2F;issues&#x2F;64&quot;&gt;sometimes have invalid IDs&lt;&#x2F;a&gt;. This is a bug, but the bug lies within &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;vmg&#x2F;redcarpet&#x2F;issues&#x2F;385&quot;&gt;Redcarpet&lt;&#x2F;a&gt;, not Slate. I created a workaround, and although we didn’t wait for Redcarpet to fix the bug, it also means there’s now a Redcarpet patch in Slate that I have to maintain.
&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;: When it came to pull requests, I used to have the attitude of “it has bugs? I’ll fix them for you!” I was worried about inconveniencing people who already put in the work to write a feature. I’ve since gotten more comfortable with asking pull requesters to make changes to their patches, even major, structural changes. It turns out most people are okay with polite criticism about their code!&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Emoji Shell</title>
    <published>2014-05-21T00:00:00+00:00</published>
    <updated>2014-05-21T00:00:00+00:00</updated>
    <link href="https://lord.io/emoji-shell/" type="text/html"/>
    <id>https://lord.io/blog/2014/emoji-shell/</id>
    <content type="html">&lt;p&gt;Now that Hacker School is over, I finally have some spare time to blog about the projects I built. This is one I built about 2&#x2F;3rds of the way into the batch.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve been writing &lt;a href=&quot;&#x2F;blog&#x2F;2014&#x2F;sha256-in-rust&#x2F;&quot;&gt;various&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;rustoleum&quot;&gt;small projects&lt;&#x2F;a&gt; in Rust in order to learn the language. My most recent project is a shell! Since obviously it&#x27;d be a ton of work to make an actually decent shell, I instead opted to build an &lt;em&gt;different&lt;&#x2F;em&gt; kind of shell. It uses emoji! You can clone the repository &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;emoji-shell&quot;&gt;on Github&lt;&#x2F;a&gt;, and run &lt;code&gt;rustc shell.rs&lt;&#x2F;code&gt; to compile.&lt;&#x2F;p&gt;
&lt;p&gt;Once you start &lt;code&gt;.&#x2F;shell&lt;&#x2F;code&gt;, you should see the prompt string:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;shell1.png&quot; alt=&quot;Shell screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes, the prompt string is a sea shell. That&#x27;s how you know you&#x27;re in emoji shell! Intuitive, no? To run basic commands, you can just type them:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;shell3.png&quot; alt=&quot;Shell screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;That little running person indicates the program is running, and the running icon with a cross through it tells you the program has stopped. The number is the exit code.&lt;&#x2F;p&gt;
&lt;p&gt;Emoji shell also has a neat command line arguments feature — you don&#x27;t need those pesky double quotes, even if an argument has spaces! Just separate all arguments with tomatoes, and emoji shell will take care of the rest. You&#x27;re probably thinking &amp;quot;of all the emoji, why tomatoes?&amp;quot; right now. That&#x27;s a good question.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;shell4.png&quot; alt=&quot;Shell screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;(If you want a tomato in one of your arguments, sorry, you&#x27;re out of luck.)&lt;&#x2F;p&gt;
&lt;p&gt;To print the current working directory, you can use the location pin. To &lt;code&gt;cd&lt;&#x2F;code&gt;, use the car to drive to your desired location. Don&#x27;t forget the tomato!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;shell6.png&quot; alt=&quot;Shell screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;ls&lt;&#x2F;code&gt; is a magnifying glass icon, and I&#x27;m sure you can guess what &lt;code&gt;cat&lt;&#x2F;code&gt; is.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;shell7.png&quot; alt=&quot;Shell screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building-the-shell-in-rust&quot;&gt;Building the Shell in Rust&lt;&#x2F;h2&gt;
&lt;p&gt;Building the shell in Rust was relatively simple. I started with the code from the University of Virginia&#x27;s &lt;a href=&quot;http:&#x2F;&#x2F;www.rust-class.org&#x2F;pages&#x2F;ps2.html&quot;&gt;OS class&lt;&#x2F;a&gt;. Sadly, the code was over a month old. In Rust terms, this means it&#x27;s basically as old as the hills, and can&#x27;t be expected to run any more. (I feel like there&#x27;s probably a rust pun somewhere in there.) I had to adapt it to Rust&#x27;s new &lt;code&gt;std::io::Process&lt;&#x2F;code&gt;. Getting it to create a process with stdin and out hooked up to Rust&#x27;s stdin and out was a little difficult, but I managed to make it work:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; config &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;ProcessConfig {
&lt;&#x2F;span&gt;&lt;span&gt;  program&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; cmd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  args&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; argv&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  cwd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5ccfe6;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;cwd)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  stdin&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;InheritFd(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  stdout&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;InheritFd(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  stderr&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;InheritFd(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.. &lt;&#x2F;span&gt;&lt;span&gt;process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;ProcessConfig&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;new()
&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; p &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Process&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;configure(config)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; status &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; p&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;wait&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By default, the &lt;code&gt;stdin&lt;&#x2F;code&gt; and &lt;code&gt;stdout&lt;&#x2F;code&gt; for a process create new pipes for sending and collecting data. Since we&#x27;re writing a shell, this is not what we want! We want the subprocess to send its stdin, out, and err to the same place as out Rust program. &lt;code&gt;stderr: process::InheritFd()&lt;&#x2F;code&gt; gives us the file descriptor of a file with a certain number, which allows us to pass it to the subprocess.&lt;&#x2F;p&gt;
&lt;p&gt;The rest of the shell was somewhat trivial. There&#x27;s just a loop that gets repeated for each command, and the command is split along tomatoes, and run. There was a little bit of trickiness with the unicode characters, namely needing &lt;code&gt;\u&lt;&#x2F;code&gt; for 16 bit unicode characters and &lt;code&gt;\U&lt;&#x2F;code&gt; for 32 bit, but besides that, the rest was relatively simple! If I had more time to improve it, it&#x27;d be fun to add piping the stdout of one process to the stdin of another. Thankfully, there happens to be an pipe emoji.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Implementing a Hash Length Extension Attack</title>
    <published>2014-04-03T00:00:00+00:00</published>
    <updated>2014-04-03T00:00:00+00:00</updated>
    <link href="https://lord.io/length-extension-attacks/" type="text/html"/>
    <id>https://lord.io/blog/2014/length-extension-attacks/</id>
    <content type="html">&lt;p&gt;In my &lt;a href=&quot;&#x2F;blog&#x2F;2014&#x2F;arduino-encryption&quot;&gt;previous post&lt;&#x2F;a&gt;, I explained how we used SHA-256 to cryptographically sign HTTP requests between an Arduino called DoorDuino and a Ruby app known as Doorbot. However, that system was vulnerable to a hash length extension attack. To understand how extension attacks work, let&#x27;s first discuss how SHA-256 hashes strings.&lt;&#x2F;p&gt;
&lt;p&gt;SHA-256 starts by creating an array of 8 numbers, which start out as predefined constants. Let’s call this array &lt;code&gt;h&lt;&#x2F;code&gt;. SHA-256 then loops through the message to be hashed in 512-bit chunks. For each chunk, it uses some math magic to modify &lt;code&gt;h&lt;&#x2F;code&gt; according to the 512 bits of the chunk and the previous value of &lt;code&gt;h&lt;&#x2F;code&gt;. This continues until all the chunks have been processed and &lt;code&gt;h&lt;&#x2F;code&gt; has been totally scrambled up. It then takes this final value of &lt;code&gt;h&lt;&#x2F;code&gt;, converts it to hexadecimal, and outputs it.&lt;&#x2F;p&gt;
&lt;p&gt;Since a SHA-256 hash is just &lt;code&gt;h&lt;&#x2F;code&gt; in hexadecimal form, anybody who can see the hash knows the final value of &lt;code&gt;h&lt;&#x2F;code&gt;. There&#x27;s nothing stopping an attacker from taking that &lt;code&gt;h&lt;&#x2F;code&gt;, and using the math magic again on another 512-bit chunk to create a new hash of the plaintext of the first hash with additional content added on at the end. The hash will be different, but the attacker &lt;em&gt;doesn&#x27;t need to know the existing plaintext&lt;&#x2F;em&gt; to generate a new hash with content added on to that plaintext. This means they could change the Doorbot request without knowing the password!&lt;&#x2F;p&gt;
&lt;p&gt;Now exploits aren&#x27;t any fun if you can&#x27;t actually use them, so let&#x27;s try it out! In order to use this exploit, your SHA-256 library must let you set the initial values of the internal hash. Sadly, Ruby&#x27;s &lt;code&gt;digest&lt;&#x2F;code&gt; library doesn&#x27;t have this functionality, so &lt;a href=&quot;http:&#x2F;&#x2F;www.mavant.com&#x2F;&quot;&gt;Matthew Avant&lt;&#x2F;a&gt; and I built an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mavant&#x2F;SHA-256&quot;&gt;implementation&lt;&#x2F;a&gt; of SHA-256 in Rust. We can easily get the sha256 of a string.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#f28779;&quot;&gt;sha256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;kittens&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; c81a7b1e755bdf87160ff008f94c8ecc21bc2a71a23bf5e1351300edc0231a1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Our library also has the function &lt;code&gt;sha256_core&lt;&#x2F;code&gt;, which allows customization of &lt;code&gt;h&lt;&#x2F;code&gt;&#x27;s initial vector, as well as an argument to change the calculated length of the hashed content, which will become useful later. It also accepts arrays of bytes instead of strings. In Rust, we convert strings to byte arrays by calling &lt;code&gt;.as_bytes().to_owned()&lt;&#x2F;code&gt; on them.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#f28779;&quot;&gt;sha256_core&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;kittens&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;as_bytes&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;to_owned&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffcc66;&quot;&gt;0x6a09e667&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xbb67ae85&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x3c6ef372&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xa54ff53a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x510e527f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x9b05688c&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x1f83d9ab&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x5be0cd19
&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; c81a7b1e755bdf87160ff008f94c8ecc21bc2a71a23bf5e1351300edc0231a1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Those two statements generate the same hash, and are equivalent — internally, &lt;code&gt;sha256&lt;&#x2F;code&gt; sets the initial value of &lt;code&gt;h&lt;&#x2F;code&gt; to &lt;code&gt;(0x6a09e667,0xbb67ae85,...)&lt;&#x2F;code&gt;, converts the message to an array of bytes, and sets the length to the length of the string.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-authentic-request&quot;&gt;The Authentic Request&lt;&#x2F;h2&gt;
&lt;p&gt;Now that our library is all set up and ready to go, let&#x27;s play the part of Doorbot, making the authenticated request to the Arduino. To unlock the door, our app makes a request to &lt;code&gt;http:&#x2F;&#x2F;doorduino&#x2F;unlock?nonce=&amp;lt;nonce&amp;gt;&lt;&#x2F;code&gt;, where &lt;code&gt;&amp;lt;nonce&amp;gt;&lt;&#x2F;code&gt; is the incrementing number. The app also sends an &lt;code&gt;X-Auth-Hash&lt;&#x2F;code&gt; header, whose value is a &lt;code&gt;sha256&lt;&#x2F;code&gt; hash generated like so:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;sha256(password + url_requested)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;password&lt;&#x2F;code&gt; is a password that is 15 characters long, and is specific to each doorbot&#x2F;doorduino pair. For our pair, the password is &lt;code&gt;secret_password&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, let&#x27;s do an example where the nonce is &lt;code&gt;42&lt;&#x2F;code&gt;. Our app will first calculate the sha256 hash from the URL and the password. These examples are all in Rust, but you shouldn&#x27;t need to know Rust to understand them — they&#x27;re pretty simple.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#f28779;&quot;&gt;sha256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;secret_password&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+ ~&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;http:&#x2F;&#x2F;doorduino&#x2F;unlock?nonce=42&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; 2e663bc3fab972a7d33a7b77dc8017bdb326065b1950f6629e448c284de36e9f
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, our app makes the HTTP request, which looks like this:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;POST http:&#x2F;&#x2F;doorduino&#x2F;unlock?nonce=42 HTTP&#x2F;1.1
&lt;&#x2F;span&gt;&lt;span&gt;Host: doorduino
&lt;&#x2F;span&gt;&lt;span&gt;Accept: *&#x2F;*
&lt;&#x2F;span&gt;&lt;span&gt;X-Auth-Hash: 2e663bc3fab972a7d33a7b77dc8017bdb326065b1950f6629e448c284de36e9f
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;the-attack&quot;&gt;The Attack&lt;&#x2F;h2&gt;
&lt;p&gt;Meanwhile, our attacker, who is well-equipped with our Rust implementation of SHA-256, spies on the connection and sees the HTTP request above. They also have access to the source code (it&#x27;s an open source project), but not the actual password used. So, our attacker has three pieces of information:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;How the hash is generated: &lt;code&gt;sha256(password + url)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The fact that passwords are always 15 characters long&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;li&gt;
&lt;li&gt;The URL requested: &lt;code&gt;http:&#x2F;&#x2F;doorduino&#x2F;unlock?nonce=42&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;The valid hash of the password and the URL: &lt;code&gt;2e663bc3fab972a7d33a7b77dc8017bdb326065b1950f6629e448c284de36e9f&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The attacker wants to generate a new HTTP request with a &lt;em&gt;higher&lt;&#x2F;em&gt; nonce that has a valid hash. Actually figuring out the password from the hash is next to impossible &lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, but as we showed earlier, the attacker doesn&#x27;t &lt;em&gt;need&lt;&#x2F;em&gt; to know the password.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, the attacker feeds the captured hash as the initial value of &lt;code&gt;h&lt;&#x2F;code&gt; to &lt;code&gt;sha256_core&lt;&#x2F;code&gt;, along with the string &lt;code&gt;&amp;amp;nonce=43&lt;&#x2F;code&gt;, and the calculated length of the password. They also pass &lt;code&gt;sha_core&lt;&#x2F;code&gt; the length in bytes of the existing hashed 512-bit block, which is 64, plus the length of the extension, which is 9, for a total of 73.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#f28779;&quot;&gt;sha256_core&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&amp;amp;nonce=43&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffcc66;&quot;&gt;0x2e663bc3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xfab972a7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xd33a7b77&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xdc8017bd&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xb326065b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x1950f662&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x9e448c28&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x4de36e9f
&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;73&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; 60be0a782cc4664e20b4c14799627b2742e437529b17ba8051fa75e018ee6a68
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This new hash is the hash of the contents of the first hash, with &lt;code&gt;&amp;amp;nonce=43&lt;&#x2F;code&gt; at the end. The attacker did not need to know the original password to generate this hash! They just generated a new hash of both the &lt;em&gt;contents&lt;&#x2F;em&gt; of the old hash with their new string tacked on at the end.&lt;&#x2F;p&gt;
&lt;p&gt;Well, I say just tacked on, but it&#x27;s sightly more complicated than that. &lt;code&gt;sha256&lt;&#x2F;code&gt; appends the total length of the message on to the end of the message, a &lt;code&gt;1&lt;&#x2F;code&gt; bit after the message, and adds &lt;code&gt;0&lt;&#x2F;code&gt; bits in between the length and the &lt;code&gt;1&lt;&#x2F;code&gt; until the total message length perfectly fills the last block. The final message length is always a multiple of 512 bits. This means that if you originally hashed &lt;code&gt;chicken&lt;&#x2F;code&gt;, &lt;code&gt;sha256&lt;&#x2F;code&gt; transforms that message into:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;chicken\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;small&gt;(&lt;code&gt;\x&lt;&#x2F;code&gt; is an escape sequence that takes the hexadecimal number after in and converts it into a raw byte.)&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So our attacker sends this request to the server:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;POST http:&#x2F;&#x2F;doorduino&#x2F;unlock?nonce=42\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x78&amp;amp;nonce=43 HTTP&#x2F;1.1
&lt;&#x2F;span&gt;&lt;span&gt;Host: doorduino
&lt;&#x2F;span&gt;&lt;span&gt;Accept: *&#x2F;*
&lt;&#x2F;span&gt;&lt;span&gt;X-Auth-Hash: 60be0a782cc4664e20b4c14799627b2742e437529b17ba8051fa75e018ee6a68
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;receiving-the-fake-request&quot;&gt;Receiving the Fake Request&lt;&#x2F;h2&gt;
&lt;p&gt;The Arduino receives this request, converts the string into a byte array, and hashes it&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;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#f28779;&quot;&gt;sha256_core&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;secret_passwordhttp:&#x2F;&#x2F;doorduino&#x2F;unlock?nonce=42&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;as_bytes&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;to_owned&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x80 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x78&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&amp;amp;nonce=43&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;as_bytes&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;to_owned&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffcc66;&quot;&gt;0x6a09e667&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xbb67ae85&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x3c6ef372&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xa54ff53a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x510e527f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x9b05688c&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x1f83d9ab&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x5be0cd19
&lt;&#x2F;span&gt;&lt;span&gt;            )&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;73&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;&#x2F;&#x2F; 60be0a782cc4664e20b4c14799627b2742e437529b17ba8051fa75e018ee6a68
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The hash is valid, and contains the password, even though the hacker did not know the password at any point. Although it &lt;a href=&quot;http:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1746507&#x2F;authoritative-position-of-duplicate-http-get-query-keys&quot;&gt;depends&lt;&#x2F;a&gt; on how the Arduino is set up to parse duplicate query strings, it will likely overwrite the first definition of nonce (&lt;code&gt;42\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x78&lt;&#x2F;code&gt;) with the latter, &lt;code&gt;43&lt;&#x2F;code&gt;. It will see that the nonce is larger than the original request, and unlock the door.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;protecting-against-this-attack&quot;&gt;Protecting Against this Attack&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hmac&quot;&gt;HMAC&lt;&#x2F;a&gt; is a way to prevent extension attacks. Instead of just hashing the content and password once, HMAC uses an algorithm that includes hashing the result of another hash, that is, nested hashing. This means that extending the outside hash is pointless, since the inside hash will still be unchanged and the server will detect the hash is invalid.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;in-the-wild&quot;&gt;In the Wild&lt;&#x2F;h2&gt;
&lt;p&gt;Although I made several assumptions along the way and my examples seems perhaps someone contrived, this attack is a real exploit that has been used against web services such as &lt;a href=&quot;http:&#x2F;&#x2F;netifera.com&#x2F;research&#x2F;flickr_api_signature_forgery.pdf&quot;&gt;Flickr and Remember the Milk&lt;&#x2F;a&gt;.  It&#x27;s a good thing to keep in mind when looking at anything that uses a hashing algorithm to sign something — SHA-256 isn&#x27;t the only hashing algorithm vulnerable to this.&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;In practice, the protocol would probably not specify a password length, and an attacker wouldn&#x27;t know the length of the password, but having to guess is fairly simple — assuming the password is less than ~200 characters, the attacker would have to try at most 200 hashes to find the right one.
&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;: That is, if the password weren&#x27;t as simple as &lt;code&gt;secret_password&lt;&#x2F;code&gt;.
&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;: This example is in Rust with our library, although in reality Arduino programs are written in that weird C variant thing. Additionally, all that weird syntax is because Rust doesn&#x27;t allow for invalid UTF-8 strings, so some parts have to be raw byte arrays.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Hashes, Nonces, and Replay Attacks on the Arduino</title>
    <published>2014-03-29T00:00:00+00:00</published>
    <updated>2014-03-29T00:00:00+00:00</updated>
    <link href="https://lord.io/arduino-encryption/" type="text/html"/>
    <id>https://lord.io/blog/2014/arduino-encryption/</id>
    <content type="html">&lt;p&gt;When &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jdotjdot&quot;&gt;J.J.&lt;&#x2F;a&gt; and I designed &lt;a href=&quot;&#x2F;blog&#x2F;2014&#x2F;unlocking-hacker-school&quot;&gt;the Hacker School door system&lt;&#x2F;a&gt;, one of our problems was keeping the system secure.&lt;&#x2F;p&gt;
&lt;p&gt;There are two parts of the door system, DoorDuino, which is an Arduino that unlocks the door, and Doorbot, which is a Sinatra server that registers users and receives text messages. These two pieces talk to each other over HTTP. When it receives a text, Doorbot sends an HTTP request to DoorDuino, which unlocks the door.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, this system isn&#x27;t the most secure. If an attacker were to spy on the connection between the two, they could see the unlock requests, and just send them again to unlock the door whenever they wanted, circumventing the Twilio number verification. We need some sort of encryption to protect the connection between the devices.&lt;&#x2F;p&gt;
&lt;p&gt;The obvious solution would have been SSL. With SSL, the URL that is being requested is encrypted from attackers, and the connection is &lt;a href=&quot;http:&#x2F;&#x2F;security.stackexchange.com&#x2F;a&#x2F;20106&quot;&gt;protected&lt;&#x2F;a&gt; from &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Replay_attack&quot;&gt;replay attacks&lt;&#x2F;a&gt;. Even if an attacker were to copy one of the Sinatra server&#x27;s SSL-protected requests bit by bit, and try to resend it, the Arduino would reject it. This would have been the perfect solution, except for one problem — Arduinos do not support SSL, and probably wouldn&#x27;t have enough memory to do it properly, anyway.&lt;&#x2F;p&gt;
&lt;p&gt;If we don&#x27;t have enough horsepower to do SSL, is there any crypto we &lt;em&gt;can&lt;&#x2F;em&gt; do? Thankfully, there is a SHA-256 library for Arduinos, so we decided to use that to sign the incoming HTTP requests. SHA-256 is a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cryptographic_hash_function&quot;&gt;cryptographic hash&lt;&#x2F;a&gt;, which is basically one-way encryption. Any message can be easily encrypted into a SHA256 hash, but if you have a SHA-256 hash, it&#x27;s very, very difficult to figure out what message was put in, especially if the message was long. If we needed the message to be &lt;em&gt;secret&lt;&#x2F;em&gt;, for an attacker to not know what message was being sent, we would have had to use more complicated two-way encryption. Fortunately, we don&#x27;t care if attackers can see the message. We just want to make sure that they can&#x27;t fake a new unlock request of their own.&lt;&#x2F;p&gt;
&lt;p&gt;So, with this basic encryption strategy, we take the hash of the password, and then send it over to the Arduino.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;sha256(&amp;quot;SUPER SECRET PASSWORD&amp;quot;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Arduino calculates the &lt;code&gt;sha256&lt;&#x2F;code&gt; of &lt;code&gt;&amp;quot;SUPER SECRET PASSWORD&amp;quot;&lt;&#x2F;code&gt;, and makes sure that the hashes match before unlocking the door.&lt;&#x2F;p&gt;
&lt;p&gt;However, it&#x27;s pretty obvious that this is insecure. If an attacker were spying on the connection to the Arduino, they would see a request like this come in.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;POST &#x2F;unlock&#x2F;e88798b1ebdf2e7b9f698255b5dcb5270a6fcc92c4b HTTP&#x2F;1.1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The second part of the URL is the hash of the password. Since this is a hash, the attacker can&#x27;t figure out the original password&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. However, the hacker could just send the &lt;em&gt;exact same&lt;&#x2F;em&gt; &lt;code&gt;POST&lt;&#x2F;code&gt; request to the Arduino, and the door would unlock. They don&#x27;t &lt;em&gt;need&lt;&#x2F;em&gt; to know the password to unlock the door. This is called a replay attack.&lt;&#x2F;p&gt;
&lt;p&gt;In order to protect our system against replay attacks, we need a way to make each valid request unique. If identical requests are valid, the system is susceptible to replay attacks. Usually, the way to make requests unique like this is by using a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cryptographic_nonce&quot;&gt;cryptographic nonce&lt;&#x2F;a&gt;, which is a unique number or word used in the request that is only valid once. SSL uses nonces with a handshake, which would work something like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Sinatra requests a nonce from the Arduino.&lt;&#x2F;li&gt;
&lt;li&gt;The Arduino sends a unique nonce, &lt;code&gt;19283029&lt;&#x2F;code&gt;, to Sinatra.&lt;&#x2F;li&gt;
&lt;li&gt;Sinatra computes the hash of the nonce plus the password: &lt;code&gt;sha256(&amp;quot;SUPER SECRET PASSWORD&amp;quot; + &amp;quot;19283029&amp;quot;)&lt;&#x2F;code&gt;, and sends it to the Arduino.&lt;&#x2F;li&gt;
&lt;li&gt;The Arduino makes sure the hash is valid, and unlocks the door.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;With this method, if an attacker were to attempt to replay the attack, the nonce would have already been used, and the Arduino would reject the request. And, since the attacker needs to know the password to create new valid requests, they can&#x27;t just request a new nonce and send a request with it.&lt;&#x2F;p&gt;
&lt;p&gt;However, this requires the Arduino to do quite a bit, and we want our system to be as simple as possible, so instead, we use a simple incrementing nonce. Instead of a handshake, the Doorbot sends an unlock request to the Arduino right away. To do this, Doorbot finds the last nonce used, and increments it by one to get a new nonce, which we&#x27;ll say is &lt;code&gt;182&lt;&#x2F;code&gt;. Doorbot then calculates the hash of the nonce added to the password.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;sha256(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;secret_password&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;182&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# =&amp;gt; 72672c56a4a44c86c2fb47d02365c46a988fbde44daaf9d7dd7ee393fa2a3a0c
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Doorbot then sends an HTTP request to the Arduino with the nonce and the hash:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;POST &#x2F;182&#x2F;72672c56a4a44c86c2fb47d02365c46a988fbde44daaf9d7dd7ee393fa2a3a0c HTTP&#x2F;1.1
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Arduino receives the request, makes sure the nonce is larger than any previous nonce used, and that the hash is actually the hash of the nonce plus the secret password. If everything is good, the Arduino unlocks the door.&lt;&#x2F;p&gt;
&lt;p&gt;If an attacker tries to resend a request, the Arduino can see that the nonce is not larger, and reject the request. If they just increment the nonce, they&#x27;ll be unable to generate a valid hash without the secret password, so that request will fail. Additionally, the Arduino doesn&#x27;t have to keep any state except the largest nonce used so far. The handshake method would require the Arduino to generate and keep an array of valid nonces, which would have been more complicated and difficult to debug. This method is also nice because it does not require the Arduino to have any concept of time&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;So this method seems pretty secure, right? I thought so too, but &lt;a href=&quot;http:&#x2F;&#x2F;www.somerandomidiot.com&#x2F;&quot;&gt;Mindy Preston&lt;&#x2F;a&gt; told me to look up hash length extension attacks. The system above is potentially vulnerable. In the next blog post, I&#x27;ll use my &lt;a href=&quot;&#x2F;blog&#x2F;2014&#x2F;sha256-in-rust&quot;&gt;SHA-256 implementation in Rust&lt;&#x2F;a&gt; to explain how to exploit a length extension attack, how the internals of SHA-256 make it possible, and how to protect against it.&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;Assuming the original password was long enough.
&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;: Getting the current time is surprisingly difficult on the Arduino.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>SHA-256 in Rust</title>
    <published>2014-03-24T00:00:00+00:00</published>
    <updated>2014-03-24T00:00:00+00:00</updated>
    <link href="https://lord.io/sha256-in-rust/" type="text/html"/>
    <id>https://lord.io/blog/2014/sha256-in-rust/</id>
    <content type="html">&lt;p&gt;Today, I implemented the &lt;a href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;SHA-2&quot;&gt;SHA-256&lt;&#x2F;a&gt; hashing algorithm &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mavant&#x2F;SHA256&quot;&gt;from scratch in Rust&lt;&#x2F;a&gt;, with &lt;a href=&quot;http:&#x2F;&#x2F;www.mavant.com&#x2F;&quot;&gt;Matthew Avant&lt;&#x2F;a&gt;. &lt;em&gt;&amp;quot;Why in the lord&#x27;s name would you do this?&amp;quot;&lt;&#x2F;em&gt; is a question you probably would ask. Hahaha, you&#x27;re so funny! Let&#x27;s talk about how SHA-256 works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-big-picture&quot;&gt;The Big Picture&lt;&#x2F;h2&gt;
&lt;p&gt;SHA-256 starts by creating an array of 8 numbers, which start out as predefined constants. Let&#x27;s call this array &lt;code&gt;h&lt;&#x2F;code&gt;. SHA-256 then loops through the message in 512-bit chunks. For each chunk, it uses some math magic to modify &lt;code&gt;h&lt;&#x2F;code&gt; according to the 512 bits of the chunk and the previous value of &lt;code&gt;h&lt;&#x2F;code&gt;. This continues until all the chunks have been processed and &lt;code&gt;h&lt;&#x2F;code&gt; has been totally scrambled up. It then takes this final value of &lt;code&gt;h&lt;&#x2F;code&gt;, converts it to hexadecimal, and outputs it. With this method, the amount of memory needed doesn&#x27;t balloon out of control for large files. At the same time, a small change, even at the start of the message, will completely change how the rest of the message is hashed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-rust-implementation&quot;&gt;The Rust Implementation&lt;&#x2F;h2&gt;
&lt;p&gt;The algorithm starts off with defining the initial hash values &lt;code&gt;h0&lt;&#x2F;code&gt; through &lt;code&gt;h7&lt;&#x2F;code&gt;, and the round constants &lt;code&gt;k&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;sha256&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; ~&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&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:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x6a09e667&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xbb67ae85&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x3c6ef372&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xa54ff53a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x510e527f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x9b05688c&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x1f83d9ab&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x5be0cd19&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; k &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x428a2f98&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x71374491&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xb5c0fbcf&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0xc67178f2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;h0&lt;&#x2F;code&gt; ... &lt;code&gt;h7&lt;&#x2F;code&gt; variables are the initial values of the hash. After each round, these variables will be replaced by the output of the mathy stuff, but since this is the first round and we don&#x27;t have any output yet, they need to have an initial value, which is those numbers up above.&lt;&#x2F;p&gt;
&lt;p&gt;Once the initialization is set up, we need to prepare the string, which involves converting it to an array of bytes, padding the end with zeros, and adding the length of the message in bits at the very end.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; msg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; input&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;as_bytes&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;to_owned&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; l &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; msg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u64&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;msg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x80&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span&gt;(msg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;% &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;!= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;56 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  msg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;std&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;io&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;extensions&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;u64_to_be_bytes(l&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span&gt;|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;v&lt;&#x2F;span&gt;&lt;span&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; v&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  msg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;i)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;})&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The padding ensures that the 512-bit chunks are exactly full, so the last chunk isn&#x27;t half-filled if the bit length of the message aren&#x27;t divisible by 512.&lt;&#x2F;p&gt;
&lt;p&gt;The next step is to actually divide up the message into chunks of 64 bytes.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; msg&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;mut_chunks&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rust makes that pretty easy. For each chunk, we&#x27;re going to do a bunch of mathy stuff, and get out the variables &lt;code&gt;a&lt;&#x2F;code&gt; through &lt;code&gt;h&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; w&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; a1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(c[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;(num&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;pow(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; a2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(c[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;(num&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;pow(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; a3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(c[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span&gt;(num&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;pow(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; a4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(c[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; a1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; a2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; a3 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt;a4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    w[i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; s0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;18&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span&gt;(w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; s1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;u32 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span&gt;(w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    w[i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; s0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; w[i&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;-&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; s1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; e &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; g &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let mut&lt;&#x2F;span&gt;&lt;span&gt; h &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h7&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&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:#ffa759;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;range&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;64&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;S1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(e&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(e&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(e&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; ch &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(e &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; f) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;e &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; g)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; temp1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; h &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;S1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; ch &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; k[i] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; w[i]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;S0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;13&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;rotr&lt;&#x2F;span&gt;&lt;span&gt;(a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; maj &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; b) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span&gt;(a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; c) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;^ &lt;&#x2F;span&gt;&lt;span&gt;(b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt; c)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; temp2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;S0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; maj&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    h &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; g&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    g &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; e&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    e &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; temp1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    d &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; c&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; temp1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt; temp2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we&#x27;ve got the variables out, we add them to the hash state variables (modulo &lt;code&gt;2^32&lt;&#x2F;code&gt;, since the variables are &lt;code&gt;u32&lt;&#x2F;code&gt;s), and loop back to the next chunk to continue.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;h0 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;h1 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;h2 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; c&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;h3 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; d&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;h4 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; e&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;h5 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; f&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;h6 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; g&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;h7 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;+=&lt;&#x2F;span&gt;&lt;span&gt; h&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once all the chunks have been processed, we encode the hash vars into hexadecimal, and print them.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#212733;color:#ccc9c2;&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:#f28779;&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;{:x}{:x}{:x}{:x}{:x}{:x}{:x}{:x}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h3&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h5&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; h7)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s all there is to it! In my next blog post, I&#x27;ll explain a potential vulnerability in hashing when it&#x27;s used for signing, such as how we used it when building &lt;a href=&quot;&#x2F;blog&#x2F;2014&#x2F;unlocking-hacker-school&quot;&gt;doorbot&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Unlocking Hacker School with a Text</title>
    <published>2014-03-21T00:00:00+00:00</published>
    <updated>2014-03-21T00:00:00+00:00</updated>
    <link href="https://lord.io/unlocking-hacker-school/" type="text/html"/>
    <id>https://lord.io/blog/2014/unlocking-hacker-school/</id>
    <content type="html">&lt;p&gt;One of the many perks of Hacker School is alumni Thursdays, where alumni can come in to hack on open source projects and pair program with others. However, there is a problem — Hacker School doesn&#x27;t have enough key fobs to give to every alumnus. Instead, they ring the doorbell, and someone sits by the phone to press the &amp;quot;unlock&amp;quot; button whenever it rings.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;door-1.jpg&quot; alt=&quot;Door1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;small&gt;The phone in question. The lowest of the three buttons unlocks the building&#x27;s front door.&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is a poor solution — the doorbell is loud and buzzy, and whoever has to sit by the phone is constantly distracted. This is Hacker School, dammit! We can fix this! Since Hacker School seems to always have a surplus of Arduinos, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jdotjdot&quot;&gt;J.J.&lt;&#x2F;a&gt; and I set out to connect an Arduino to the phone. We could use this Arduino with Twilio to let alumni unlock the door with a text message.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hacking-the-phone&quot;&gt;Hacking the Phone&lt;&#x2F;h2&gt;
&lt;p&gt;With the help of &lt;a href=&quot;http:&#x2F;&#x2F;slendermeans.org&#x2F;&quot;&gt;Carl&lt;&#x2F;a&gt;&#x27;s disassembling skills and a butter knife, we got the phone opened up.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;door-2.jpg&quot; alt=&quot;Door1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There was some label that said &amp;quot;WARNING: HIGH VOLTAGE, MAY CAUSE MORTAL DAMAGE&amp;quot;, but we just kinda ignored it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;door-3.jpg&quot; alt=&quot;Door1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The phone was surprisingly difficult to disassemble, but we managed to expose the part of the phone just behind the buttons in a way so that everything still worked. Simulating a press of the &amp;quot;unlock&amp;quot; button was as simple as connecting a wire from one metal contact to another. The phone manufacturer even put in little metal rings that made it easy to connect alligator clips. How considerate of them!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;door-4.jpg&quot; alt=&quot;Door1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;small&gt;The two metal contacts behind the button.&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We obviously didn&#x27;t want to have someone standing there connecting and disconnecting wires to unlock the door, so we used a &lt;a href=&quot;http:&#x2F;&#x2F;wikipedia.org&#x2F;wiki&#x2F;Relay&quot;&gt;relay&lt;&#x2F;a&gt; hooked up to one of the Arduino&#x27;s output pins to programmatically allow current to flow across the button. J.J. has a soon-to-be published blog post with more details.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;door-5.jpg&quot; alt=&quot;Door1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Once the relay was set up, the Arduino &lt;em&gt;could&lt;&#x2F;em&gt; unlock the door, but had no idea &lt;em&gt;when&lt;&#x2F;em&gt; to. We got an ethernet shield, and J.J. created an &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jdotjdot&#x2F;DoorDuino&quot;&gt;HTTP server&lt;&#x2F;a&gt; for the Arduino that unlocked the door whenever it received a &lt;code&gt;POST&lt;&#x2F;code&gt; with the correct password. (I&#x27;ll write more about how we encrypted that password in a future blog post.)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;door-6.jpg&quot; alt=&quot;Door1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;small&gt;The finished Arduino and phone, all packaged up neatly. The note on the screen reads &amp;quot;Mess with the best, die like the rest.&amp;quot;&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;twilio-and-authentication&quot;&gt;Twilio and Authentication&lt;&#x2F;h2&gt;
&lt;p&gt;We wanted to design the text messaging system so that only Hacker Schoolers with registered phone numbers could unlock the door. Rather than overload the already memory-starved Arduino with more tasks, we decided to have a separate server, on an actual Linux-running computer, to handle the user registration and text messaging. When the server detects a new text message from a Hacker Schooler, it sends a HTTP &lt;code&gt;POST&lt;&#x2F;code&gt; to the Arduino, and the Arduino unlocks the door.&lt;&#x2F;p&gt;
&lt;p&gt;Originally this server was to be hosted on Heroku. Sadly, that would require poking a hole in the Hacker School firewall for Heroku to send unlock requests to the Arduino. Instead, we hosted the server locally on the Hacker School network. Although this forces people to connect to the Hacker School Wi-Fi to register their phone numbers, it makes the whole setup a bit more secure, so we stuck with it.&lt;&#x2F;p&gt;
&lt;p&gt;We wrote this server, called &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;doorbot&quot;&gt;Doorbot&lt;&#x2F;a&gt;, in Sinatra. When someone first connects, Doorbot uses Hacker School&#x27;s OAuth server and the &lt;code&gt;oauth2&lt;&#x2F;code&gt; Ruby gem to make sure they&#x27;re a Hacker Schooler.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;doorbot-login.png&quot; alt=&quot;Doorbot login screen&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After people have logged in with their Hacker School account, Doorbot prompts them to add their phone number to the whitelist.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;doorbot-phone.png&quot; alt=&quot;Doorbot phone entry screen&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s also a web interface to unlock the door with the click of a button.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2014&#x2F;doorbot-unlock.png&quot; alt=&quot;Door1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After someone registers their phone number, they can text Doorbot to unlock the door. To check for incoming texts, Doorbot has a separate Ruby script which queries Twilio every couple of seconds. Twilio recommends using their callback system to notify a server when texts are received, but since this is hosted on a local network, Twilio can&#x27;t connect to Doorbot. We had to settle for a polling method, which uses the Twilio API to check the SMS logs every couple of seconds. When a new text appears in the log, Doorbot makes sure it comes from a registered number, and then tells the Arduino to unlock the door.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-result&quot;&gt;The Result&lt;&#x2F;h2&gt;
&lt;p&gt;After about a week and a half of on and off work, we&#x27;ve ended up with a reliable server and Arduino setup to let in alumni without key fobs. Hacker Schoolers can text a number, and the front door unlocks within a second or two. It&#x27;s fun, and I like to think it makes Hacker School a little more welcoming for alumni every Thursday. This project has also been really educational, both in terms of how to control an Arduino remotely with HTTP, as well as how to cope with tight memory constraints.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;d like to run your own &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lord&#x2F;doorbot&quot;&gt;Doorbot&lt;&#x2F;a&gt;&#x2F;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jdotjdot&#x2F;doorduino&quot;&gt;Doorduino&lt;&#x2F;a&gt; pair, feel free to clone them on Github. You&#x27;ll have to modify Doorbot to not require Hacker School OAuth, but that shouldn&#x27;t be too difficult, and you should be up and running in no time at all.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>gdb on OS X</title>
    <published>2014-03-14T00:00:00+00:00</published>
    <updated>2014-03-14T00:00:00+00:00</updated>
    <link href="https://lord.io/gdb-on-osx/" type="text/html"/>
    <id>https://lord.io/blog/2014/gdb-on-osx/</id>
    <content type="html">&lt;p&gt;One of my current projects at &lt;a href=&quot;http:&#x2F;&#x2F;www.hackerschool.com&quot;&gt;Hacker School&lt;&#x2F;a&gt; is to (attempt) to solve the &lt;a href=&quot;http:&#x2F;&#x2F;wikipedia.org&#x2F;wiki&#x2F;Knapsack_problem&quot;&gt;knapsack problem&lt;&#x2F;a&gt; using 64-bit assembly. I&#x27;ve never done anything in assembly before — before I started this project, I didn&#x27;t even know what a &lt;a href=&quot;http:&#x2F;&#x2F;wikipedia.org&#x2F;wiki&#x2F;Processor_register&quot;&gt;register&lt;&#x2F;a&gt; was. It&#x27;s been an educational, if frustrating project. Today&#x27;s frustrations have revolved around macho64 and debugging.&lt;&#x2F;p&gt;
&lt;p&gt;As detailed in &lt;a href=&quot;&#x2F;blog&#x2F;2014&#x2F;assembly-on-osx&quot;&gt;my first assembly blog post&lt;&#x2F;a&gt;, I assemble my &lt;code&gt;knapsack.asm&lt;&#x2F;code&gt; file on OSX with this shell script:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Generate object file from assembly:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;nasm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; macho64&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; knapsack.o knapsack.asm
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Link object file:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;ld&lt;&#x2F;span&gt;&lt;span&gt; knapsack.o&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; knapsack
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This creates a binary file &lt;code&gt;knapsack&lt;&#x2F;code&gt;, which I can easily run from the command line with &lt;code&gt;.&#x2F;knapsack&lt;&#x2F;code&gt;. This works perfectly fine on OS X, no problem.&lt;&#x2F;p&gt;
&lt;p&gt;I started running into trouble, however, when I tried to use gdb, a debugging tool. It&#x27;s great for stepping through assembly code one instruction at a time, looking at the registers, and seeing where the code is screwing up. Installing gdb wasn&#x27;t too difficult, a simple brew install command...&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span&gt; install https:&#x2F;&#x2F;raw.github.com&#x2F;Homebrew&#x2F;homebrew-dupes&#x2F;master&#x2F;gdb.rb
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;...followed by some simple certificate setup, and I was good to go. It worked fine, at first.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span&gt; gdb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -tui&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;knapsack &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# gdb seems to need sudo on OS X
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;) run
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I could see my program execute, and all the values of the registers. Setting breakpoints with &lt;code&gt;break &amp;lt;function name&amp;gt;&lt;&#x2F;code&gt; worked fine as well. However, &lt;code&gt;step&lt;&#x2F;code&gt; had problems.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#212733;color:#ccc9c2;&quot;&gt;&lt;code&gt;&lt;span&gt;(gdb) break open_file
&lt;&#x2F;span&gt;&lt;span&gt;Breakpoint 1 at 0x1f8f
&lt;&#x2F;span&gt;&lt;span&gt;(gdb) run
&lt;&#x2F;span&gt;&lt;span&gt;Starting program: &#x2F;Users&#x2F;robert&#x2F;Desktop&#x2F;knapsack-asm&#x2F;knapsack 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Breakpoint 1, 0x0000000000001f8f in open_file ()
&lt;&#x2F;span&gt;&lt;span&gt;(gdb) step
&lt;&#x2F;span&gt;&lt;span&gt;Single stepping until exit from function open_file,
&lt;&#x2F;span&gt;&lt;span&gt;which has no line number information.
&lt;&#x2F;span&gt;&lt;span&gt;0x0000000000001fd2 in open_file_success ()
&lt;&#x2F;span&gt;&lt;span&gt;(gdb) 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I couldn&#x27;t get gdb to single step through individual lines of assembly code, only entire function calls. I looked on the internet for information about adding debug information to nasm. It looked like you could tell nasm to enable debug information with &lt;code&gt;-g -F &amp;lt;debug format&amp;gt;&lt;&#x2F;code&gt;, and list available debug formats with &lt;code&gt;-y&lt;&#x2F;code&gt;. I checked out the list of formats for macho64.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;nasm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; macho64&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -y
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;valid&lt;&#x2F;span&gt;&lt;span&gt; debug formats for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;macho64&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; output format are (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;#39;*&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; denotes default)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt; null      Null debug format
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Damn. A &lt;a href=&quot;http:&#x2F;&#x2F;forum.nasm.us&#x2F;index.php?topic=651.0&quot;&gt;nasm forum post&lt;&#x2F;a&gt; from 2011 confirmed it — nasm does not support the macho debug format yet.&lt;&#x2F;p&gt;
&lt;p&gt;I definitely wasn&#x27;t going to try the knapsack problem without a working assembly debugger, so I searched for a solution. nasm has an alternative called yasm, but yasm doesn&#x27;t have any macho64-compatible debug formats either. Some suggestions online involved some sort of hack to convert elf64 into macho64, and it didn&#x27;t even sound like that worked. I eventually decided that macho64 just wasn&#x27;t going to cut it.&lt;&#x2F;p&gt;
&lt;p&gt;elf64 runs on Linux, and nasm can output debug information for elf64, so I decided to spin up a quick Linux machine with &lt;a href=&quot;http:&#x2F;&#x2F;vagrantup.com&quot;&gt;Vagrant&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;vagrant&lt;&#x2F;span&gt;&lt;span&gt; init hashicorp&#x2F;precise64
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note the &lt;code&gt;precise64&lt;&#x2F;code&gt;...we&#x27;re running 64-bit assembly, so we need 64-bit Ubuntu, not the 32-bit that Vagrant docs have you set up normally by default.&lt;&#x2F;p&gt;
&lt;p&gt;I also added the following shell provision to the auto generated &lt;code&gt;Vagrantfile&lt;&#x2F;code&gt;, to install nasm and gdb by default on the VM.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-ruby &quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span&gt;config&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;vm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f29e74;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;provision &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;&amp;quot;shell&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ccc9c2cc;&quot;&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bae67e;&quot;&gt;inline: &amp;quot;apt-get update --yes; apt-get install nasm gdb --yes&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, spinning up and sshing into a VM is a simple command away.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;vagrant&lt;&#x2F;span&gt;&lt;span&gt; up
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;vagrant&lt;&#x2F;span&gt;&lt;span&gt; ssh
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once I&#x27;m sshed into the VM, I can easily compile my &lt;code&gt;.asm&lt;&#x2F;code&gt; file with debug information and run gdb on it.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;vagrant&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;nasm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; elf64&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; knapsack.o&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -g -F&lt;&#x2F;span&gt;&lt;span&gt; dwarf knapsack.asm
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;ld&lt;&#x2F;span&gt;&lt;span&gt; knapsack.o&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; knapsack
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -tui&lt;&#x2F;span&gt;&lt;span&gt; .&#x2F;knapsack
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Inside gdb, I can set up a breakpoint and step forward from it...&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;) break open_file 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;Breakpoint&lt;&#x2F;span&gt;&lt;span&gt; 1 at 0x400147: file knapsack.asm, line 76.
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;) run
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;Starting&lt;&#x2F;span&gt;&lt;span&gt; program: &#x2F;vagrant&#x2F;knapsack 
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;Breakpoint&lt;&#x2F;span&gt;&lt;span&gt; 1, open_file () &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;at&lt;&#x2F;span&gt;&lt;span&gt; knapsack.asm:76
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;) step
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;) 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Success! The program steps forward a line. I can also actually see the assembly source code in the top half of the gdb screen. I&#x27;ve definitely never been this excited about a debugger before.&lt;&#x2F;p&gt;
&lt;p&gt;I definitely don&#x27;t know what I&#x27;m doing with this project, and I&#x27;ve had strong feelings of &amp;quot;wow I am seriously just bumbling around here,&amp;quot; but I think that&#x27;s a healthy thing to feel at Hacker School. On the first day, the facilitators told us to &amp;quot;seek out what we&#x27;re scared of.&amp;quot; I&#x27;d say I&#x27;ve definitely lived up to that today.&lt;&#x2F;p&gt;
</content>
  </entry>
  <entry xml:lang="en">
    <title>Running Assembly on OS X</title>
    <published>2014-03-05T00:00:00+00:00</published>
    <updated>2014-03-05T00:00:00+00:00</updated>
    <link href="https://lord.io/assembly-on-osx/" type="text/html"/>
    <id>https://lord.io/blog/2014/assembly-on-osx/</id>
    <content type="html">&lt;p&gt;I&#x27;ve been learning a little assembly with some other Hacker Schoolers. It&#x27;s fun, but I spent nearly an hour yesterday trying to find a modern online guide for running x86-64 assembly on OS X, and couldn&#x27;t really find anything that didn&#x27;t involve complicated uses of &lt;code&gt;gcc&lt;&#x2F;code&gt;. Frankly, without the ever-wise advice of &lt;a href=&quot;http:&#x2F;&#x2F;davidad.github.io&#x2F;&quot;&gt;davidad&lt;&#x2F;a&gt;, I probably wouldn&#x27;t have figured it out, so here&#x27;s a quick guide to what I did for future reference.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;update-nasm&quot;&gt;Update nasm&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;nasm&lt;&#x2F;code&gt; is the command you&#x27;ll use to assemble assembly code. The default version on my computer was old and didn&#x27;t have the proper formats, so just I used &lt;a href=&quot;http:&#x2F;&#x2F;brew.sh&#x2F;&quot;&gt;homebrew&lt;&#x2F;a&gt; to update it by installing a newer version.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; brew install nasm
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After I closed and reopened my terminal, I got the new version of &lt;code&gt;nasm&lt;&#x2F;code&gt;, which had the critical &lt;code&gt;macho64&lt;&#x2F;code&gt; format.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; nasm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -v
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;NASM&lt;&#x2F;span&gt;&lt;span&gt; version 2.11 compiled on Mar  4 2014
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt; nasm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -hf
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;macho32&lt;&#x2F;span&gt;&lt;span&gt;   NeXTstep&#x2F;OpenStep&#x2F;Rhapsody&#x2F;Darwin&#x2F;MacOS X (i386) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt; files
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;macho64&lt;&#x2F;span&gt;&lt;span&gt;   NeXTstep&#x2F;OpenStep&#x2F;Rhapsody&#x2F;Darwin&#x2F;MacOS X (x86_64) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;object&lt;&#x2F;span&gt;&lt;span&gt; files
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;dbg&lt;&#x2F;span&gt;&lt;span&gt;       Trace of all info passed to output stage
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;an-example-assembly-file&quot;&gt;An Example Assembly File&lt;&#x2F;h2&gt;
&lt;p&gt;Stick this example assembly file in a &lt;code&gt;hello_world.asm&lt;&#x2F;code&gt; file in a new directory:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;asm&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-asm &quot;&gt;&lt;code class=&quot;language-asm&quot; data-lang=&quot;asm&quot;&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;%define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;SYSCALL_WRITE &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x2000004
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;%define &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;SYSCALL_EXIT  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0x2000001
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;global &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;start
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;start:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mov &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;1
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mov &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;rsi&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;str
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mov &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;rdx&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;strlen
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mov &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;SYSCALL_WRITE
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;syscall
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mov &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;rax&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;SYSCALL_EXIT
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;mov &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;rdi&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt;0
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;syscall
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;section &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;.data
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;db &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;`Hello&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;assembly!\n`&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt; ; to use escape sequences, use backticks
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;strlen &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f28779;&quot;&gt;equ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;$ &lt;&#x2F;span&gt;&lt;span&gt;- &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffa759;&quot;&gt;str
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It should print &lt;code&gt;hello, world&lt;&#x2F;code&gt;, and then exit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-nasm-and-ld&quot;&gt;Using nasm and ld&lt;&#x2F;h2&gt;
&lt;p&gt;To assemble your code, run:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sh&quot; style=&quot;background-color:#212733;color:#ccc9c2;&quot; class=&quot;language-sh &quot;&gt;&lt;code class=&quot;language-sh&quot; data-lang=&quot;sh&quot;&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Generate object file from assembly:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;nasm&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span&gt; macho64&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; hello_world.o hello_world.asm
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Link object file:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;ld&lt;&#x2F;span&gt;&lt;span&gt; hello_world.o&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffcc66;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; hello_world
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#5c6773;&quot;&gt;# Run executable:
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffd580;&quot;&gt;.&#x2F;hello_world
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all goes well, you should see &lt;code&gt;Hello, assembly!&lt;&#x2F;code&gt; appear in your terminal. Good work!&lt;&#x2F;p&gt;
</content>
  </entry>
</feed>
