<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Cyrus's Internet Journal]]></title><description><![CDATA[articles on work, and occasionally life]]></description><link>https://blog.cyrusroshan.com</link><generator>RSS for Node</generator><lastBuildDate>Sat, 08 Aug 2026 03:29:23 GMT</lastBuildDate><atom:link href="https://blog.cyrusroshan.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><item><title><![CDATA[The importance of examples]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s my first post on here. I wrote it before I ended up setting up my blog. I figured I had to start writing blog posts some point, and by writing my ideas on things as I encountered them, I&#x27;d remember my ideas better.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="inspiration" class="css-1oc01jt evim1t94">Inspiration:</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I started writing this after looking at <a href="https://developer.github.com/v3/repos/contents/">some GitHub API docs</a>, and not understanding how to read files from a private repo. I ended up looking around, realizing the answer after looking at a <a href="https://gist.github.com/Integralist/9482061">GitHub gist</a>, and thought I was an idiot for not realizing it sooner. But I realized that even if I was being an idiot, I had read the page and the OAuth page, and knew they needed to fit together somehow: all I needed was an example.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="do-we-really-need-examples" class="css-1oc01jt evim1t94">Do we really <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">need</em> examples?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When writing documentation for our own programs, we&#x27;re biased. Very biased. Not only do we know how to write code or use our software efficiently, but we also know exactly how it works the way it does and the processes it takes.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We sometimes even assume that our software is meant to be used in a specific way and will never be used in inefficient/impractical method X. Why? Because X is insecure, or X would never happen if documentation was followed, or there are more efficient tools than the one we&#x27;ve made, that are actually built for doing X.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="but-thats-not-always-the-case" class="css-1887rzz evim1t95">But that&#x27;s not always the case.</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Sometimes, or more often, almost always, the user won&#x27;t be reading all of the documentation. Maybe barely any of it. Or maybe the docs you wrote were bad, or incomplete, or assumed the user knew things they didn&#x27;t.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That&#x27;s what examples are for</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Examples at their most basic level are beginner friendly. For beginners, writing a program, and walking through it, explaining as you go, is more important and valuable than providing each function call along with a detailed desicription of what it does.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We all learn by being given examples. Like babies learn from hearing adults talk, we learn how to use a language, library, or framework, from seing well-structured, thought-out examples and their given or implied use cases. And babies babble before they learn to talk, just like we understand small bits of code before we understand a program as a whole. But sentence structure, proper word usage, etc., take much longer.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It&#x27;s clear that the solution is more frequent and more thorough examples. You don&#x27;t need to give five examples for every new concept you introduce. But you could.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="as-an-example" class="css-1oc01jt evim1t94">As an example...</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Since I&#x27;m writing about giving examples, it&#x27;s only fair that I give an example on how to give examples. I started out learning JS, and no other resource was as consistently thorough and complete in its documentation as the Mozilla Developer Network.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Consider for example, the ternary operator. It&#x27;s simple enough, if you&#x27;re used it multiple times. It&#x27;s just an if/else statement with a different return value on true/false. It&#x27;s dead simple, right? Not to all beginners. Ask a friend who&#x27;s just started programming if they can understand it and use it properly just by you explaining it to them. Chances are, they won&#x27;t.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you look at the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">MDN docs</a> on it though, it looks like 2/3 of the relevant words are examples alone. And half of the other words are explaining exactly what the examples are doing. This is great documentation, and it&#x27;s not because of just the description of the functional requirements, because you probably included something along those lines when you explained it. It&#x27;s the examples, the walkthrough of what the example does, the thoroughness of the examples, and the sheer number of them, which helps them cover so many use cases.</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/examples</link><guid isPermaLink="false">examples</guid><pubDate>Fri, 18 Dec 2015 10:16:16 GMT</pubDate></item><item><title><![CDATA[An intro to hackathons]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This isn&#x27;t just for people who haven&#x27;t gone to hackathons before, but also for people who went to one and had an underwhelming experience. Hackathons are all different, so don&#x27;t let one bad experience shy you away from them.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-are-they" class="css-1oc01jt evim1t94">What are they?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So you&#x27;re going to a hackathon. You&#x27;ve signed up, and you don&#x27;t know quite what it is, but you&#x27;re interested, maybe because you&#x27;ve heard good things about them or they sounded like fun. They&#x27;re all pretty similar in concept, but when I think of hackathons, I think of coroporate hackathons and collegiate hackathons.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="corporate-hackathons" class="css-1887rzz evim1t95">Corporate hackathons</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Corporate hackathons are generally smaller than collegiate hackathons. Both in size, and in time spent working. That&#x27;s not to say they&#x27;re bad, some of the ones I&#x27;ve been to have been better than some of the collegiate hackathons that I&#x27;ve been to, despite their size. These hackathons will generally be 50 people or less, and all the ones I&#x27;ve been to have been less than 24 hours, and they&#x27;ve also had participants go home for the night and come back in the morning. They also usually have no problem with providing enough food and snacks.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">They&#x27;re also much different from collegiate events in that professionals are allowed to these events, so you&#x27;ll most likely end up working with people from companies with local branches. If you&#x27;re around the Dallas area, the AT&amp;T Foundry usually hosts a few of these every year.
There are also larger corporate hackathons, which I can&#x27;t say too much about, as I haven&#x27;t been to more than a couple with much more than 50 people.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="collegiate-hackathons" class="css-1887rzz evim1t95">Collegiate hackathons</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Collegiate hackathons usually only allow current students to participate in them. If you&#x27;re in high school, they might require you to be above 18 as well. They usually give out more swag (read: goodies, so be prepared to carry lots back), and are generally either 24 hours or 48 hours. If you want to sleep, you&#x27;ll generally sleep on the floor. They usually have lots of sponsors, lots of prizes, and generally are much larger events overall.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Another difference is that while corporate hackathons usually have a theme (IoT, mobile apps, big data, etc.), collegiate hackathons usually don&#x27;t. They&#x27;re also almost always fully organized by college students, which is pretty impressive considering the huge amount of money that goes into them.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The rest of this post is about collegiate hackathons, but some of it can be applied to corporate hackathons as well.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-to-bring" class="css-1oc01jt evim1t94">What to bring?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I&#x27;m a hardware hacker, so I usually bring my own hardware, which I&#x27;ve written about more <a href="http://cyrusroshan.com/blog/2016/01/02/a-hardware-hackers-kit.html">over here</a>. I&#x27;ll also bring a day&#x27;s worth of clothes, my phone, wallet, device chargers, plane tickets, headphones (nice for listening on long flights), deodorant, shampoo, and toothpaste/toothbrush, all in one duffel bag. I&#x27;ll also bring a backpack with my hardware kit, laptop, and free space for free stuff. Feel free to bring resumes, as well, recruiters are there for a reason. It&#x27;s also a good idea to bring a blanket, or clothes warm enough comfortably to sleep in. I usually go with jeans/sweatpants and a hoodie.
(Side note: bring and use those toiletries. After a couple days without them you&#x27;re going to reek and that&#x27;s no fun. Also, shoutout to hackathons with showers, y&#x27;all are the best)</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-to-do" class="css-1oc01jt evim1t94">What to do?</h2>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="before-you-go" class="css-1887rzz evim1t95">Before you go</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, from the start, book your plane tickets early, arrive early (get there early and you get good spots), and make sure you have all your stuff packed the night before. It also helps to have a team and idea of what you&#x27;re going to work on before you get to the event. If you don&#x27;t, that&#x27;s fine too, there are almost always team-building events beforehand to help people who don&#x27;t have teammates connect and form a team.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="when-you-get-there" class="css-1887rzz evim1t95">When you get there</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Talk to the recruiters, don&#x27;t be afraid to ask questions or take the free stuff they&#x27;re giving out, a lot of the goodies they give out will be gone quickly. If you&#x27;re interested in a company, you can take time to talk to their recruiter, and give out a copy of your resume. For large hackathons I usually spend almost an hour at the beginning for just going through the booths, looking around, asking questions, and talking. Then, after the opening ceremony, it&#x27;s time to start working on your idea. At most collegiate hackathons, hardware checkout will open after the opening ceremony. If you want a big-ticket item to borrow from the hardware checkout, it&#x27;s best to get there early before it gets taken.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">While working on your hack, be sure to grab snacks and take some short breaks. Hackathons are usually very well stocked as far as snacks go, and they&#x27;ll often have events like smash tournaments, either set up by the hackathon organizers themselves or sponsoring companies. And while some people like to brag about how much sleep they didn&#x27;t get, getting a few hours of sleep can definitely help refresh you and give you a new mindset when tackling coding errors. On that note, don&#x27;t be afraid to ask for mentors if you&#x27;re having trouble.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In the final few hours before presenting, you&#x27;ll usually want to make sure that you upload your submission to whatever website the organizers are using, as well as make some finishing touches. You&#x27;ll usually be presenting expo-style, where you have an assigned table and judges come and walk through and look at everyone&#x27;s project like they would at a science fair. You&#x27;ll also usually have to pack up all of your stuff before you go to your table, and after presenting, head to the closing ceremony.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="where-to-find-them" class="css-1oc01jt evim1t94">Where to find them?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That&#x27;s all great, but where do you find out about hackathons? Look no further, <a href="http://www.hackalist.org/">hackalist</a> is my personal favorite for finding out about new hackathons I mean, you can sort by travel reimbursement, and it has them in order by month. This really only includes collegiate hackathons, though. If you want to find out about corporate hackathons, the best way I&#x27;ve found is by looking through EventBrite, asking around, or Googling.</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/hackathon-intro</link><guid isPermaLink="false">hackathon-intro</guid><pubDate>Thu, 31 Dec 2015 10:16:16 GMT</pubDate></item><item><title><![CDATA[A hardware hacker's kit]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So you&#x27;re a beginner to either hackathons or hardware hacking, and you&#x27;re not sure what to bring? Well, at HackDFW, we&#x27;ve got a pretty solid hardware setup, so you should have everything you need. At hackathons that aren&#x27;t as focused on hardware though, here&#x27;s an example list of what to bring. There&#x27;s also a section on helping you figure out which board to use for a project, and some cool hardware projects to inspire you.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You won&#x27;t need everything on this list; you&#x27;ll probably use less than a third of it for a single project, and you&#x27;ll probably have projects that might need something more than what I&#x27;ve listed. It&#x27;s always good to be prepared, though, and you can&#x27;t slap on another sensor in a hardware project as easily as you can download and require another library in a software project.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-youll-want" class="css-1oc01jt evim1t94">What you&#x27;ll want:</h2>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="basics" class="css-1887rzz evim1t95">Basics:</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here are some things that it&#x27;d be hard to really make a hardware project without:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Dev Board (an Arduino, Raspberry Pi, Photon, NodeMCU, etc.)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Cable (whichever your board needs)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Breadboard</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Jumper wires (optionally include alligator clips)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Resistors</li>
</ul>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="tools" class="css-1887rzz evim1t95">Tools:</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Some things that&#x27;ll make working with hardware a lot easier:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Needle nose pliers (with built in wire cutters)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Screwdrivers</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Superglue</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Electric tape</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Multimeter (this might be too bulky, I don&#x27;t always bring one)</li>
</ul>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="input-and-output" class="css-1887rzz evim1t95">Input and Output:</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You can&#x27;t do much with just the list of above items. You&#x27;ll need some of the following, depending on what you&#x27;re working on, to get a solid project.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="small-components" class="css-2md8qb evim1t96">Small components:</h4>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">These are smaller, more basic components, which aren&#x27;t mounted on a board of their own.</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">LEDs</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Photoresistors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Reflective IR</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">IR Transmitter/Reciever LEDs</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Transistors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Capacitors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Piezos</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Humidity sensor</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Temperature sensor</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Hall sensors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Vibration Motors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Tilt/vibration sensors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">DC Motors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Push button switches</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Flex sensors (a bit more expensive, I&#x27;d only get one)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Force sensitive resistors (same as above)</li>
</ul>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="larger-components" class="css-2md8qb evim1t96">Larger Components:</h4>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Servos</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Pulse sensor</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Ultrasonic range sensors</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Gyro/Accelerometer (usually have both on the same breakout board)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">LCD screen (preferably with I2C for less wires)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Bluetooth module (you&#x27;ll need one with BLE support for iPhones)</li>
</ul>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="additional-power" class="css-2md8qb evim1t96">Additional Power:</h4>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For powering your board or components that require more voltage</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Relay module</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Breadboard psu</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">9v Batteries (not for your dev board, for powering a motor that needs more than it can handle. Use with transistor to switch on/off)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Rechargeable power bank (for when you want to power your dev board without having it hooked to your laptop)</li>
</ul>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="where-to-get-them" class="css-1oc01jt evim1t94">Where to get them?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So now that you know what to get, where do you get it? If you&#x27;re looking for reliability, use <a href="http://www.amazon.com/">Amazon</a>, <a href="https://www.adafruit.com/">Adafruit</a>, or my favorite of the three (because of their nice guides and docs), <a href="https://www.sparkfun.com/">Sparkfun</a>. If you&#x27;re looking to save money (and it does cost a decent amount), check out <a href="http://www.aliexpress.com/">Aliexpress</a> for components, and your local dollar tree for superglue/electric tape/pliers/etc.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="which-board-to-use" class="css-1oc01jt evim1t94">Which board to use?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, each board is useful for different things. For this, I&#x27;m just going to be comparing the three most popular: Arduino UNO, Raspberry Pi 2, and Particle Photon.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">There are a few factors that I consider when picking a board:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Setup time</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Usage</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Language</li>
</ul>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="setup-time" class="css-1887rzz evim1t95">Setup Time:</h3>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A Raspi has a decent setup time. You need to be able to set it up to ssh into it, which means you&#x27;ll need an OS on an SD card, the necessary cables, and a monitor/keyboard/mouse to be able to use it. If you&#x27;ve already set it up before, though, you can just bring it with an ethernet cable (you&#x27;ll need an ethernet to thunderbolt adapter for macs though). If you&#x27;re renting one out, though, that&#x27;s not really an option.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">An Uno is generally plug and play, so setup time is nil</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Photons are pretty nice, <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">if</em> you aren&#x27;t in a saturated wireless airspace. The problem is, a lot of hackathons are. There&#x27;s a solution to this, though, which is using serial setup. Particle uses the node-serial package though, so if that gets a bit funky (like it did with the El Capitan update on OS X), then you won&#x27;t be having any fun.</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Basically, for setup time, Uno &gt; Photon &gt; Raspi.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="usage" class="css-1887rzz evim1t95">Usage:</h3>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A Raspi can do a lot of stuff, should be able to handle a lot, but it has some trouble with analog input. You can solve that with an analog to digital converter, or by having an arduino as a go-between. I&#x27;d use Raspi for anything where you want a small, local server, where you can directly interface with hardware. However, in a hackathon setup, an Uno or Photon can do almost everything, if not more, with the right libraries, so it generally comes down to preference.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">An Uno can do everything a Photon can do, but it lacks wireless connectivity. However, you can use a node package such as <a href="https://github.com/voodootikigod/node-serialport">node-serial</a> or <a href="https://github.com/rwaldron/johnny-five">johnny-five</a> (the latter also uses node-serial, but check it out as well) to interface with your computer while it&#x27;s connected over USB, which opens up so many options (and also makes the Uno my go-to board). This does, however, make your setup a bit more complicated, if you&#x27;re using it for the first time.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A Photon can do everything an arduino can do, but with less ports, less libraries, and less guides. It makes up for that, though, with its incredibly easy setup <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">(when it works)</em>, and Particle&#x27;s servers, which you can use as a limited backend. It also has a smaller form factor, if that matters in your application.</li>
</ul>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="language" class="css-1887rzz evim1t95">Language:</h3>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A Raspi is basically a full computer, soooo you can do pretty much anything. Most people perfer python on it, though.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">An Uno can be programmed with C/C++, however, if you use something like <a href="http://pyserial.sourceforge.net/">pySerial</a> or <a href="https://github.com/voodootikigod/node-serialport">node-serial</a>, you can write python or javascript programs to communicate with the arduino on your computer, and even just use it as a data-collector if you want (which, out of the three devices, it&#x27;s the best at). There&#x27;s also <a href="https://github.com/rwaldron/johnny-five">johnny-five</a>, if you want to use literally nothing but javascript (these options require the arduino to be tethered to the computer via USB for them to work).</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A Photon can be programmed with C/C++, however, you can just send and recieve the data to and from Particle&#x27;s servers, have all of the benefits of node-serial/pyserial, except just using REST and any server, so it doesn&#x27;t even need to be local.</li>
</ul>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="some-cool-hardware-projects" class="css-1oc01jt evim1t94">Some cool hardware projects!</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you&#x27;re looking for inspiration, here are a few hardware projects to check out:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="https://dheera.net/projects/sesame">Sesame</a>, which lets you remotely unlock your door via a smartwatch voice command.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="https://www.reddit.com/r/arduino/comments/3ygf5s/i_made_a_mini_handheld_tetris_console/">A simple tetris game</a>, amazingly small, powered with a LiPo battery, and controlled with push buttons.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="http://devpost.com/software/brailleware">FifthSense</a>, a tool to for blind people to send and recieve data. Uses buttons for input, vibration motors for output.</li>
</ul></div>]]></description><link>https://blog.cyrusroshan.com/post//post/hardware-hackers-kit</link><guid isPermaLink="false">hardware-hackers-kit</guid><pubDate>Sat, 02 Jan 2016 10:16:16 GMT</pubDate></item><item><title><![CDATA[Making a 3d scanner for under $20]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At this Spring&#x27;s HackPrinceton, my friend <a href="http://yarabarla.com/">AK</a> and I built a fast and efficient 3d scanner out of spare parts. I think it&#x27;s very cool.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<iframe title="YouTube video player" width="480" height="300" src="https://www.youtube.com/embed/6dSABwcAYv8?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">The final product. The slower the motors run, the more accurate the scan.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Both the <a href="http://www.devpost.com/software/spin-to-win">project submission</a> and the <a href="https://github.com/CyrusRoshan/Spin-to-Win">source code</a> are online.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="how-does-it-work" class="css-1oc01jt evim1t94">How does it work?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For measurement, we used a reflective IR LED. More detail on this later, but basically I&#x27;m using it here as a close-range distance measurement tool.</p>
<!-- -->
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In order to measure a 3d surface, two other components come into play, each adding a separate dimension to the scan. The first is a vertical shaft which raises and lowers the reflective IR LED. The second is a DC motor, which rotates the scanned object, allowing the scanner to measure its sides.</p>
<!-- -->
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="scan-accuracy" class="css-1oc01jt evim1t94">Scan accuracy</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You&#x27;re probably wondering how accurate this project&#x27;s scans actually were. It&#x27;s literally a <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">ten-cent RIR LED on a stick</em>, held together by cardboard.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I wondered that too, as we were building it. I hadn&#x27;t seen examples of reflective IR LEDs being used for measuring distance before. And even though it showed promising results when I tested it before starting, I couldn&#x27;t be sure how accurate it was, given that the data was definitely not a linear function of distance.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/spin-to-win/images/papercone.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">A scan of a paper cone</span></div></span></div>
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11">
<img src="/images/post/spin-to-win/images/paperconewithhand.png" class="css-1k43lf1 ef55ps60"/>
</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">The same paper cone, but a judge we were demoing to wanted to wave his hand between the cone and the scanner for a bit while it was running.</span></div></span></div>
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11">
<img src="/images/post/spin-to-win/images/papercylinder.png" class="css-1k43lf1 ef55ps60"/>
</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">A scan of a slightly deformed paper cylinder.</span></div></span></div>
</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">Some example scans generated when plotting the raw data through Wolfram</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">As it turns out, the scans were <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">pretty darn accurate</em>. In fact they were so clean, we had a judge doubt that the data was live. He waved his hand in between to see, and you can see the results above (middle picture, compared to the original on left).</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="is-it-really-under-20" class="css-1oc01jt evim1t94">Is it really under $20?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Yup. I source most of my electronics from Aliexpress, so that helps. Here&#x27;s the breakdown:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Reflective IR LED - 10 cents</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">DC motor - $3</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Breadboard - $3</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Continuous rotation servo - $7</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Arduino clone - $3 to $10</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">USB A Male &lt;-&gt; USB B Male adapter - Free (usually included with the Arduino, even cheap ones)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Plastic gears - $3 for a bag, probably $0.20 for parts used</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Cardboard - Free</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Electrical tape, wires, resistors - around $2 worth of parts</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And this isn&#x27;t even pricing at scale, or with efficient use of parts (e.g. using a PCB instead of breadboard + wires).</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="ideation-process" class="css-1oc01jt evim1t94">Ideation process</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Akhilesh and I flew into Philadelphia early, so we went to a Public Library to kill time before the hackathon started. He goes to the bathroom, and comes out wondering how hard it&#x27;d be to scan his poop. I look at my kit and see if we have the parts. And here we are.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="prototype-process" class="css-1oc01jt evim1t94">Prototype process</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After some fairly basic tests, I decided that a Reflective IR LED was probably our best bet as a scanner. Our alternative was an ultrasonic rangefinder, and I didn&#x27;t think it&#x27;d have enough granularity at low distances to work as a close-range 3d scanner.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Next, we needed to move the object or the scanner such that the entire object could be scanned. We focused on the vertical dimension first. I tried using a pulley-like system with a DC motor, and of course without a smooth pulley it&#x27;d occasionally slow or snag, and we couldn&#x27;t get a consistent speed.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Looking for an alternative, I looked in my tackle box of hardware and found a rack to use in a rack and pinion gearing, and that actually worked perfectly, once we secured it into place. I attached the RIR LED, and also put a cylinder of electrical tape on it to try and make it pick up less noise, which actually worked pretty well.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<iframe title="YouTube video player" height="300" src="https://www.youtube.com/embed/fmdrBJvw8gc?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Testing out the rack-and-pinion gearing for vertical scanner movement</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Then we tried making a flat base and attaching it to a dc motor. We first tried taping a few pieces of cardboard together and using the hole in a zip tie to attach it to the dc motor and hold it in place. It didn&#x27;t work; it ended up too wobbly to actually get any decent measurements on, though.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<iframe title="YouTube video player" height="300" src="https://www.youtube.com/embed/kzbxL6kLE_0?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Rotating the base was the easiest way to get an even scan, but attaching the base wasn&#x27;t easy.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We were lucky, though: the dc motor I used had basically the exact same diameter as one of the gears in the gear set, so we were able to tape cardboard circles to the gear in order to provide a larger base, and this gave us less wobble than our earlier design.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<iframe title="YouTube video player" height="300" src="https://www.youtube.com/embed/jmB9qMBHB-o?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Fairly stable and ready to scan!</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Once we got this working, we also needed to hold the rack and pinion together using a bunch of zip ties, cardboard, and duct tape. The motor also broke apart a couple times, requiring the metal inside to be repositioned. And of course, we needed to calibrate everything, to get near-usable results!</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="calibration-process" class="css-1oc01jt evim1t94">Calibration process</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In this process, we figured out a function to convert the Reflective IR LED&#x27;s raw analog output to units of distance. We also figured out the function to get vertical distance (vertical scanner movement) and degrees of rotation (horizontal base rotation) as a function of time.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Figuring out position of the z-axis was simple, we just measured the distance/time to get the speed of the motor when moving vertically, which given the initial value of 0 (measuring starting at the object&#x27;s base), gives the z position as a function of time.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To find the angle of rotation, I measured the length of time it took for 10 rotations (to reduce error from starting/stopping time) and divided by 10.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To find the distance from the object to the scanner, we needed to fit the data given by the reflective IR LEDs. And for that we needed some data points to get a curve best fit. Using Chrome dev tools as a substitute for a ruler, I recorded the scanner&#x27;s analog output values, while moving a piece of cardboard away, centimeter by centimeter.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">With this data, we were able to estimate the function best fit using Wolfram alpha:</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">$$$ f(x) = -600 + \frac{19169 \times x}{30} + \frac{30433 x^2}{360} - \frac{1751 x^3}{16} + \frac{4009 x^4}{144} - \frac{727 x^5}{240} + \frac{89 x^6}{720} $$$</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Glad we didn&#x27;t have to calculate that by hand. Unfortunately Wolfram didn&#x27;t give us the inverse, which we needed (in a scan, we have raw analog values and want estimated distance). So I just plugged in the range of input values, which is a limited range of ints (0-2048), and made a lookup table instead.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Combining these functions, we were able to determine y/z coordinates given distance and time. (Remember, our scanner rotates and moves up at the same time, so it&#x27;s moving in a spiral shape.)</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And with this, we could generate point clouds (seen above in earlier sections)! From this, you can estimate the shape of the object, and generate a STL file to send to your 3d printer, in order to print the object you just scanned!</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="want-to-build-it-yourself" class="css-1oc01jt evim1t94">Want to build it yourself?</h2>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="caveats" class="css-1oc01jt evim1t94">Caveats</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Want to build this on your own? It&#x27;s very cool, and very cheap! But if you&#x27;re planning on using it for anything serious, note a couple caveats:</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You&#x27;ll probably need 3d-printed parts for it to be calibrated well. (Though it&#x27;s fun project to make by hand though, and the experience and results were pretty rewarding.) It&#x27;s also not that great at scanning anything too glossy (shiny plastic/metal).</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="details-you-might-find-useful" class="css-1oc01jt evim1t94">Details you might find useful</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">All data is passed via USB from the Arduino to the laptop, where all of the processing is done in Node. It&#x27;s much faster that way, and you can do whatever you want with it from there.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Data is sent from the Node instance to the Wolfram notebook through.... the wondrous OS X clipboard (last minute features, what can I say). It takes a long time for Wolfram Notebook to graph the data, but I think it&#x27;s just slow frontend javascript, not optimized for large datasets. It might be faster on other software.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I don&#x27;t have any good pictures of the circuit, but the only complicated part is wiring the Reflective IR LEDs, which you can do like this:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/spin-to-win/images/tcrt.jpg" alt="Example TCRT5000 breadboard layout" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">The circuit we used was something like this one</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Thankfully no signal amplifiers are needed (I didn&#x27;t have any), and the wiring for the servos and dc motor are also pretty standard. Have fun!</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/spin-to-win</link><guid isPermaLink="false">spin-to-win</guid><pubDate>Tue, 05 Apr 2016 10:16:16 GMT</pubDate></item><item><title><![CDATA[Building an electronic banjo out of paper plates]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This weekend at HackPrinceton, my teammate <a href="http://bearcott.com">Benny Yan</a> and I made a <a href="https://devpost.com/software/electric-boogaloo-6vuwx0">prizewinning</a> electronic banjo. It&#x27;s not an <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">electric</em> (amplified) banjo. The difference is when you hold down frets and strum strings, the sounds it plays are mp3 files, not amplified string vibrations.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/electronic-banjo/images/frontendFinal.jpg" class="css-1k43lf1 ef55ps60"/></div>
<div><img src="/images/post/electronic-banjo/images/hardwareFinal.jpg" class="css-1k43lf1 ef55ps60"/></div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Final software and hardware, side by side</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In addition, there are LEDs under the fretboard that light up to show you where to place your fingers (in our demo, we showed chord positions, but I have a few other ideas for it that I think would be cool). We also had a nicely designed UI that you could use to show which strings and frets were being pressed down, as well as selecting chords to view and have displayed on the banjo&#x27;s fretboard, and a list of songs to go through and show chords and lyrics for in realtime.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div><video controls=""><source src="/images/post/electronic-banjo/images/finalDemo.mp4" type="video/mp4"/> Your browser does not support the video tag </video></div>
<div><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/electronic-banjo/images/1479053512277.jpg" class="css-1k43lf1 ef55ps60"/></div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">A very short demo that shows frets lighting up and being pressed</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Before I get into it though, I&#x27;d like to thank the HackPrinceton organizing team, especially all of the hardware lab mentors. Those guys are some of the nicest people I&#x27;ve met, and I&#x27;d probably have either spent an extra 5+ hours debugging hardware or just not been able to finish without their help debugging two hardware bugs.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-we-used" class="css-1oc01jt evim1t94">What we used</h2>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Frontend:
<ul>
<li class="css-1650jxb e1mpr5v80">React</li>
<li class="css-1650jxb e1mpr5v80">Babel</li>
<li class="css-1650jxb e1mpr5v80">SASS</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Backend:
<ul>
<li class="css-1650jxb e1mpr5v80">Go</li>
<li class="css-1650jxb e1mpr5v80">gin-gonic/gin</li>
<li class="css-1650jxb e1mpr5v80">tarm/serial</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Hardware:
<ul>
<li class="css-1650jxb e1mpr5v80">Electronics:
<ul>
<li class="css-1650jxb e1mpr5v80">Arduino Uno x2</li>
<li class="css-1650jxb e1mpr5v80">White LED x12</li>
<li class="css-1650jxb e1mpr5v80">1k Resistors</li>
</ul>
</li>
<li class="css-1650jxb e1mpr5v80">Materials:
<ul>
<li class="css-1650jxb e1mpr5v80">Wire (lots)</li>
<li class="css-1650jxb e1mpr5v80">Paper clips (brass plated)</li>
<li class="css-1650jxb e1mpr5v80">Paper plates</li>
<li class="css-1650jxb e1mpr5v80">Cardboard</li>
<li class="css-1650jxb e1mpr5v80">Springs</li>
<li class="css-1650jxb e1mpr5v80">Foam</li>
</ul>
</li>
</ul>
</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">There&#x27;s not a whole lot of complicated electronics here, and realistically you could probably use one arduino mega instead of two unos. Most of the time I spent on this was painstakingly soldering everything together, placing all of the layers down precisely, hardware debugging (encountered the weirdest hardware bug I&#x27;ve seen yet), and figuring how to orient everything properly (springs, clips, wires). The backend code itself was written pretty last minute, which looking back on it, could have gone pretty badly, but thankfully it ended up working out.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="how-we-made-it" class="css-1oc01jt evim1t94">How we made it</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I worked on the hardware and backend, and had very little to do with the frontend, which Benny made, but here are the steps I took for the hardware:</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">First, it was important to have an idea for how the fretboard worked. There are a few ways to do a fretboard which immediately come to mind, but the way we finally implemented it was by far the best way to do it in my opinion. I have a lot of projects that I&#x27;ve done with reflective IR LEDs, so at first I thought of using those as a range finder since we could use those to find the range on small instruments (7cm from a uke or banjo head is a decent amount for demo purposes) or to use a system with force or light sensitive resistors under each fret, but these methods all have issues with emulating how a real string instrument would have its audio affected.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I ended up going with a system with much less complicated components. Simply using 4 strings with 5v out and different resistances on each string (not grounded), and having each metal fret piece connected to an analog input pin on the arduino means that you get lifelike and accurate strings. Based on which analog pin you&#x27;re reading from, you can figure out the fret number, and based on what the voltage reading is, you can figure out which combination of strings is being pressed. It&#x27;s also very accurate in how it works compared to a real string instrument because the way this reads string/fret combos is by the string being touched to the fret, which (aside from a few techniques), is how notes are normally played on string instruments.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/electronic-banjo/images/fretWiring.jpg" class="css-1k43lf1 ef55ps60"/></div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">The wiring for the neck—each string has a different resistance, and each fret measures voltage independently, allowing multiple string-fret combos to be read without conflict.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So after hashing out how I wanted the frets to work (since without the frets, there&#x27;s not a whole lot you can do) I moved on to making the strings for detecting strumming. I first tried reading analog input on all of the strings and putting 5v through a wristband on my hand, but it&#x27;s much easier to reverse that and put 5v through all of the strings and ground my hand, since my hand isn&#x27;t very conductive. This is pretty similar to how a makey-makey works, actually. I used a 1k pulldown resistor and analog input, since I was going to need two arduinos for this project anyways, but you could change the resistor value and use digital pins instead.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/electronic-banjo/images/stringWiring.jpg" class="css-1k43lf1 ef55ps60"/></div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">The wiring for the strumming side. This one&#x27;s a bit more simple, it just checks if I&#x27;ve touched a string.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The fretboard was made by first hollowing out the space for the LEDs on two layers of cardboard, inserting them, and placing a cut sheet of paper plate on top (Benny did this), then the LEDs had to be wired up, cut, soldered, covered with electrical tape, and the next layer (frets) had to be added, cut, soldered, wired, then the strings on top of those had to be added, cut and soldered and wired to the arduino as well. I&#x27;m not the quickest, so at one point I spent 4 hrs straight just cutting, taping, and soldering wires.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/electronic-banjo/images/wiringLEDs.jpg" class="css-1k43lf1 ef55ps60"/></div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">It took hours to solder LEDs, layer frets, and connect it all to the arduino without breaking any wiring.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">During this time, I was also testing the wires to make sure I didn&#x27;t miswire something before soldering. At one point I taped all of the thin LED wires (that took up less space on the fretboard) to the thicker ones that would go inside the arduino pins after twisting them together, and had to untape, solder, and tape again, since they would lose connections at some angles after being taped. So there were a few other things that took up some time.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="the-code" class="css-1oc01jt evim1t94">The code</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I didn&#x27;t write any of the frontend code, but basically how it works is the frontend continuously sends a GET request to the server to get which strings/frets to highlight on the webapp, and sends a POST request telling the server what LEDs to light up when it wants to light up the fretboard. This allows you to do things like select different chords and have them displayed on the banjo in realtime, as well as showing the tab for the chord on the screen. There was also a feature for playing songs and having the webapp show the user which chords and lyrics to use in realtime.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Benny&#x27;s design and frontend code were nice and polished; the backend on the other hand, was incredibly rushed. The arduino files were written as I went and weren&#x27;t too bad since I had to write them to test the code. The server itself however, was written pretty quickly, and I would reccomend restructuring large amounts of it if you&#x27;re going to actually use it. It basically opens up one serial connection to the fretboard uke, one to the string uke, and starts reading in data and parsing it as JSON. The server&#x27;s running at the same time in a goroutine and basically just serves up the last read data, formatted properly into JSON for GET requests, and for POST requests, simply writes the correct LED to light up to the fretboard arduino over serial.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The wonky part is the math used to calculate which frets are being played. It was getting pretty close to presentations, so I used some hackathon quality logic to go with my hackathon quality code, and didn&#x27;t bother using math to calculate which string combination would create which analog value on the fretboard. I ended up just getting a few combinations of frets (e.g. 0, 1, 2, 3, 01, 12, 23, 012, 123, 0123), manually pressing those down, getting an approximate value, and giving it a short range around that, and just checking which range a fret read in, and seeing if it was in one of those ranges. As a consequence, since I forgot 03 as a combo, holding down the top and bottom strings on a single fret worked, but I don&#x27;t think we even thought to test that, it was more like testing the first fret on the first string and the third fret on the fourth string, so it worked out all right.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="the-results" class="css-1oc01jt evim1t94">The results</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We presented pretty well to the judges prior to the closing ceremony, and HackPrinceton actually had a private judging prior to the closing ceremony, so the results were decided before we went on stage, and we did well in that. For the closing ceremony though, we had 2 minutes to present, went on stage, immediately tangled wires with the hdmi, usb, etc., wires on stage, took about a minute to plug in the hdmi, and fumbled through that presentation so badly that if we were judged based off of that, we wouldn&#x27;t be finalists. We ended up doing pretty well though, Benny won us the best design prize, I won us the best DIY prize, and together we got best overall. A great ending to HackPrinceton part 2: Electric Boogaloo.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="the-weirdest-bug-ever" class="css-1oc01jt evim1t94">The weirdest bug ever</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So while I was working on wiring the fretboard, I was also testing the wires to make sure I didn&#x27;t have to undo the whole thing after I was done and realized I made an error. After I got to the stage where I put the LEDs on, connected them to a single ground, wired the positive ends up to individual thin wires into individual thin wires into the digital ports on the fretboard arduino, I moved on to the frets themselves. I placed a layer of electrical tape on the wire, and added the paper clips, which went on the front of the neck and wrapped around to the back, and actually looked pretty solid as frets. When reading input from the frets, however, it turned out that all three frets gave nearly the same reading... (nearly the same reading as opposed to exactly the same reading, I assume because of the built in delay on analogread).</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div>
<video width="100%" controls="">
<source src="/images/post/electronic-banjo/images/wiredFrets.mp4" type="video/mp4"/>
Your browser does not support the video tag.
</video>
</div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Quickly testing all the LEDs after wiring them.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After <del>some</del> lots of hardware debugging, it turned out that the three frets were grounded together... through the wire that grounded the LEDs. That wouldn&#x27;t be so crazy, except each fret had a layer of electrical tape covering it entirely from the LEDs and their wires. Adding two more layers of tape did the trick, so I can only assume that a combination of the tape being on the thinner side, being stretched, and firmly pressed (the paper clips held on pretty tightly to the neck) caused a leak.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="future-ideas" class="css-1oc01jt evim1t94">Future Ideas</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here are a few ideas that I had thought of while making this project. Keep in mind that these are untested, and I&#x27;m just a CS major who does hardware at hackathons, so these might not be 100% accurate in implementation. These were ideas I discarded because I knew we didn&#x27;t have the materials/time, and they were plans for muting the strings and using springs for analog strums.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Muting strings is a pretty big thing in playing guitar, and probably also in banjo playing, and it&#x27;s where you put your finger on top of a string and press gently but not hard enough to touch the string to the fret. As a result, you dampen the strings by causing almost all of the vibrations to travel through you. This would be checked for by checking the voltage that comes through the other side of the string. You could probably check for this by grounding yourself, and also reading in voltage from the end of the strings on the neck of the banjo. Then the strings you were touching would have different values than the ones that didn&#x27;t. You&#x27;d also be grounded if you were touching the strings to push them down to the frets, but you&#x27;d know that they were pushed to the frets, and there wouldn&#x27;t be any scenarios where they&#x27;d be pushed to a fret but not touched.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For using analog strums (e.g. to know how loud to play an mp3 based on the strength of the strumming), using something similar to how an electric guitar works would probably be the best method. Placing pickups under strings would allow you to see if the string was being pulled up or down, and how much, based on the motion of the magnetic field generated, and the resulting current that would go to the amp (or in this case the voltage-reading analog inputs on the arduino, since v = ir). You could alternatively attach springs to the very end of the strings, and use a hall sensor to determine the change in magnetic field caused by the spring&#x27;s expansion and contraction. Again, these are untested, so they may not work exactly how I describe.</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/electronic-banjo</link><guid isPermaLink="false">electronic-banjo</guid><pubDate>Tue, 15 Nov 2016 10:16:16 GMT</pubDate></item><item><title><![CDATA[Why I built the wrong blog publishing workflow]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I used to find writing for a public audience to be a taxing process. <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">I wasn&#x27;t sure why</em>, but I thought it might be because my workflow was bad. To tackle that, I built a small project. I hoped it&#x27;d be an end to my writing troubles.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This post goes over how I built that project (it is kind of a cool project). But it also goes over <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">why it was the wrong solution.</strong></p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="misdiagnosing-the-root-issue" class="css-1oc01jt evim1t94">Misdiagnosing the root issue</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To decide what I &quot;needed&quot; to build, I started by comparing workflows: I looked at the way I wanted to write, and contrasted it to the way I <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">did</em> write.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">My previous workflow had me spend a lot of time in my text editor. Which I thought was bad for writing, because when I&#x27;d start writing, I&#x27;d try live previewing my blog, and only an hour later realize I was knee deep in minor CSS changes.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So I thought it was the <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">text editor</em> that made it easy to get off-track. I wanted a simpler workflow. And I was actually so fed up with my previous workflow, I wanted to cut my laptop out entirely. <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">I wanted to write and publish posts just using my phone.</strong></p>
<note type="thought">
What a mistaken conclusion. Looking back, _the text editor itself wasn&#x27;t my problem_. I was just uncomfortable writing about something I was unsure of to a public audience. So changing how my blog looked was easy, but _writing carefully thought-out content and exposing it to public judgement_ was hard.
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, much like I&#x27;d procrastinate large projects in college, I wound up procrastinating writing by cleaning up my blog&#x27;s styling.
</p>
<style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="over-engineering-the-technical-solution" class="css-1oc01jt evim1t94">Over-engineering the technical solution</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">On my laptop, after I wrote a post in Markdown, I would:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">build my blog using Hugo</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">git push</code> changes to Github</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">which then deployed the contents of the <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">docs</code> folder via Github Pages</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I decided that to deploy from mobile, I would make a Lambda that did the same thing as my laptop. Meaning that after I wrote the post on my phone, I would:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">send it to the AWS Lambda</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">which would then <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">git clone</code> my blog repo</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">then insert the post, build the repo using Hugo, commit the changes</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">and <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">git push</code> changes to Github</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">which would then deploy the contents of the <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">docs</code> folder via Github Pages</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This meant that the Lambda would need to run Hugo and Git. Naturally, instead of adding a small amount of vendor lock-in with <a href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html">AWS Lambda Layers</a> to manage binary dependencies, I opted for a <a href="https://github.com/grycap/scar">mostly-academic seeming library</a> to run Docker in a Lambda. I&#x27;m ashamed of how long it took me to get all this working.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">(Note: There&#x27;s also AWS&#x27;s <a href="https://github.com/awslabs/aws-lambda-container-image-converter">img2lambda</a>, to convert Docker images to Lambda layers, but it didn&#x27;t work in this case)</p>
<note type="thought">
An interesting thing I noticed in retrospect: When I build projects for work, I tend to start with the absolute minimum, look for existing solutions before building them on my own, and use well-tested dependencies. But for side projects, I do the opposite.
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I don&#x27;t think this is a bad behavior, actually, because it lets me try out more risky decisions in a safe environment. But it does mean that I shouldn&#x27;t expect the same results.
</p>
<style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="the-architecture" class="css-1oc01jt evim1t94">The architecture</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So the architecture I built had three parts:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A text editing app of my choice, to draft the post
<ul>
<li class="css-1650jxb e1mpr5v80">This app was just for me to edit posts on. Any app would work, as long as it could export plain text. I chose <a href="https://apps.apple.com/app/id775737172?ign-mpt=uo%3D4">iA writer</a> because it had nice markdown preview support.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">An AWS Lambda function, which published the post
<ul>
<li class="css-1650jxb e1mpr5v80">The most important part of this project. <a href="https://github.com/CyrusRoshan/blog-lambda">Source code</a> is here.</li>
<li class="css-1650jxb e1mpr5v80">I wanted to use a serverless platform, because I felt the frequency of my posts didn&#x27;t merit a full-time server.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">An iOS shortcut, which took the post from the app and sent it to the Lambda
<ul>
<li class="css-1650jxb e1mpr5v80">I think iOS shortcuts are underrated, specifically for simple ETL tasks like this. <a href="https://www.icloud.com/shortcuts/185164a491484e5db3dfa769510fe614">Source code</a> is here (only viewable on iOS).</li>
</ul>
</li>
</ul>
<style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="the-results" class="css-1oc01jt evim1t94">The Results</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And this is what my new workflow looked like, from start to finish. I could write a post, export it to the shortcut, which would send it to the Lambda function, which would publish it.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/iWOOQtYB1rE?rel=0&amp;modestbranding=1" frameBorder="0" allow="autoplay; encrypted-media; picture-in-picture" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">The full publishing workflow, with the Lambda doing a cold start</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But while it looked nice, it didn&#x27;t address my problems. Months went by before I felt I could publish this very post. When I finally edited it, I realized why it took so long to publish. And so I changed this post from a longer technical overview, to a shorter commentary on where I went wrong.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I still have a mobile post pipeline, but it doesn&#x27;t look like this. It&#x27;s just <a href="https://workingcopyapp.com/">git app</a> for iOS, and a <a href="https://github.com/peaceiris/actions-hugo">Github action</a>. I didn&#x27;t write anything more complicated than a config file to use it.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But more importantly, I pushed myself to address the issues. I didn&#x27;t like how my blog looked—so I made it look clean and scale well on mobile. I was worried about presenting my opinion—so I took time writing my opinions before subjecting them to judgement. I didn&#x27;t have enough time to write—so I set aside a full day for a post, instead of a couple hours.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So that&#x27;s a start. Now, I&#x27;ll have to keep writing to turn these behaviors into habits.</p></note></note></div>]]></description><link>https://blog.cyrusroshan.com/post//post/hugo-in-a-lambda</link><guid isPermaLink="false">hugo-in-a-lambda</guid><pubDate>Sun, 14 Jun 2020 00:00:00 GMT</pubDate></item><item><title><![CDATA[My home infrastructure setup with Ansible]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Having a home server has many benefits:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Spotify-connected speakers 🔈</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">wifi printing 🖨</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">automated laptop backups over wifi 💿</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">and more! 😱</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And you might find this useful, when you have:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">unused speakers</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">a wired, usb-only printer</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">and a laptop that hasn&#x27;t been backed up in a year</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And I did. And I had an unused Raspberry Pi I could use as a home server. But I kept procrastinating on setting it up.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Because I knew that <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">not only</em> did I have to do a lot of initial configuration, I&#x27;d have to <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">repeat the entire process</strong> if my server&#x27;s storage failed. And Paspberry Pis use SD cards, which have a reputation for higher failure rates.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Of course, there are software solutions to this. They&#x27;re all some form of configuration and deployment, and I&#x27;d loosely categorize them into three areas:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Push-based systems
<ul>
<li class="css-1650jxb e1mpr5v80"><a href="https://docs.ansible.com/ansible/latest/index.html">Ansible</a></li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Pull-based systems
<ul>
<li class="css-1650jxb e1mpr5v80"><a href="https://docs.chef.io/">Chef</a>, <a href="https://docs.ansible.com/ansible/latest/cli/ansible-pull.html">ansible-pull</a> <a href="https://docs.ansible.com/ansible/latest/index.html">(example)</a></li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Docker-based, pull-based systems
<ul>
<li class="css-1650jxb e1mpr5v80"><a href="https://www.balena.io/">Balena</a>, <a href="https://deviceplane.com/">Deviceplane</a></li>
</ul>
</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Each has their merits, and these are just a subset of the tools that exist.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For my home setup, I opted for Ansible. I did this because I:</p>
<ol type="a">
  <style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">don&#x27;t want to host anything</li>
  <style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">want a fairly simple solution</li>
  <style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">can easily change Ansible to ansible-pull, if I want devices to pull updates from a git repo</li>
  <style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">don&#x27;t care about docker—I won&#x27;t be using a variety of architectures or OSes (I just have a few Pis)</li>
  <style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">can easily figure out the IP of all of my Pis and connect to them directly (a requirement, for Ansible)</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This solved my problems, and even though though it took a bit of extra time to set things up with Ansible, it was maybe 2-3x the time it&#x27;d take me to run the plain bash commands. And setting up my second Raspberry Pi was much faster as a result.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">My config sets up the following:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">SSH via your public key instead of password</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">ZSH/ohmyzsh set up with Agnoster as the default theme when you SSH in</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Spotifyd set up (just plug in a speaker and you&#x27;ve got Wifi speakers)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Hostnames match your pi&#x27;s inventory name</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And I&#x27;ve made it open source. <a href="https://github.com/CyrusRoshan/personal-pi">Here it is on Github</a>, feel free to fork it for your personal setup.</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/home-infra-with-ansible</link><guid isPermaLink="false">home-infra-with-ansible</guid><pubDate>Sat, 24 Oct 2020 00:00:00 GMT</pubDate></item><item><title><![CDATA[Two cable SSH: the fastest Raspberry Pi setup]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Fiddling with monitors is annoying. This method lets you get an SSH connection to your Pi without having to connect it to a monitor, find an external keyboard, or manually type in your wifi password.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img width="70%" src="/images/post/two-cable-ssh/images/setup.jpg" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Simple and portable enough that you could do the entire process at a cafe</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Taking out the manual process and sending everything over the wire makes it much easier to automate initial config, and I found it very useful when setting up <a href="../home-infra-with-ansible">my home servers with Ansible</a>.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="the-two-cable-ssh" class="css-1oc01jt evim1t94">The two-cable SSH</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s how to do it with a macOS host:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Start with a copy of Raspbian on your SD card. You can install the <a href="https://www.raspberrypi.org/documentation/installation/installing-images/">Raspberry Pi imager</a>, which makes it a painless process.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Re-insert the SD Card, then create an empty file named &quot;ssh&quot; into its boot partition. This should be the partition that auto-mounts, so you can simply <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">cd</code> into it, then <code class="css-1hue6hc e1mpr5v84">touch ssh</code>.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Insert the SD card into your Pi, and connect the ethernet and microUSB cables to your laptop.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Open System Preferences and go to the Sharing tab. <a href="https://apple.stackexchange.com/a/143519">Enable internet sharing</a> through your ethernet port. If you&#x27;re using an adapter, your ethernet port may be called by the adapter name, such as &quot;USB 10/100 LAN&quot;.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Open System Preferences, and go to the Network tab. Enable DHCP or DHCP with manual address on your ethernet port. Wait for it to get connected.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">In your terminal, run <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">ifconfig</code>, then find your bridge interface, <code class="css-1hue6hc e1mpr5v84">bridge100</code> in my case, and get its network address under <code class="css-1hue6hc e1mpr5v84">inet</code>.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Usually, you can just assume the Pi&#x27;s IP address will be allocated to the next IP bridge interface&#x27;s IP + 1. In my case, this is 192.168.2.1 + 1, so 192.168.2.2.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Or to be really sure, you can find the Pi&#x27;s IP by scanning the range of IP addresses in your <a href="https://en.wikipedia.org/wiki/Subnetwork">subnet</a>.
<ul>
<li class="css-1650jxb e1mpr5v80">In my case, my bridge interface address is 192.168.2.1 and mask is 0xffffff00, which is a /24 block.</li>
<li class="css-1650jxb e1mpr5v80">So <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">sudo nmap -sS -p 22 192.168.2.1/24</code> will list out all devices under this block.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Simply SSH in! In my case, <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">ssh pi@192.168.2.2</code>, with default password <code class="css-1hue6hc e1mpr5v84">raspberry</code>.</li>
</ol></div>]]></description><link>https://blog.cyrusroshan.com/post//post/two-cable-ssh</link><guid isPermaLink="false">two-cable-ssh</guid><pubDate>Sun, 25 Oct 2020 00:00:00 GMT</pubDate></item><item><title><![CDATA[The harmful assumptions we make about tasks]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Most task managers make two assumptions. Do you make them too?</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">A task manager needs to remember all of your tasks</em> <br/>(Would you buy a task manager that lost data?)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">All tasks can use a similar creation workflow</em> <br/>(You hit the &#x27;create issue&#x27; button, and fill in some fields. Simple, obvious, how could it be better?)</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It&#x27;s not obvious that they&#x27;re wrong—they actually seem <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">useful</em>. But both at work, and at home, making these assumptions will reduce your effectiveness.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And if you have trouble context-switching, procrastinate tasks, or have an ever-growing task backlog that looms over your head, these assumptions have likely caused you unnecessary pain.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s how they hurt us, and how to stop it from happening.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="permanent-tasks-cause-fatigue" class="css-1oc01jt evim1t94">Permanent tasks cause fatigue</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Before starting Tandem, my manager Tim previously co-founded <a href="https://techcrunch.com/2013/05/01/yahoo-acquires-to-do-app-astrid/">Astrid</a>, a personal task manager, which he later sold to Yahoo.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At Astrid, Tim tried an interesting re-engagement email. Users who had been inactive for 6 weeks were asked: &quot;want to delete all your tasks and start fresh?&quot;</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The hypothesis was that these inactive users had tasks that overwhelmed them. Either the amount, the complexity, or the low importance of backlogged tasks, caused users to put tasks off. So every time these users visited Astrid, they saw tasks they couldn&#x27;t do, felt bad, and eventually stopped visiting—procrastination in action. Astrid&#x27;s re-engagement email offered the users a chance to start fresh.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It was impressively compelling. Most re-engagement emails get a 1% response rate. This email had about 5%.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I imagine those users had the same feeling you get when you move from one browser to another, or from one task manager to another, and leave your bookmarks, open tabs, backlogged tasks, to start fresh in the name of increased productivity.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But simply deleting the backlog doesn&#x27;t end the cycle.</p>
<hr/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Nowadays, Tim uses a simpler task manager—a notebook. He uses a page a day, adds some tasks from JIRA, and when tasks come in during the day, he writes them down and works on them when he&#x27;s available. These are mostly small tasks, things that are easy to forget. If he gets a bug (important to track) or a task he can delegate, he puts it in JIRA.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The notebook isn&#x27;t meant to store issues forever. The pages get turned, and previous information becomes less accessible. So the next day, if he needs to carry over something that hasn&#x27;t been completed, he needs to make the conscious decision to do so.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This solution solves task-management fatigue. And incidentally, it solves another problem:</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="not-all-tasks-are-created-the-same" class="css-1oc01jt evim1t94">Not all tasks are created the same</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">There is a gap in task management. When we look at the tools used for tracking tasks and goals, there&#x27;s something for every level of the company:</p>
<br/>






























<style data-emotion="css mdixsy">.css-mdixsy{width:100%;}.css-mdixsy thead{box-shadow:0px 0px 1px 1px black;}.css-mdixsy td{text-align:center;border:1px solid black;padding:4px;}</style><table class="css-mdixsy e1mpr5v83"><thead><tr><th>Level</th><th>Goal</th><th>Tool</th></tr></thead><tbody><tr><td>Company quarter-level</td><td>Quarterly Goals</td><td>Notion/Gdocs</td></tr><tr><td>Org quarter-level</td><td>KPIs</td><td>Notion/Gdocs, JIRA Epics</td></tr><tr><td>Team sprint-level</td><td>Tickets</td><td>JIRA Tasks/Bugs</td></tr><tr><td>Personal day-level</td><td>???</td><td>???</td></tr></tbody></table>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Except at the personal day-level, where you&#x27;re working on tickets, getting requests for feature updates from your PM, bug discoveries from QA, and breaking down your actual tickets into different tasks, which may require subtasks that weren&#x27;t anticipated.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">One proposal is that you should track all of these tasks, no matter how small, in JIRA. But the teams I see successful at implementing this are those that can afford to work at a slower, more &quot;enterprise&quot; pace. Which isn&#x27;t a problem—at least for engineering—but it&#x27;s often not an option at smaller startups, when learning cycles must be fast.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">Even if you work at a larger company, at a slower pace, you may relate when it comes to personal life: tasks come from a variety of directions, at all times. You can&#x27;t toss every minor task in a task manager.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You can&#x27;t fix every task before the next one comes in. If you only use JIRA, you choose between possibly forgetting these small tasks, or breaking your train of thought to search, categorize, and fill out a form every time you get a small task.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">On the flip side, quickly writing these down in a temporary place means that <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">you don&#x27;t need to</strong>:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Spend mental effort remembering minor tasks,</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">or take significant time to file minor issues.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Have your task manager filled with minor issues you&#x27;ve forgotten to close,</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">or leave hastily-written issues for later, when you forget what the vaguely titled issue is for.</li>
</ul>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="correcting-for-the-mistakes" class="css-1oc01jt evim1t94">Correcting for the mistakes</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The solution is not complicated: use a temporary, personal task manager.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Don&#x27;t go out and buy something new. You already have something you can use at home. Tim&#x27;s notebook is a good example. I personally message myself on Slack (and iMessage, for personal use).</p>
<details><summary>An example of how I Slack myself</summary>
<style data-emotion="css 3mx8t2">.css-3mx8t2{border-left:2px solid black;padding-left:1em;}</style><div class="css-3mx8t2 egp0t60">
<style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="using-slack-for-daily-personal-tasks" class="css-2md8qb evim1t96">Using Slack for daily personal tasks</h4>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When I&#x27;m working, and get a non-urgent task that would otherwise interrupt me, it goes in my Slack DMs. This is what it looks like:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/task-management-assumptions/images/IMG_7647.jpg" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Some days are quiet</span></div></span></div>
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"><img src="/images/post/task-management-assumptions/images/IMG_7644.jpg" class="css-1k43lf1 ef55ps60"/></div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">And some are hectic</span></div></span></div>
</div></div>
<p class="css-wurtue evim1t98">In the morning, to re-build yesterday&#x27;s context, I just look at yesterday&#x27;s list. If there are unfinished items, I can carry them over. But it&#x27;s a conscious decision. I don&#x27;t need to carry over optional, low-priority tasks.</p>
<p class="css-wurtue evim1t98">And if you&#x27;ve got a bad memory, there&#x27;s a huge benefit for team stand-ups. I used to write JQL filters to search JIRA (doesn&#x27;t work—and misses tasks), now I just take a look at Slack.</p>
</div>
</details>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The important requirements are just that your task manager:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Requires effort to carry over old tasks.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Makes writing down tasks quick.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Isn&#x27;t used for notes <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">(anecdotally, this adds noise, and forces you to parse notes from tasks)</em>.</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If a task is critical, long term, or requires cooperation, file it in your normal issue tracker. Otherwise, it&#x27;s probably a daily, personal task, and you can file it in here.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So take out a notebook, open Slack, pick what works for you. And see if you don&#x27;t feel calmer and more in control of your tasks.</p>
<br/>
<br/>
<hr/>
<br/>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="relevant-tools" class="css-1oc01jt evim1t94">Relevant tools</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I think these tools have interesting ideas to help individuals manage tasks.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="amna" class="css-1887rzz evim1t95">Amna</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Ravi, my old college roommate and friend since high school, left Microsoft to build <a href="https://www.getamna.com">Amna</a>, a personal task manager with tight browser integration.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I resonate with the thesis: recently I switched away from Firefox Tree Style Tabs, because I noticed that by organizing my tabs (which were part of tasks), it inadvertently became a de-facto task manager. But it wasn&#x27;t built for that!</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Amna solves that exact problem: each task you do spawns a browser that keeps all of your relevant tabs.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/task-management-assumptions/images/amna1.jpg" alt="caption: All the tabs in this browser window are related to the same task, and Amna keeps their state when I close the browser." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">All the tabs in this browser window are related to the same task, and Amna keeps their state when I close the browser.</span></div></span></div>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/task-management-assumptions/images/amna2.jpg" alt="caption: After I&#x27;m done with a task, I can go back and look at the tabs I had open." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">After I&#x27;m done with a task, I can go back and look at the tabs I had open.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It helps prevent:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Muscle-memory opening HN, clicking an interesting blog post, and leaving it open &quot;to read later&quot; for several weeks</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">The pain of trawling through bookmarks and browser history, when you realize you forgot something</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">The clutter of leaving tabs open to prevent forgetting something</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you&#x27;ve forgotten a time when you had less than five tabs open, <a href="https://www.getamna.com/">try using Amna</a>.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="jam" class="css-1887rzz evim1t95">Jam</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Two of my ex-Cloudflare friends, Dani and Irtefa, started <a href="https://jam.dev/">Jam</a>. It&#x27;s probably the fastest way for PMs/designers to directly make comments on a website. So you get less minor interruptions, and more clarity on the requested change.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/task-management-assumptions/images/jam2.jpg" alt="caption: All you do is type jam on the page, click an element, and type the comment." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">All you do is type jam on the page, click an element, and type the comment.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But I don&#x27;t include Jam here just for that. Jam also allows you to <a href="https://words.jam.dev/introducing-jam-wand/">offload the actual copy changes</a> to your PM, which flat-out decreases your minor tasks. If this sounds exciting, get on the waitlist <a href="https://jam.dev/">here</a>.</p>
<hr/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">A big thank you to Calvin French-Owen, Zack Bloom, Tim Su, and Tejas Manohar for their thoughtful feedback on earlier drafts of this post.</em></p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/task-management-assumptions</link><guid isPermaLink="false">task-management-assumptions</guid><pubDate>Sat, 12 Dec 2020 00:00:00 GMT</pubDate></item><item><title><![CDATA[Bypassing hotspot limits on iOS]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">My parents live in a fairly rural area of Texas. There&#x27;s no cable internet, and fiber is out of the question—they&#x27;re the target demographic for Starlink. When I was in high school, we used our phone landline for a very-flaky, too-expensive DSL. Nowadays we use hotspots.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So if there&#x27;s no hotspot, there&#x27;s no internet.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And when I flew in this winter to visit, my paid hotspot plan didn&#x27;t activate on time. So there I was, sitting in quarantine, trying to use my laptop with no internet. But annoyingly, I already had <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">unlimited</em> phone data.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I wondered: why can&#x27;t I use my phone&#x27;s LTE data to hotspot? As it turns out, it&#x27;s not that you <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">can&#x27;t</em>—it&#x27;s just that <em class="css-5hfsd2 e1mpr5v81">iOS doesn&#x27;t want you to</em>.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s how I managed to get a DIY hotspot working on a regular, non-jailbroken iPhone.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/phone-data-hotspot/images/ssh_debug.jpeg" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Logs from sshd -d -d</span></div></span></div>
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11">
<img src="/images/post/phone-data-hotspot/images/warp_detailed_speed.png" class="css-1k43lf1 ef55ps60"/></div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">And the speed&#x27;s not bad!</span></div></span></div>
</div></div>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="how-does-it-work" class="css-1oc01jt evim1t94">How does it work?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When you use a hotspot on iOS, your device treats your hotspot&#x27;s network packets differently than the network data that apps use. Hotspot packets get routed differently, and they get metered. And if your hotspot plan isn&#x27;t activated, your device won&#x27;t even let you hotspot at all.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/phone-data-hotspot/images/verizon_hotspot.jpeg" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Connecting through my built-in iOS hotspot doesn&#x27;t route traffic through my iOS VPN</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In order to prevent that, this custom hotspot tunnels your laptop&#x27;s network packets through an app (in this case, <a href="https://ish.app/">iSH</a>). This way, your laptop&#x27;s traffic gets treated as if it&#x27;s just an app making network connections.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s a quick visual overview of the process:</p>
<style type="text/css">
@media screen and (max-width: 800px) {
	.mermaid svg {
		height: 300px !important;
	}
}
</style>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1p2i3v2">.css-1p2i3v2{display:contents!important;font-size:18px!important;}.css-1p2i3v2 svg{background-color:transparent!important;max-width:100%;}.css-1p2i3v2 svg .actor{stroke:black!important;fill:#751506!important;rx:5px;ry:5px;}.css-1p2i3v2 svg .actor tspan{fill:#fff7e8!important;font-size:24px!important;font-family:charter,times new roman,serif!important;}.css-1p2i3v2 svg .messageText{stroke:none!important;fill:black!important;alignment-baseline:alphabetic;}.css-1p2i3v2 svg .note{stroke:#751506!important;fill:#ffefd0!important;stroke-width:4px!important;border-radius:2em!important;padding:10px 20px!important;rx:3px;ry:3px;}.css-1p2i3v2 svg .noteText{font-size:17px!important;}.css-1p2i3v2 svg *[class^='activation'],.css-1p2i3v2 svg *[class*=' activation']{stroke:#751506!important;fill:#751506!important;}.css-1p2i3v2 svg *[class^='messageLine'],.css-1p2i3v2 svg *[class*=' messageLine']{stroke-width:3px!important;}.css-1p2i3v2 svg .actor-line{stroke:#beb3b1!important;stroke-width:3px;}.css-1p2i3v2 svg #sequencenumber>circle{r:4px!important;}</style><div class="_mermaid_ css-1p2i3v2 egr3cz50"><svg id="my-svg" width="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="max-width: 585px; background-color: white;" viewBox="-50 -10 585 581" role="graphics-document document" aria-roledescription="sequence"><g><rect x="291" y="495" fill="#eaeaea" stroke="#666" width="150" height="65" name="$L" rx="3" ry="3" class="actor actor-bottom"/><text x="366" y="527.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="366" dy="0">💻 Laptop</tspan></text></g><g><rect x="0" y="495" fill="#eaeaea" stroke="#666" width="150" height="65" name="$P" rx="3" ry="3" class="actor actor-bottom"/><text x="75" y="527.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="75" dy="0">iPhone 📱</tspan></text></g><g><line id="actor1" x1="366" y1="65" x2="366" y2="495" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="$L"/><g id="root-1"><rect x="291" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="$L" rx="3" ry="3" class="actor actor-top"/><text x="366" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="366" dy="0">💻 Laptop</tspan></text></g></g><g><line id="actor0" x1="75" y1="65" x2="75" y2="495" class="actor-line 200" stroke-width="0.5px" stroke="#999" name="$P"/><g id="root-0"><rect x="0" y="0" fill="#eaeaea" stroke="#666" width="150" height="65" name="$P" rx="3" ry="3" class="actor actor-top"/><text x="75" y="32.5" dominant-baseline="central" alignment-baseline="central" class="actor actor-box" style="text-anchor: middle; font-size: 16px; font-weight: 400;"><tspan x="75" dy="0">iPhone 📱</tspan></text></g></g><style>#my-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#my-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#my-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#my-svg .error-icon{fill:#552222;}#my-svg .error-text{fill:#552222;stroke:#552222;}#my-svg .edge-thickness-normal{stroke-width:1px;}#my-svg .edge-thickness-thick{stroke-width:3.5px;}#my-svg .edge-pattern-solid{stroke-dasharray:0;}#my-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#my-svg .edge-pattern-dashed{stroke-dasharray:3;}#my-svg .edge-pattern-dotted{stroke-dasharray:2;}#my-svg .marker{fill:#333333;stroke:#333333;}#my-svg .marker.cross{stroke:#333333;}#my-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#my-svg p{margin:0;}#my-svg .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#my-svg text.actor&gt;tspan{fill:black;stroke:none;}#my-svg .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#my-svg .innerArc{stroke-width:1.5;stroke-dasharray:none;}#my-svg .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#my-svg .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#my-svg #arrowhead path{fill:#333;stroke:#333;}#my-svg .sequenceNumber{fill:white;}#my-svg #sequencenumber{fill:#333;}#my-svg #crosshead path{fill:#333;stroke:#333;}#my-svg .messageText{fill:#333;stroke:none;}#my-svg .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#my-svg .labelText,#my-svg .labelText&gt;tspan{fill:black;stroke:none;}#my-svg .loopText,#my-svg .loopText&gt;tspan{fill:black;stroke:none;}#my-svg .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#my-svg .note{stroke:#aaaa33;fill:#fff5ad;}#my-svg .noteText,#my-svg .noteText&gt;tspan{fill:black;stroke:none;}#my-svg .activation0{fill:#f4f4f4;stroke:#666;}#my-svg .activation1{fill:#f4f4f4;stroke:#666;}#my-svg .activation2{fill:#f4f4f4;stroke:#666;}#my-svg .actorPopupMenu{position:absolute;}#my-svg .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#my-svg .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#my-svg .actor-man circle,#my-svg line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#my-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g/><defs><symbol id="computer" width="24" height="24"><path transform="scale(.5)" d="M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z"/></symbol></defs><defs><symbol id="database" fill-rule="evenodd" clip-rule="evenodd"><path transform="scale(.5)" d="M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z"/></symbol></defs><defs><symbol id="clock" width="24" height="24"><path transform="scale(.5)" d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z"/></symbol></defs><defs><marker id="arrowhead" refX="7.9" refY="5" markerUnits="userSpaceOnUse" markerWidth="12" markerHeight="12" orient="auto-start-reverse"><path d="M -1 0 L 10 5 L 0 10 z"/></marker></defs><defs><marker id="crosshead" markerWidth="15" markerHeight="8" orient="auto" refX="4" refY="4.5"><path fill="none" stroke="#000000" stroke-width="1pt" d="M 1,2 L 6,7 M 6,2 L 1,7" style="stroke-dasharray: 0, 0;"/></marker></defs><defs><marker id="filled-head" refX="15.5" refY="7" markerWidth="20" markerHeight="28" orient="auto"><path d="M 18,7 L9,13 L14,7 L9,1 Z"/></marker></defs><defs><marker id="sequencenumber" refX="15" refY="15" markerWidth="60" markerHeight="40" orient="auto"><circle cx="15" cy="15" r="6"/></marker></defs><text x="367" y="80" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Creates an ad-hoc WiFi network</text><path d="M 367,109 C 427,99 427,139 367,129" class="messageLine0" stroke-width="2" stroke="none" marker-end="url(#arrowhead)" style="fill: none;"/><line x1="367" y1="109" x2="367" y2="109" stroke-width="0" marker-start="url(#sequencenumber)"/><text x="367" y="113" font-family="sans-serif" font-size="12px" text-anchor="middle" class="sequenceNumber">1</text><text x="219" y="154" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Connects to Laptop's wifi network</text><line x1="76" y1="185" x2="362" y2="185" class="messageLine0" stroke-width="2" stroke="none" marker-end="url(#arrowhead)" style="fill: none;"/><line x1="76" y1="185" x2="76" y2="185" stroke-width="0" marker-start="url(#sequencenumber)"/><text x="76" y="189" font-family="sans-serif" font-size="12px" text-anchor="middle" class="sequenceNumber">2</text><text x="222" y="200" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">iPhone assigned an IP address</text><line x1="365" y1="231" x2="79" y2="231" class="messageLine0" stroke-width="2" stroke="none" marker-end="url(#arrowhead)" style="fill: none;"/><line x1="365" y1="231" x2="365" y2="231" stroke-width="0" marker-start="url(#sequencenumber)"/><text x="365" y="235" font-family="sans-serif" font-size="12px" text-anchor="middle" class="sequenceNumber">3</text><text x="76" y="246" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Sets up SSH server</text><path d="M 76,277 C 136,267 136,307 76,297" class="messageLine0" stroke-width="2" stroke="none" marker-end="url(#arrowhead)" style="fill: none;"/><line x1="76" y1="277" x2="76" y2="277" stroke-width="0" marker-start="url(#sequencenumber)"/><text x="76" y="281" font-family="sans-serif" font-size="12px" text-anchor="middle" class="sequenceNumber">4</text><text x="222" y="322" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Laptop SSHes into iPhone</text><line x1="365" y1="353" x2="79" y2="353" class="messageLine0" stroke-width="2" stroke="none" marker-end="url(#arrowhead)" style="fill: none;"/><line x1="365" y1="353" x2="365" y2="353" stroke-width="0" marker-start="url(#sequencenumber)"/><text x="365" y="357" font-family="sans-serif" font-size="12px" text-anchor="middle" class="sequenceNumber">5</text><text x="219" y="368" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">SOCKS5 proxy established</text><line x1="76" y1="399" x2="362" y2="399" class="messageLine0" stroke-width="2" stroke="none" marker-end="url(#arrowhead)" style="fill: none;"/><line x1="76" y1="399" x2="76" y2="399" stroke-width="0" marker-start="url(#sequencenumber)"/><text x="76" y="403" font-family="sans-serif" font-size="12px" text-anchor="middle" class="sequenceNumber">6</text><text x="367" y="414" text-anchor="middle" dominant-baseline="middle" alignment-baseline="middle" class="messageText" dy="1em" style="font-size: 16px; font-weight: 400;">Configures applications to use proxy</text><path d="M 367,445 C 427,435 427,475 367,465" class="messageLine0" stroke-width="2" stroke="none" marker-end="url(#arrowhead)" style="fill: none;"/><line x1="367" y1="445" x2="367" y2="445" stroke-width="0" marker-start="url(#sequencenumber)"/><text x="367" y="449" font-family="sans-serif" font-size="12px" text-anchor="middle" class="sequenceNumber">7</text></svg></div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">After setting this up once, subsequent runs take under a minute</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After step 7, the custom hotspot is configured. Data from this hotspot is treated just like normal app data!</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="setting-it-up" class="css-1oc01jt evim1t94">Setting it up</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s how I got this working.</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Download</strong> <a href="https://ish.app/">iSH</a>, an interactive shell, to proxy connections through an iOS app
<ul>
<li class="css-1650jxb e1mpr5v80">If you previously had an old version of iSH installed, you will need to <a href="https://github.com/ish-app/ish/">manually enable</a> its built in <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">apk</code> for package management. New downloads have it enabled by default.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Create</strong> a new adhoc wifi network from your laptop, connect to it from your phone, and get your phone&#x27;s IP
<ul>
<li class="css-1650jxb e1mpr5v80">you can quickly verify that the connection works using something simple like <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">python3 -m http.server</code></li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Send</strong> your SSH public key from laptop → phone
<details><summary>This step was harder without wifi. Click here to expand and see the quick-and-dirty way I did it.</summary><strong class="css-13l2ows evim1t910">On my laptop</strong>, I ran <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">cat publickey | base64 | pbcopy</code>, then pasted the result into <code class="css-1hue6hc e1mpr5v84">http://$PHONE_IP/$RESULT</code>. This hit the server on my phone (run using <code class="css-1hue6hc e1mpr5v84">python3 -m http.server</code>), which showed it in the URL path of the server logs on my phone.
<br/>
<strong class="css-13l2ows evim1t910">Then on my phone</strong>, taking that result from phone logs, I copy → pasted it into a shell command, <code class="css-1hue6hc e1mpr5v84">echo &quot;[paste here]&quot; | base64 -d &gt; publickey</code>.</details></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Install</strong> <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">sshd</code> on iSH
<ul>
<li class="css-1650jxb e1mpr5v80">Add your public key from the previous step to the <code class="css-1hue6hc e1mpr5v84">/.ssh/authorized_keys</code> file</li>
<li class="css-1650jxb e1mpr5v80">Configure the ssh server settings. The changes I made were:</li>
</ul>
<pre><div style="font-size:12px"><div style="color:#f8f8f2;background:#282a36;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto;border-radius:0.3em"><code class="language-bash" style="color:#f8f8f2;background:none;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span>Port </span><span class="token" style="color:#bd93f9">2222</span><span> </span><span class="token" style="color:#6272a4"># Custom port, 22 won&#x27;t work</span><span>
</span><span>ListenAddress </span><span class="token" style="color:#bd93f9">0.0</span><span>.0.0 </span><span class="token" style="color:#6272a4"># Allow the laptop to connect via wifi</span><span>
</span><span>PermitRootLogin prohibit-password </span><span class="token" style="color:#6272a4"># Allow root login</span><span>
</span><span>PubkeyAuthentication </span><span class="token" style="color:#f1fa8c">yes</span><span> </span><span class="token" style="color:#6272a4"># Allow public key auth</span><span>
</span><span>AuthorizedKeysFile /.ssh/authorized_keys </span><span class="token" style="color:#6272a4"># Allow access from your public key</span><span>
</span><span>PasswordAuthentication no </span><span class="token" style="color:#6272a4"># Disable passwords</span><span>
</span>PermitEmptyPasswords no
<span>Compression no </span><span class="token" style="color:#6272a4"># CPU is a concern more than bandwidth, when we&#x27;re doing this emulated + local network</span><span>
</span><span>AllowTCPForwarding </span><span class="token" style="color:#f1fa8c">yes</span><span> </span><span class="token" style="color:#6272a4"># Allow port forwarding</span><span>
</span><span>GatewayPorts </span><span class="token" style="color:#f1fa8c">yes</span><span> </span><span class="token" style="color:#6272a4"># Allow port forwarding</span><span>
</span><span>UseDNS no </span><span class="token" style="color:#6272a4"># Not useful</span><span>
</span><span>PermitTunnel </span><span class="token" style="color:#f1fa8c">yes</span><span> </span><span class="token" style="color:#6272a4"># Allow our reverse tunnel</span><span>
</span></code></div></div></pre>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Test</strong> an SSH connection to the app from the laptop
<ul>
<li class="css-1650jxb e1mpr5v80">You should be able to get your phone&#x27;s IP from the settings page</li>
<li class="css-1650jxb e1mpr5v80">SSH in from your laptop with <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">ssh root@$PHONE_IP -p 2222</code></li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now, on your laptop you should be able to run <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">ssh -N -D 1080 root@$PHONE_IP -p 2222</code> to create a SOCKS5 proxy server on port 1080! You can open your browser (Firefox, Chrome), configure this as a proxy, and use this to route traffic!</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you only need to use your browser, you&#x27;re good! But you might also want to use other tools, and many of these tools don&#x27;t respect system proxy settings. For that, we can use proxychains.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="using-proxychains" class="css-1887rzz evim1t95">Using Proxychains</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><a href="https://github.com/haad/proxychains">Proxychains</a> and <a href="https://github.com/rofl0r/proxychains-ng">proxychains-ng</a> are tools that allow you to use a proxy with software that isn&#x27;t configured for it.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Since I&#x27;m on macOS, and proxychains-ng has better support, I used it here. Here&#x27;s the setup:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Install</strong> with <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">brew install proxychains-ng</code></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Edit</strong> the file <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">/usr/local/etc/proxychains.conf</code> to use <code class="css-1hue6hc e1mpr5v84">socks5 127.0.0.1 1080</code> as the proxy</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Run</strong> the program you want to use with <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">proxychains4 program_name [arguments]</code></li>
</ol>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="limitations" class="css-1oc01jt evim1t94">Limitations</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Though this is a great backup internet solution, it&#x27;s not as good as a normal carrier-enabled hotspot. Here&#x27;s a little more depth on what its drawbacks are and why they occur.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="desktop-limitations" class="css-1887rzz evim1t95">Desktop limitations</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">On an unrooted iPhone, you can&#x27;t modify iptables or <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">truly</em> run as root, so setting up a VPN server on the phone and connecting to it on your laptop doesn&#x27;t work. You&#x27;ll have to route the traffic through SSH or another protocol whose server can be run in iSH.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I spent a couple hours, but for whatever reason, I couldn&#x27;t get <a href="https://github.com/sshuttle/sshuttle">sshuttle</a> working. Proxychains works fine, but it means you need to manually launch every program you&#x27;d like proxied, and UDP traffic isn&#x27;t supported, just TCP.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Note that you may be able to work around these limitations on Linux, where you have more control over the network stack than on macOS.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="app-limitations" class="css-1887rzz evim1t95">App limitations</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">There are a couple of limitations to this method from the app side, as well. Though they&#x27;re both bearable as-is.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="1-backgrounding" class="css-2md8qb evim1t96">1. Backgrounding</h4>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When your phone locks, or you switch apps, iSH will get backgrounded, and your connection to the server will be lost.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To allow iSH to run into the background, you can run <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">cat/dev/location &gt; dev/null &amp;</code>, which polls your location, though it&#x27;s still a bit flaky. You could also disable auto-lock screen, though remember to re-enable it after you&#x27;re done.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="2-heat" class="css-2md8qb evim1t96">2. Heat</h4>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After an hour or two of constantly running <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">sshd</code> on iSH, your phone gets warm and toasty. This is because iSH emulates all of its commands—but for good reason, App Store approval!</p>
<br/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">However, with effort, a custom app could solve the above limitations by:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Allowing more control over backgrounding behavior, including <a href="https://yifan.lu/2013/12/17/unlimited-backgrounding-on-ios/">abusing background music for unlimited backgrounding</a>.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Running arm64 sshd <a href="https://news.ycombinator.com/item?id=24862329">without requiring x86 emulation</a>, reducing CPU usage.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">And doing both of the above without requiring App-Store approval, since you can load custom apps locally.</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Until then, this is a proof-of-concept that leaves productionization as an exercise to the reader.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Enjoy!</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/phone-data-hotspot</link><guid isPermaLink="false">phone-data-hotspot</guid><pubDate>Mon, 25 Jan 2021 00:00:00 GMT</pubDate></item><item><title><![CDATA[Why I don't feel like writing.]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">I don&#x27;t know.</em> Maybe it&#x27;s because I&#x27;ve got lots of things to do. Maybe that&#x27;s just something I tell myself when I procrastinate work that seems hard. Why is writing hard? Because it&#x27;s vulnerable? Or because vulnerable work is held close-to-heart, and the standards are higher, so I truly <em class="css-5hfsd2 e1mpr5v81">do</em> need to do more work to get it out?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Why don&#x27;t I feel like writing?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I don&#x27;t know! Sometimes the words come out, and sometimes they don&#x27;t. I guess this is one of the times where they just don&#x27;t. Would I be better at editing right now? Why don&#x27;t the words come out easily? Is it because I&#x27;m stressed, is it because I&#x27;m frustrated? Is it because I&#x27;m too tired and have exhausted all of my thinking potential earlier in the day? Should I not be writing late?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Why don&#x27;t I feel like writing?...</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Okay, this title-repetition has worn off. I can&#x27;t keep going the whole way, should I scrap it? Should I just delete the whole thing and start again? Sometimes, when I delete the whole thing, I feel that the next time, I might be less inclined to start it in the first place.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">What a hamper.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So I <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">do</em> think that the editing standards are higher to get something out for publication. But when I&#x27;m writing, I&#x27;m just writing for my own blog! Why is it hard to post something that&#x27;s difficult to write? Oh wait, that&#x27;s not what I mean. Oh wait. <em class="css-5hfsd2 e1mpr5v81">It is.</em> I have to write something that&#x27;s difficult, and then I have to edit it, to make it something that&#x27;s good, and then—unsatisfied with its blemishes—I have to make it into something that&#x27;s producable. I have to publish it. How can I?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Oh, that wasn&#x27;t bad, actually.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I think this style feels fairly freeing. [oh god, I just accidentally deleted the whole work, why is iA writer so bad]. Ah, yes, that&#x27;s the problem. When I write with my inner dialogue, it&#x27;s literally the thoughts that go through my head. There&#x27;s very little editing, and the structuring isn&#x27;t well-thought-out. A sentence could be confusing. Or the whole argument could be ordered with a structure that makes it confusing. Do I stop and edit? Do I backspace? Oh wait, I did, and now I don&#x27;t remember the rest of what I&#x27;m saying! It&#x27;s difficult!</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, maybe that&#x27;s why I don&#x27;t write as often as I want to.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Except, <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">I do.</em> I just discard all the drafts that don&#x27;t make it. And oh, <em class="css-5hfsd2 e1mpr5v81">so many</em> of them end up as just drafts. Never making it to production. Never seeing the light of day. But yes, that does put me in a rut. If I feel like I&#x27;m writing another draft that won&#x27;t make it, I might just give up. If I spend too much time editing, I might just give up. If I have to make <em class="css-5hfsd2 e1mpr5v81">stylistic</em> changes that require <em class="css-5hfsd2 e1mpr5v81">code</em> changes in my CMS platform, I might just give up. How do I make sure I don&#x27;t just give up? The only way that&#x27;s pretty much guaranteed: I just ... hit ... send.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">...</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">[fin]</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This blog post was edited less than once, or not at all. This blog post was reviewed by no-one[0]. But I still like it. Enough to hit submit, at least.</p>
<ol start="0">
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Though, it <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">was</em> based off of a conversation I had with a friend</li>
</ol></div>]]></description><link>https://blog.cyrusroshan.com/post//post/why-dont-i-feel-like-writing</link><guid isPermaLink="false">why-dont-i-feel-like-writing</guid><pubDate>Mon, 05 Jul 2021 00:00:00 GMT</pubDate></item><item><title><![CDATA[Introducing Portal Windows]]></title><description><![CDATA[<div><style data-emotion="css aa7kzm">.css-aa7kzm{width:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:center;-ms-flex-pack:center;-webkit-justify-content:center;justify-content:center;}</style><div class="css-aa7kzm e1fiwp610"><div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">(This post originally published on <a href="https://blog.tandem.chat/portal-windows/">Tandem&#x27;s blog</a>)</em></p></div></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">What’s the piece of technology that reduced your headache the most in the last year?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For me, it’d be <a href="https://github.com/cryptagon/portal-windows">Portal Windows</a>. It&#x27;s a library we made at <a href="https://tandem.chat">Tandem</a> that lets you render and position native windows as simply as you render and position tooltips in your React app.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
    <iframe title="YouTube video player" width="480" height="300" src="https://www.youtube.com/embed/p6m2zotGy-g?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">tired: juggling your free time. wired: juggling some portal windows</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">A year ago, making changes to other windows was a slog.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To trace the flow of data through our app, you would have to jump from file to file. Stores in the renderer sent messages to the node process, which then forwarded them to the renderer process for the window that was displayed. If you wanted to add a small icon to a row on our tooltips, users would have to download a new desktop app to see it.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And worst of all, these changes took <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">so long</em> to make.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Today, every single one of those problems is gone, and I <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">enjoy</em> window-related tickets. I don&#x27;t have to write a single line of desktop code, or do any message-passing. I mostly just write React components, as if there were no windows involved.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Not only that, but behavior we didn’t consider a year ago, because it was prohibitively difficult, is now simple.</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Rendering a window onto multiple screens, even as screens are added/removed,</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">doing complicated bounds correction,</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">positioning a window relative to an <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">element</em> on another window, even as the parent window moves and gets resized?</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">All covered. You too can feel great while writing complex window-management code.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now, here’s a high-level of how Portal Windows work, a few simple examples, a few examples of how we use them today in the Tandem app, and then the source code.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="structure" class="css-1oc01jt evim1t94">Structure</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Portal Windows are made up of a three-layer system:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Integration with React, allowing you to treat a window as a component in your tree, change its props, render elements inside it (thanks to React Portals)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A window management store, which keeps track of window and screen state, allowing relative positioning of windows, bounds correction, and multi-screen rendering support</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Desktop-side code that enables the frontend to apply and receive updates, and create and address windows</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">What does this let you do? Great things!</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="examples" class="css-1oc01jt evim1t94">Examples</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you enjoy using Tandem, you might be familiar with these windows, and their use cases:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
    <iframe title="YouTube video player" width="480" height="300" src="https://www.youtube.com/embed/Ptz3m7Pu_7U?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Meeting reminders: get reminded of your meeting before it starts, and have Tandem automatically launch it for you at the start time. Shown on every screen.</span></div></span></div>
<br/>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
    <iframe title="YouTube video player" width="480" height="300" src="https://www.youtube.com/embed/Ifea3a8HHcQ?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Chatbox: when untoggled, new messages pop up to the left of the callbox, and slowly fade. When toggled, it remains open and shows chat history.</span></div></span></div>
<br/>

<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
    <iframe title="YouTube video player" width="480" height="300" src="https://www.youtube.com/embed/CX0xMNzHkEY?rel=0&amp;showinfo=0" frameBorder="0" allowfullscreen=""></iframe>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Screenshare: fetches windows + screens, and lets you share them. Once you screenshare, &#x27;end screenshare&#x27; window appears on the bottom of the screen you&#x27;re sharing to let you end it quickly.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Being able to use portal windows means that the &quot;End Screenshare&quot; window ended up being only ~100 lines of code total, and took &lt;1hr to build.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="using-portal-windows" class="css-1oc01jt evim1t94">Using Portal Windows</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Remember the swarm of windows in the video at the top? <a href="https://github.com/cryptagon/portal-windows/blob/main/examples/src/app.tsx">Here&#x27;s the code</a> behind it, and <a href="https://github.com/cryptagon/portal-windows/blob/main/examples/src/simpleApp.tsx">here&#x27;s a simpler version</a> that only has one portal window.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You can follow the steps to get it integrated in your existing Electron app <a href="https://github.com/cryptagon/portal-windows">here</a>, or copy a <a href="https://github.com/cryptagon/portal-windows/tree/main/examples">fresh project</a> to play around with.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This tech has cut down on the time it takes to ship new features drastically, and we’re open-sourcing it as a gift to the community. Check out the <a href="https://github.com/cryptagon/portal-windows">source code here!</a> (licensed MIT)</p>
<style data-emotion="css fzwid6">.css-fzwid6{width:100%;text-align:center;}</style><div class="css-fzwid6 e1n61chs0"><style data-emotion="css 10cwprm">.css-10cwprm{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;}@media screen and (max-width: 500px){.css-10cwprm{font-size:20px;}}</style><h3 class="css-10cwprm evim1t95">...</h3></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Does this interest you? Let us know, we&#x27;re hiring! <a href="mailto:jobs@tandem.chat">jobs@tandem.chat</a>!</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/introducing-portal-windows</link><guid isPermaLink="false">introducing-portal-windows</guid><pubDate>Wed, 25 Aug 2021 00:00:00 GMT</pubDate></item><item><title><![CDATA[To my teachers]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Do you know how some kids want to be teachers when they grow up?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Do you know <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">why?</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I do. When I was in fifth grade, I was shy, short, and quiet. I had skipped two grades, and so I was two years younger than the other students. My parents had moved five times (Vermont, Pennsylvania, Indiana, New Mexico) before we had come back to Texas, and I didn&#x27;t have a lot of friends. Or, for that matter, experience making them.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But in the mornings, before school, every day, I would get dropped off at around 6am by my parents. I would wait with the crossing guard until my teacher came to school, and then go sit with her in the classroom and write in my journal, and do my work, until school started. I still remember her name was Mrs. Hill.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In that class, I went from being a very-quiet, very-unsure, very-shy child, to being a mostly-quiet, mostly-unsure, mostly-shy kid. And, as anyone who&#x27;s been in that situation can tell you, that&#x27;s actually a lot of improvement. I felt proud when I could shape a spoon out of aluminum foil for our hands-on science demonstration, I felt good about writing, in a way I thought was interesting. And at Camp Tyler, an outdoor school that each 5th grade class in our public school distict visited for a week, I had fun.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That&#x27;s the change a teacher can cause. You might say, &quot;that&#x27;s what they&#x27;re told to do&quot;. But I remember Mrs. Hill would spend her own money to buy supplies and other things for the classroom. She didn&#x27;t need to wake up so early for school to let me in. Neither did the crossing guard.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I haven&#x27;t had a long career, but I&#x27;ve been exceedingly lucky to meet people like Mrs. Hill. People that made me want to be like them, when I grew up.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="teachers-are-mentors" class="css-1oc01jt evim1t94">Teachers are Mentors</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">My first internship was exceptional. It shaped my career in the same way that Mrs. Hill&#x27;s fifth grade class shaped my educational path.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That summer I had a great time, learned a lot, and grew as a person. I left that internship better-equipped to solve problems.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Not just because the tech was robust, or the team was skilled, or because I had real responsibilities. But also because of who I sat next to.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">My manager, Zack, was more of a mentor than anything else. When we had discussions, we had them as peers. When we had 1-1s, we would talk about life, and I knew I could ask difficult questions. The type you would ask a friend, when you needed advice.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To some people, I&#x27;m describing their current manager-direct relationship. To others, I&#x27;m describing something unfathomably impossible. For me, it was my first internship, and I kind of figured I had found something good.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Zack mentored as a peer, and by that, I mean imagine you had time-traveled to see yourself 10 years in the future. Would you expect them to look down on you? Hand you quick answers, instead of expanding your understanding? Or would you imagine them to do everything they could in their power to increase your knowledge and independence, assuming they would be better for it?</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="paying-it-forward" class="css-1oc01jt evim1t94">Paying it forward</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Nowadays, when I need to be a mentor, I try to imagine how Zack would approach it. Last winter, I helped my sister as she built and programmed a RC car with an arduino, and she actually had a good time. This summer, I mentored two of our interns at <a href="https://tandem.chat">Tandem</a>, and I actually did well.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I say <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">actually</em>, because I historically haven&#x27;t been a great mentor. Back when I was in college, I set expectations too high, and I looked down on people I mentored if I didn&#x27;t feel they met them. I probably had an overall discouraging effect on my sister, or friends I tried to teach programming to, instead of accelerating their learning.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If I hadn&#x27;t been other side of the table, and learned how to be a mentor <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">from my mentors</em>, I don&#x27;t know how I would&#x27;ve ever improved.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="a-grateful-thanks" class="css-1oc01jt evim1t94">A grateful thanks</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I feel incredibly lucky to have these people in my life. People with no prior connection to me, who still care that I learn, and do well.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To Mrs. Hill, to Zack, and to all my other teachers:</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Thank you for instilling a learning spirit in me.</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/to-my-teachers</link><guid isPermaLink="false">to-my-teachers</guid><pubDate>Thu, 16 Dec 2021 00:00:00 GMT</pubDate></item><item><title><![CDATA[Patching dependencies is easier than forking]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Oftentimes, it feels like we overengineer the solutions we build. Patching packages never feels this way.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When I use patch-tool, it&#x27;s often the best solution.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It may not be the best long-term solution, but it&#x27;s so darn fast. And at a startup, speed of development directly translates into product velocity.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So let me tell you how to use it. With an example: Patching Datadog.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-patch-package-does" class="css-1oc01jt evim1t94">What patch-package does.</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When working with javascript, you naturally have file access to the contents of your imported NPM packages. So you can modify them locally. If your code needs a dependency changed, you can make that change, rebuild, and try it out.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">What <a href="https://www.npmjs.com/package/patch-package">patch-package</a> does <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">then</em>, is it lets you check those patches into version control. So when your teammates or CI systems pull the repo, as part of running <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">yarn</code> to update deps, they reapply those patches. That way you can modify your dependencies, without having to take on the weighty burden of forking them.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="why-make-a-patch" class="css-1oc01jt evim1t94">Why make a patch?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So here&#x27;s the context. I work at a company called <a href="https://jam.dev">Jam</a>, and we make the best QA tool for websites and webapps. We care about our users&#x27; experience, so we want to keep track of unexpected errors that users hit. We use Datadog for this.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The problem is that a portion of our Chrome<style data-emotion="css pz1a0z">.css-pz1a0z{margin-left:3px;margin-right:1px;display:inline-block;-webkit-transform:translate(0px,-3px);-moz-transform:translate(0px,-3px);-ms-transform:translate(0px,-3px);transform:translate(0px,-3px);}</style><sup id="fnref-1" class="css-pz1a0z e1mpr5v82"><a href="#fn-1" class="footnote-ref">1</a></sup> extension is a content-script, which gets loaded alongside pages that users report bugs on. When our content script sends updates to Datadog, these updates live in the context of the host page. So they pollute the user&#x27;s network requests tab in devtools. And when a user closes the page, requests that were buffered could be lost!</p>
<hr/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So that&#x27;s the issue. We don&#x27;t want Datadog requests to go be sent by the pages that our users browse. But Datadog&#x27;s <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">browser-logs</code> and <code class="css-1hue6hc e1mpr5v84">browser-rum</code> packages don&#x27;t let you proxy messages with a proxy function! You <a href="https://docs.datadoghq.com/real_user_monitoring/faq/proxy_rum_data/?tab=npm">can</a> set a URL to proxy them through, but that doesn&#x27;t help in our case. What do? Fork it?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">No! Patch-package to the rescue!</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="the-patch-itself" class="css-1oc01jt evim1t94">The patch itself</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The Datadog packages we use have all of their requests go through one file:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/easily-patch-your-javascript-deps/images/original_code.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">note: in this case, this file lived in a third-package, <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">@datadog/browser-core</code>, which is the package I patched directly, after elevating it to a top-level dependency.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">What we need to do now is modify this file to allow us to proxy these requests. After that, we&#x27;ll be able to proxy these requests over postMessage, from our content script to our background script.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But first, we need to figure out what version of the file we&#x27;re modifying! For this file, there&#x27;s a <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">cjs</code> and an <code class="css-1hue6hc e1mpr5v84">esm</code> version. Easiest way to figure out which one we&#x27;re importing? Just sprinkle some log statements in, clear webpack&#x27;s cache, and reload!</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/easily-patch-your-javascript-deps/images/cjs_vs_esm.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99"><style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">THIS IS ESM!</code></span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We&#x27;ve found our file! Next step: modify it!</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Since Chrome extension content scripts live in a separate context from their host page (<style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">window</code> objects aren&#x27;t shared), we can simply have our patched package read from the <code class="css-1hue6hc e1mpr5v84">window</code> object, to figure out where should send the message data, without worrying about intereference with/from the host page.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/easily-patch-your-javascript-deps/images/modify_dep.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">And if we don&#x27;t add a <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">&#x27;DATADOG_REQUEST_PROXY&#x27;</code> function to the <code class="css-1hue6hc e1mpr5v84">window</code>, our logger falls back gracefully. This is useful, because we&#x27;ll be using this dependency in our background script as well, where we want to use default behavior!</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Amazing! Last step, proxy the messages and execute them on the background script.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/easily-patch-your-javascript-deps/images/original_code.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">in the content script, it looks like this</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And in the background script, we execute the messages as regular network requests:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/easily-patch-your-javascript-deps/images/background_handler.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">That <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">HttpRequest</code>? Imported from the same file we patched, which thankfully already exported it.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The end result: Datadog logs are smoothly sent through our background script!</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now that we&#x27;re satsified with our changes, we run <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">yarn patch-package</code> to generate a patch file, and commit it to version control:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/easily-patch-your-javascript-deps/images/patchfile.png" class="css-1k43lf1 ef55ps60"/>
</div></div>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="try-it-at-home" class="css-1oc01jt evim1t94">Try it at home!</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Next time you consider forking a package to change a few lines, don&#x27;t forget you have another option!</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Patch-package even makes it easy to contribute back, by providing an easy way to submit your patch as a PR!</p>
<br/>
<hr/>
<br/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">One more thing: care as much about user experience as we do? Hate how long it takes to file bugs?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><a href="https://chrome.google.com/webstore/detail/jam/iohjgamcilhbgmhbnllfolmkmmekfmci">Try Jam today</a>! Our users file bugs in seconds, directly to their issue tracker, with all the details engineers need. Learn more <a href="https://jam.dev">here</a>!</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/easily-patch-your-javascript-deps/images/network_tab_screenshot.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Seriously, give your engineers something to be excited about, when you hand them a bug.</span></div></span></div>
<br/>
<br/>
<br/>
<div class="footnotes">
<hr/>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li id="fn-1" class="css-1650jxb e1mpr5v80">Firefox support coming soon, Safari support is intended after that.<a href="#fnref-1" class="footnote-backref">↩</a></li>
</ol>
</div></div>]]></description><link>https://blog.cyrusroshan.com/post//post/easily-patch-your-javascript-deps</link><guid isPermaLink="false">easily-patch-your-javascript-deps</guid><pubDate>Wed, 20 Apr 2022 00:00:00 GMT</pubDate></item><item><title><![CDATA[Explaining the copy-paste magic trick]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Earlier this week, I hit Hacker News&#x27;s <a href="https://news.ycombinator.com/item?id=31157122">frontpage</a> with a technical magic trick.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">HN users were surprised, impressed, and paranoid. Maybe a <a href="https://news.ycombinator.com/item?id=31162662"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">little</em> too paranoid</a>, in classic HN fashion.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you haven&#x27;t yet, you can test it out <a href="https://cyrusroshan.com/hosted-projects/magic-card-paste/">here</a> (desktop Chrome only). Once you&#x27;re done, you may be curious about the details.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="how-does-it-work" class="css-1oc01jt evim1t94">How does it work?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In order to understand the magic, let&#x27;s first go over the flow:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When a user visits the site, they can click a card to have it copied to clipboard</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">They paste it in an input field to verify its value</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">They open a link to Google docs</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">They paste in their Google doc, and they get a Joker card instead, which tells them to try pasting in their URL bar</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Pasting in their URL bar gives them a link directly to my Twitter account</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And now, the details.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This trick was made possible with the <a href="https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem">ClipboardItem constructor</a>, part of the Clipboard API in Javascript. This constructor allows you to copy text programatically. But it&#x27;s not only <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">plain</em> text—you can also copy rich text, the kind with styles and formatting that you might find in a fancy word doc.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Of course, when you&#x27;re pasting rich text into an input field that doesn&#x27;t support it (like a URL bar), you want to fall back to plain text. This works by the receiving application pulling the requested <a href="https://developer.apple.com/documentation/appkit/nspasteboard/pasteboardtype">MIME-type from your pasteboard</a>—and not simply by converting copied rich text to plain text.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This means that we can populate both a rich text value and a plain text value in the pasteboard, and they don&#x27;t have to have the same data!</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, walking through the steps in detail:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When a user clicks the card to copy it to clipboard, we copy a regular card to clipboard (in plain text), and a joker (in rich text). The joker is only shown if a user pastes into another application without going to a later step (this is unexpected).</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When the user pastes into the input field, they paste the plain text data, which is the card they copied—a digital equivalent to when magicians say &quot;now, memorize your card&quot;.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When the user clicks the link to navigate to Google Docs, we perform a sleight-of-hand trick, and actually populate the pasteboard <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">again</em> — this time, we copy my twitter URL to clipboard in plain text, and a joker which tells the user to paste into their URL bar, in rich text.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When the user pastes in Google Docs to verify their card, they see the joker, telling them to paste in their URL bar</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When the user pastes in their URL bar, they get my twitter link, a URL they don&#x27;t remember copying! This part feels unexpectedly surprising, as it seems like your clipboard was updated while you were on a trusted site, Google docs.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Now that the user is convinced that I post interesting content, and is already on my twitter page with the follow button a single click away, they follow me. (I gained 1/3 of my twitter followers in the past from this magic trick alone, over the past few days!)</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It&#x27;s not so magic anymore, but I hope you enjoyed the trick, and the explanation!</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/explaining-copy-paste-magic</link><guid isPermaLink="false">explaining-copy-paste-magic</guid><pubDate>Sun, 01 May 2022 00:00:00 GMT</pubDate></item><item><title><![CDATA[Onboarding Quickly]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Of all the skills to learn on the job, onboarding quickly is possibly the most underrated. You only onboard to a job once, that initial momentum sets up the rest of your experience.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But people learn from experience, and it&#x27;s not often that you switch to a new job. Luckily, in college, I had 4 internships, and then immediately worked at 3 startups (which had a big spread—1 IPO&#x27;d, and two shut down). So I&#x27;ve been lucky to have some practice.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now I work at <a href="https://jam.dev">Jam</a>, and we&#x27;re doing well, so I don&#x27;t think I&#x27;ll need this advice soon. But I&#x27;m writing it while it&#x27;s fresh. For my friends, who are switching jobs or have been laid off. For my sister, who&#x27;s applying for internships. And for you, who could possibly be joining me to build Jam ;)</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This is my opinionated take on to make sure you take advantage of your first week.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-you-should-do-when-you-join-a-company" class="css-1oc01jt evim1t94">What you should do when you join a company</h2>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">First, found out what your job is
<ul>
<li class="css-1650jxb e1mpr5v80">Have a general idea before you join. In fact, you should learn as much of this before you start, in order to align your expectations with reality</li>
<li class="css-1650jxb e1mpr5v80">What are you hired for? (Where do you fit in to the team)</li>
<li class="css-1650jxb e1mpr5v80">What is the composition of the team (Where do others fit in to the team)</li>
<li class="css-1650jxb e1mpr5v80">Find out what your manager thinks their job is (do they take an active involvement in the team? Do they view 1-1s as a chore?) This will help you understand how to treat them as a resource. And unfortunately, when you cannot rely on them (a situation I&#x27;ve seen too often with friends at larger companies).</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Find out how to do your job (high-level)
<ul>
<li class="css-1650jxb e1mpr5v80">Find out where your team sits in the org chart (and what are your adjacent teams)</li>
<li class="css-1650jxb e1mpr5v80">Find out which people you&#x27;ll need to talk to at those relevant teams (and of course, your teammates should also have some relations with these people to lubricate communications)</li>
<li class="css-1650jxb e1mpr5v80">Find out the collaboration process with other roles, especially new roles you might not have interacted with
<ul>
<li class="css-1650jxb e1mpr5v80">For example, at Tandem, I switched from a primarily-backend role (DNS work at cloudflare, systems work at Deviceplane) to frontend/full-stack. My mistake was instead of asking how to work with our designer, I assumed design handoffs were a one-way street. I was wrong, of course, and ended up having a great handoff process with our designer, Bernat. I would give product and design feedback as I was handed designs, as well as suggestions for minor changes that would improve product velocity. But in order for us to make this relationship effective, I first had to understand it.</li>
</ul>
</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Find out how to do your job (low-level)
<ul>
<li class="css-1650jxb e1mpr5v80">What are the systems you&#x27;ll be building</li>
<li class="css-1650jxb e1mpr5v80">What are the repos you&#x27;ll be touching</li>
<li class="css-1650jxb e1mpr5v80">What are the connected systems (upstream, downstream)</li>
<li class="css-1650jxb e1mpr5v80">What&#x27;s oncall like, what metrics, tools, dashboards you need
<ul>
<li class="css-1650jxb e1mpr5v80">You&#x27;ll probably forget this—that&#x27;s okay. Better to have a vague idea of what you need to do, than no idea at all</li>
</ul>
</li>
<li class="css-1650jxb e1mpr5v80">Ask an experienced coworker for a rundown of how your main area of focus operates (this&#x27;ll be the main repo you&#x27;ll be touching), including a walkthrough of the code. After this, you should feel ready to jump into the code</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Engage with excitement, push boundaries, do not become jaded
<ul>
<li class="css-1650jxb e1mpr5v80">One of my founder friends remarked that part of the reason they hired interns was because interns bring energy. As a new hire, you too have this energy, excitement, and something to prove. Express it soon, or it will fade as work becomes routine.</li>
<li class="css-1650jxb e1mpr5v80">Read all the interesting docs, especially notes the founders have written
<ul>
<li class="css-1650jxb e1mpr5v80">At Segment, the founders had referenced [author&#x27;s] post on [commoditizing your complement], which was eye-opening perspective to hear on business strategy, as an engineering intern</li>
</ul>
</li>
<li class="css-1650jxb e1mpr5v80">Schedule coffee chats with people on your team, and new interesting people you meet—this is one of the best ways to learn about another role
<ul>
<li class="css-1650jxb e1mpr5v80">At Linkedin, I scheduled a 30m coffee chat with a director, who ended up extending it to an hour after he realized I was based in SF and had trekked down from SF to Sunnyvale for the meeting. People often want to reward you for making an effort to get to know them.</li>
</ul>
</li>
<li class="css-1650jxb e1mpr5v80">Browse all the channels</li>
<li class="css-1650jxb e1mpr5v80">Read all the interesting docs (and figure out what the travel policy is ;))
<ul>
<li class="css-1650jxb e1mpr5v80">At Cloudflare, there was an almost-hidden clause in the travel policy doc that noted you could get up to $500 for staying with a friend on a business trip, instead of booking a hotel. As a result, every time I visited Austin for work, I stayed with a coworker and earned $500 (and did them a favor by skipping a lunch and expensing them a good dinner) :)</li>
</ul>
</li>
<li class="css-1650jxb e1mpr5v80">Offer your opinions — sometimes a fresh set of eyes is the most useful thing you might have. Other times, an energetic response is a useful tool for leaders trying to energize or braisntorm with their team
<ul>
<li class="css-1650jxb e1mpr5v80">At LinkedIn, our extended team had an extended all-hands with a VP, and for what felt like minutes, nobody asked a question. I noticed he had pink laces on his gray Allbirds, asked him where he got them. Having my dumb (though well-received) question to set the bar low broke the ice enough for engineers with better questions than me to start talking.</li>
</ul>
</li>
<li class="css-1650jxb e1mpr5v80">Ask questions</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now, as you prepare to make the most of your first week and following month, remember: you&#x27;re off to a good start!</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/onboarding-quickly</link><guid isPermaLink="false">onboarding-quickly</guid><pubDate>Fri, 25 Nov 2022 00:00:00 GMT</pubDate></item><item><title><![CDATA[You don't have to upgrade your cloud VM's RAM]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This post is about saving money on hobby projects, by scraping the bottom of the barrel with what your cloud provider offers.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Most cloud providers have a free tier of hosting, with low RAM. For example, Fly.io currently offers 3x instances of a shared-1-cpu instance with 256mb RAM.
But what if you need more? <a href="https://fly.io/docs/about/pricing/#compute">Fly.io&#x27;s pricing page</a> shows you&#x27;d pay ~$10/mo for a 2gb RAM instance.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I have a side project that uses very bursty RAM, so it feels annoying to pay for 2gb RAM for a whole month, when I really only need it for a few minutes a day.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Enter the solution: swapping to disk.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Disk swap is when your OS uses available disk space as RAM (more info from the <a href="https://wiki.archlinux.org/title/swap#Swap_space">Arch wiki</a>). Since RAM is faster than disk, this has a performance downside, but nowdays most cloud instances have fast SSDs. They&#x27;ll still be about 10x slower than RAM, but if you&#x27;re still reading this, you&#x27;ll be too cheap to complain about the performance penalty.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="show-me-the-code" class="css-1oc01jt evim1t94">Show me the code!</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Alright! Note that this won&#x27;t work in Docker without privilege escalation, so you&#x27;ll have to run this <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">after</em> your Dockerfile is built.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After running this, an application that would otherwise have 2GB of free disk space will use that disk space for memory allocation.</p>
<pre><div style="font-size:12px"><div style="color:#f8f8f2;background:#282a36;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto;border-radius:0.3em"><code class="language-bash" style="color:#f8f8f2;background:none;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span class="token" style="color:#6272a4"># Allocate 2048MB (2GiB) to a swapfile</span><span>
</span>fallocate -l 2048M /swapfile
<span></span><span class="token" style="color:#f1fa8c">chmod</span><span> 0600 /swapfile
</span><span></span><span class="token" style="color:#f1fa8c">mkswap</span><span> /swapfile
</span>
<span></span><span class="token" style="color:#6272a4"># Optionally modify swappiness (the likelihood to use swap)</span><span>
</span><span></span><span class="token" style="color:#6272a4"># (default is 60 on most Linux systems)</span><span>
</span><span></span><span class="token" style="color:#6272a4"># More info: https://unix.stackexchange.com/a/88820</span><span>
</span><span></span><span class="token" style="color:#f1fa8c">echo</span><span> </span><span class="token" style="color:#bd93f9">90</span><span> </span><span class="token" style="color:#f8f8f2">&gt;</span><span> /proc/sys/vm/swappiness
</span>
<span></span><span class="token" style="color:#6272a4"># Enable the swap file</span><span>
</span><span></span><span class="token" style="color:#f1fa8c">swapon</span><span> /swapfile
</span></code></div></div></pre>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You&#x27;ll want to call this from your application code, as your app starts up. As <a href="https://community.fly.io/t/swap-memory/2749/4">noted</a> by a Fly maintainer, <a href="https://github.com/superfly/flyctl/blob/72736560d1a4119317dc18bb8913ab9a4d4d755b/scanner/templates/rails/standard/lib/tasks/fly.rake#L24-L36">Fly automatically does this for Rails projects</a>. This should prevent high/bursty-memory programs from being killed by the system OOM killer!</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="verify-it-works" class="css-1oc01jt evim1t94">Verify it works</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After running, you can run <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">free —mega</code> to see if it&#x27;s taken effect:</p>
<pre><div style="font-size:12px"><div style="color:#f8f8f2;background:#282a36;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto;border-radius:0.3em"><code class="language-bash" style="color:#f8f8f2;background:none;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span class="token" style="color:#6272a4"># free —mega</span><span>
</span><span>              total        used        </span><span class="token" style="color:#f1fa8c">free</span><span>      shared  buff/cache   available
</span><span>Mem:            </span><span class="token" style="color:#bd93f9">231</span><span>          </span><span class="token" style="color:#bd93f9">75</span><span>          </span><span class="token" style="color:#bd93f9">95</span><span>           </span><span class="token" style="color:#bd93f9">0</span><span>          </span><span class="token" style="color:#bd93f9">60</span><span>         </span><span class="token" style="color:#bd93f9">148</span><span>
</span><span>Swap:          </span><span class="token" style="color:#bd93f9">2147</span><span>          </span><span class="token" style="color:#bd93f9">65</span><span>        </span><span class="token" style="color:#bd93f9">2081</span><span>
</span></code></div></div></pre>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now we see that we&#x27;ve got about 2gb of memory from swap thanks to our changes!</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/swap-cloud-vm</link><guid isPermaLink="false">swap-cloud-vm</guid><pubDate>Sat, 10 Dec 2022 00:00:00 GMT</pubDate></item><item><title><![CDATA[Query your Gmail account by hand using IMAP]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Have you ever wondered how mail clients work under the hood? Most mail clients fetch your mail with a protocol called called IMAP, and it&#x27;s surprisingly human-readable.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s how it looks:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/query-imap-by-hand/images/imap-query-example.png" alt="Three example IMAP queries" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Three examples of how you might use the IMAP <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">FETCH</code> query to see the raw data that your mail client uses</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Above, I&#x27;ve queried the same message in three different ways, each returning different data. More info on IMAP commands and queries can be found in the latest RFC: <a href="https://www.rfc-editor.org/rfc/rfc9051">IMAP4rev2</a>.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="querying-your-own-gmail-with-imap" class="css-1oc01jt evim1t94">Querying your own Gmail with IMAP</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s how you can use IMAP to query your own Gmail account.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">First, you&#x27;ll want to make an app password. This is a password that isn&#x27;t your real password, but you can give to an app to use for certain functionality on your account. They&#x27;re nice to have for testing. You can either <a href="https://support.google.com/accounts/answer/185833">follow the instructions here</a> or create one directly <a href="https://myaccount.google.com/apppasswords">at this link</a>.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now, you can use this app password to connect to Gmail! You can use a variety of programs that will let you create a TLS client. We&#x27;re writing IMAP by hand, after all.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For example, you could connect with ncat using: <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">ncat —ssl imap.gmail.com 993 —crlf</code>. Or you could connect with socat using: <code class="css-1hue6hc e1mpr5v84">socat ssl:imap.gmail.com:993,crlf readline</code>. Essentially, these commands connect to Gmail&#x27;s IMAP server over SSL, and replace your stdin <code class="css-1hue6hc e1mpr5v84">\n</code> with <code class="css-1hue6hc e1mpr5v84">\r\n</code>, <a href="https://www.rfc-editor.org/rfc/rfc3501#section-2.2">which is required for IMAP commands</a>.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After opening a connection, you can login with your password:</p>
<pre><div style="font-size:12px"><div style="color:#f8f8f2;background:#282a36;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto;border-radius:0.3em"><code class="language-bash" style="color:#f8f8f2;background:none;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span>a LOGIN youremail@gmail.com yourapppassword
</span></code></div></div></pre>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Which should have the server respond with:</p>
<pre><div style="font-size:12px"><div style="color:#f8f8f2;background:#282a36;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto;border-radius:0.3em"><code class="language-bash" style="color:#f8f8f2;background:none;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span>* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS </span><span class="token assign-left" style="color:#f8f8f2">COMPRESS</span><span class="token" style="color:#f8f8f2">=</span><span>DEFLATE ENABLE MOVE CONDSTORE ESEARCH </span><span class="token assign-left" style="color:#f8f8f2">UTF8</span><span class="token" style="color:#f8f8f2">=</span><span>ACCEPT LIST-EXTENDED LIST-STATUS LITERAL- SPECIAL-USE </span><span class="token assign-left" style="color:#f8f8f2">APPENDLIMIT</span><span class="token" style="color:#f8f8f2">=</span><span class="token" style="color:#bd93f9">35651584</span><span>
</span><span>a OK youremail@gmail.com authenticated </span><span class="token" style="color:#f8f8f2">(</span><span>Success</span><span class="token" style="color:#f8f8f2">)</span><span>
</span></code></div></div></pre>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Great, now select a mailbox, such as your inbox:</p>
<pre><div style="font-size:12px"><div style="color:#f8f8f2;background:#282a36;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto;border-radius:0.3em"><code class="language-bash" style="color:#f8f8f2;background:none;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span>a SELECT INBOX
</span></code></div></div></pre>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And you can query away! Try running <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">a FETCH 1 FAST</code> to see how old your first email in your inbox is.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now that you&#x27;re at the bottom of this post, you might be interested in a project I&#x27;m working on to automagically sort your emails. <a href="https://www.endbox.ai/">If that sounds interesting, you can sign up for the waitlist here.</a></p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/query-imap-by-hand</link><guid isPermaLink="false">query-imap-by-hand</guid><pubDate>Tue, 20 Jun 2023 00:00:00 GMT</pubDate></item><item><title><![CDATA[My first month as an Engineer doing Product Management]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">Author&#x27;s note: this stream-of-consciousness journal entry has not been through the editing cycle I try to apply to posts. That said, it&#x27;s been a useful reference to at least one early-career PM, so I&#x27;ve made it public. I hope you find it helpful.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I&#x27;m still an engineer, but we&#x27;re trying out something new at Jam (where I work). For this 6 week engineering sprint, I&#x27;ll be PM&#x27;ing the features we build.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This is partly because the sprint has a highly-technical focus (our developer tools), and partly because once earlier, around a year ago, I asked to improve our developer tools.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That time, I gave my case for why our devtools should be improved, and asked for just three weeks to clean up the UX to make them look and feel more like native browser devtools. I got six weeks, and the option for Jam to pay <a href="https://bernatfortet.com/">Bernat</a> (the designer I worked with at Tandem) to do designs for us for a couple hours—an option I obviously took.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That project turned out well, and Jam as a whole has been doing great in the year since. So we&#x27;re at the point where our devtools yet-again have access to resources to make them even better.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Namely, engineering resources: me, and the rest of the engineering team. That takes us back to the title. For these 10 weeks (4wks planning + 6wks eng sprint), I&#x27;m not exactly a full-time PM. I&#x27;m a PM who&#x27;s also an engineer. So I&#x27;ve even allocated myself to the engineering sprint.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Essentially, I&#x27;m an optimization algorithm for a human, as I decide where to put my time between product and engineering. For my first four weeks, I&#x27;m trying to do product work, while only taking on eng work when there&#x27;s an urgent or relevant bug. For my last week, I&#x27;m prioritizing some eng work ahead, to keep my teammates unblocked in their current project, then doing product work to keep them unblocked for their next project, then doing eng work so I can finish my current project.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For context, <a href="https://jam.dev">Jam</a> is a Browser Extension which lets PMs, QAs, support, etc., quickly report bugs to their issue tracker, for their engineering team. Then, when an engineer views a bug on Jam, they see the console logs, network requests, and a video, screenshot, or session replay. We call the eng-specific part of our app the &quot;devtools&quot;. My goal is to, with 6 weeks of our engineering team&#x27;s time, improve the experience of engineers using devtools as much as I can.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/first-weeks-being-pm/images/overall.png" class="css-1k43lf1 ef55ps60"/>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">An example of what <style data-emotion="css bh5kom">.css-bh5kom{color:blue;color:-webkit-link;cursor:pointer;-webkit-text-decoration:underline;text-decoration:underline;}</style><span href="https://jam.dev/c/484512ee-f321-4507-b210-12d10f1ab79b" class="css-bh5kom evim1t91">a bug filed with Jam</span> looks like today.<br/><br/>A developer may read the bug description, watch the session replay, look at console logs, or inspect the body of a network request, as part of their debugging process.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Now, with your understanding of how this works, here&#x27;s my perspective on how it feels.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="and-how-does-that-feel" class="css-1oc01jt evim1t94">And how does that feel?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Well, I just finished week 5, and it&#x27;s been like a plunge in cold water! Remember on a hot summer day, you might hop into a swimming pool, and even if the water was cold, it felt refreshing? But first it felt cold?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So first you&#x27;re eyeing the pool, and it looks great. Then you jump in, and it&#x27;s cold. But then you start swimming, and heat up. As you reach the surface again to breathe, it&#x27;s starting to get refreshing.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s how it went:</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">On my first week, I was still wrapping up a feature and some bugfixes unrelated to devtools. At the same time, I was doing market research: thinking of ideas, asking friends/developers/our eng team, looking at customer feedback, and looking at other products (mostly Chrome devtools), to create and pick features we might build.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">This felt relatively simple. I&#x27;d already done market research for half of my eng/product internship at LinkedIn. I&#x27;d compare it to looking at the pool.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Then, the second week, I scoped out the cost and the expected impact of the potential devtools features, and decided which ones we&#x27;d prioritize for our 6 week sprint. Once I had that list, I began writing Product Requirement Documents (PRDs) for the features we were going to build. These are documents that should contain everything an engineer needs to build the feature, including handling edge cases, design mocks, and text copy.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">This felt adventurous but doable. I&#x27;d have to express my opinions and be the authority on product decisions here—previously I was always able to ask the PM if I felt unsure. I&#x27;d compare this to jumping into the pool, cannonball style.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Then, the third week, I continued writing PRDs, and started pairing with our designer to mock designs for them. This is a lot more involved than your normal product + design collaboration, because devtools are very opinionated and intricate. As a technical PM, you need to be there to assert those opinions that engineers (users) will have, but at the same time, you&#x27;re not a designer. So it&#x27;s a tight collaboration.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">This started to become a little overwhelming, as the sheer amount of meetings began to balloon. I&#x27;d compare it to jumping in the pool, and feeling the cold shock of the water.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Next, the fourth week, I continued writing PRDs in tandem with designs, and finished designs for these PRDs with our designer. I also worked with our PM-founder, Dani, to decide how to allocate engineers onto these project.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">This felt a little tricky: meetings decreased, but decisionmaking and managing my own time increased. I&#x27;d compare this to swimming up from the bottom of the pool.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And most recently, the fifth week, I did a couple of engineering kickoffs to hand off two PRDs to the engineers working on them. Then, I quickly finished a small feature to unblock them—they&#x27;ll hook into the code in it as part of the ticket they&#x27;re currently working on. After that, I continued writing PRDs, creating the final PRD (but not finishing designs for it).</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">This again felt overwhelming and tricky. meetings increased, decisionmaking increased, and I had to manage my own time better than before. But I knew it&#x27;d get easier soon. I&#x27;d compare this to swimming, almost at the surface.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At this point, I have to kick off two more features with engineers next week, work on the last two unfinished PRDs (one has design assets, one needs both product and design work). Then, I can work on the next feature that I&#x27;ve allocated myself onto as an engineer.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I expect the following weeks to be calmer (starting 2wks from now), as most of the product planning will have been done, and I&#x27;ll be mostly in engineer-mode. Then, when other engineers wrap up their projects, I&#x27;ll kick off another project with them and work with our marketer to launch updates.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So that&#x27;s the overview.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="my-mistakes" class="css-1oc01jt evim1t94">My mistakes</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">As usual, I made mistakes. Nothing crazy, but I&#x27;ll be unlikely to make them next time.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Chronologically from the top, they are:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">As I did market research, I didn&#x27;t consider that after I do all of the research on what exists (thinking as a developer, reading customer feedback, sourcing developer opinions, looking at existing products), I&#x27;d still have more thoughts that I would personally come up with at the end. So I ended up rushing near the end, and I don&#x27;t think I did a good job capturing (and thus prioritizing) some of my more experimental ideas.
<ul>
<li class="css-1650jxb e1mpr5v80">Giving me a hybrid PM role for a whole 6wk eng sprint is already experimental (for context, this is also the first time we&#x27;ve tried 6wk eng sprints at work), so maybe it&#x27;s better to not add too much variance with experimental ideas. But I do wish I had more time to flesh these ideas out, they seem interesting.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">As I was writing PRDs in week 2 and week 3, I suddenly realized that while a PRD communicates product requirements to engineers (and that had been all I&#x27;d experienced as an engineer), there was something more to a PRD. <br/>
<br/>
Turns out, a designer also needs to know the product requirements. So I went back and typed out the full user flow from the perspective of what the user needed to do, for PRDs with complicated flows. Then, for PRDs with specific cases that needed to be designed, I went back, and typed out the cases that needed to be covered.
<ul>
<li class="css-1650jxb e1mpr5v80">This wasted both product time and design time. Design time was more important, as it was more limited.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Next, as I allocated engineers, I realized that I didn&#x27;t chart out the allocation of engineers earlier, I just kinda winged it and estimated in my head. It wasn&#x27;t a huge mistake—I hadn&#x27;t overpromised any customers. But I had gone through the design process for most of our features, and it&#x27;d be a waste of design and product time if we had to cut a fully-scoped feature.
<ul>
<li class="css-1650jxb e1mpr5v80">Luckily, we managed to fit everything in (or I just made another mistake and overpromised my own capacity as an engineer, we&#x27;ll see).</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Finally, for the fifth week, I didn&#x27;t think to show to the team what our sprint would look like on Monday at standup (to get them excited), to involve marketing (to give them heads-up), or to pipeline the work I was doing (to make sure people are unblocked in the future).
<ul>
<li class="css-1650jxb e1mpr5v80">Luckily our PM-founder Dani thought of these things, and mentioned them to me, so I managed to benefit from her foresight 😛</li>
</ul>
</li>
</ul>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="the-biggest-mistake" class="css-1887rzz evim1t95">The biggest mistake</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But the biggest source of pressure was my last mistake: the unexpected time-cost of things I needed to do that didn&#x27;t produce deliverables.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For example, a few sources of time pressure:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">I&#x27;ve been getting my wrists checked out, and going to Occupational Therapy (OT) to get this sorted out, which takes 2.5hrs a week on average</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Two of our engineers recently joined, and as engineers onboard, they need help with:
<ul>
<li class="css-1650jxb e1mpr5v80">dealing with our tooling, CI, local dev env</li>
<li class="css-1650jxb e1mpr5v80">architectural overviews of dataflows/parts of our codebase</li>
<li class="css-1650jxb e1mpr5v80">pair programming and/or debugging</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Having regular 1-1s with teammates, which used to be a nice forced-break from programming, lost this benefit, given I was already frqeuently context-switching.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Being the engineer with the most experience on our devtools codebase (due to my earlier chance to improve them) and devtools-adjacent data flows (coincidentally, due to other feature work I&#x27;d done), I was the go-to person for background on them.
<ul>
<li class="css-1650jxb e1mpr5v80">This meant that after I kicked off devtools features with an engineer, I&#x27;d spend additional time in calls/DMs giving background for architecture or technical decisions</li>
</ul>
</li>
</ol>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-ive-learned" class="css-1oc01jt evim1t94">What I&#x27;ve learned</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">These 5 weeks have given me more respect for PMs. It&#x27;s easy to see a good PM do their job, without realizing all the parts they have to keep coordinated in lockstep.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I already knew how important communication was, but I didn&#x27;t realize how hard it was. It&#x27;s easy for things to slip between the cracks, yet optional communication (like giving an overview of the sprint to the whole team in standup) often has an outsized impact (like getting everyone excited).</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Most importantly, I learned how important excitement is. Most of us would agree:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When work feels meaningless, I feel demotivated.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When work gives me potential to do good work, learn, and make a product people enjoy, I feel excited.</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, when kicking off features with engineers in last week, I tried to group features together for each engineer, allocate enough time to do features well, and be flexible when engineers want to make product and design changes. The idea is to let engineers own the features they&#x27;re working on—just like when I upgraded devtools myself, last time.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It ended up being helpful to me, too! It turns out that when an engineer feels that they&#x27;re allowed to make product and design decisions, they might make better decisions than you—the PM! Think about it: they&#x27;re focusing deeply on one feature, while you&#x27;re spread out over multiple features at a time. That means they have time to focus on the nuance of tiny behaviors that they implement, but you might not think to cover in your PRD.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="obligatory-callout" class="css-1oc01jt evim1t94">Obligatory callout</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Anyway, if you enjoyed reading this journal-style post, and thought you might have fun working here—<a href="https://careers.jam.dev/">check out Jam</a>! To be clear, my engineering weeks are much more relaxing than the hybrid role I&#x27;ve written about here ;)</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/first-weeks-being-pm</link><guid isPermaLink="false">first-weeks-being-pm</guid><pubDate>Fri, 07 Jul 2023 00:00:00 GMT</pubDate></item><item><title><![CDATA[How do you get a bimodal distribution from a uniform distribution function?]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Given a uniformly distributed random-number-generating function, <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">f()</code>, how can you transform it into a function with a bimodal distribution, <code class="css-1hue6hc e1mpr5v84">g()</code>?</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/normal-dist.png" alt="caption: A histogram of a normal distribution. Randomly sampled values are evenly weighted across the output range." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">A histogram of a normal distribution. Randomly sampled values are evenly weighted across the output range.</span></div></span></div>
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"><img src="/images/post/transforming-distributions/images/bimodal-dist.png" alt="caption: A bimodal distribution. Most values (mode) clump in two (bi) heaps, hence &quot;bimodal&quot;." class="css-1k43lf1 ef55ps60"/></div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">A bimodal distribution. Most values (mode) clump in two (bi) heaps, hence &quot;bimodal&quot;.</span></div></span></div>
</div></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This is the question that I dealt with as I overengineered my blog. I wanted to tilt my posts, to give the effect of papers loosely placed on a desk.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/angled-posts-preview.png" alt="caption: a few angled posts" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">a few angled posts</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I was looking to generate many different posts at slightly different angles, which required some randomness. But which type of randomness would I want to use?</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/math-random-samples.png" alt="caption: A histogram chart of `Math.random()` samples." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">A histogram chart of <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.random()</code> samples.</span></div></span></div>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="simple-transform-functions" class="css-1oc01jt evim1t94">Simple transform functions</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Just to understand what some common transforms might look like, I tried plotting them out.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This histogram, which comes from plotting <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.pow(Math.random(), 2)</code> samples, looks like a power law distribution:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/pow-dist-graph.png" alt="caption: (About half of the total samples in this distribution are less than 0.25.)" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">(About half of the total samples in this distribution are less than 0.25.)</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The distribution of these <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.sqrt(Math.random())</code> samples feels fairly linear:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/sqrt-dist-graph.png" alt="caption: (This is the same as `Math.pow(Math.random(), 1/2)`)" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">(This is the same as <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.pow(Math.random(), 1/2)</code>)</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Interesting, but how do we get a normal distribution?</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="getting-a-normal-distribution" class="css-1oc01jt evim1t94">Getting a normal distribution</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Combining the two above functions, we get closer. Their combination looks like an attempt at building a sandcastle with dry sand:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/sandcastle-looking-graph.png" alt="caption: This distribution comes from `Math.sqrt(Math.random()) + Math.pow(Math.random(), 2)`." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">This distribution comes from <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.sqrt(Math.random()) + Math.pow(Math.random(), 2)</code>.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Remember the linear-looking <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.sqrt(Math.random())</code> function? When sampled three times and added together, it gives us a normal-looking distribution:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/starting-to-look-normal.png" alt="caption: It&#x27;s a little misshapen, but `Math.sqrt(Math.random()) + Math.sqrt(Math.random()) + Math.sqrt(Math.random())` looks normal enough." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">It&#x27;s a little misshapen, but <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.sqrt(Math.random()) + Math.sqrt(Math.random()) + Math.sqrt(Math.random())</code> looks normal enough.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You might&#x27;ve guessed the pattern by now.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If we add <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.random()</code> on itself a few times, we get an even-more normal looking distribution. The more times we do it, the more-normal the graph starts to look.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/more-normal-graph.png" alt="caption: `Math.random() + Math.random() + Math.random()`" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99"><style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.random() + Math.random() + Math.random()</code></span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Great, but why does this work?</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="why-does-adding-samples-of-a-uniform-distribution-give-us-a-normal-distribution" class="css-1oc01jt evim1t94">Why does adding samples of a uniform distribution give us a normal distribution?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This may seem confusing. So let&#x27;s break down the possibilities. Imagine instead a uniform distribution that gives integers in the range <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">[1, 6]</code>.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">One provider of this distribution function is the common six-sided die.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When we have one die, we have an equal 1/6 chance of getting any value.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When we have two dice, each die still has an equal 1/6 chance of getting any value. However, if you&#x27;ve played any dice-rolling game, you might know that the chance of rolling a 12 is much lower than the chance of rolling a 7.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Why is this?</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">To roll a two, you must roll two 1&#x27;s. We&#x27;ll call this a (1, 1).</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">To roll a three, could roll:
<ul>
<li class="css-1650jxb e1mpr5v80">(1, 2)</li>
<li class="css-1650jxb e1mpr5v80">(2, 1)</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">To roll a four, you could roll:
<ul>
<li class="css-1650jxb e1mpr5v80">(1, 3)</li>
<li class="css-1650jxb e1mpr5v80">(2, 2)</li>
<li class="css-1650jxb e1mpr5v80">(3, 1)</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">To roll a five, you could roll:
<ul>
<li class="css-1650jxb e1mpr5v80">(1, 4)</li>
<li class="css-1650jxb e1mpr5v80">(2, 3)</li>
<li class="css-1650jxb e1mpr5v80">(3, 2)</li>
<li class="css-1650jxb e1mpr5v80">(4, 1)</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">And so on, with permutation count increasing until 7, and then falling down after..</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">To roll an 11, you could roll:
<ul>
<li class="css-1650jxb e1mpr5v80">(5, 6)</li>
<li class="css-1650jxb e1mpr5v80">(6, 5)</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">And to roll a 12, you must roll a (6, 6).</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Since each die roll is as likely as any other die value, each ordered die permutation (an ordered combination) is as likely as any other ordered die permutation.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That is, rolling a (1, 1) is as likely as rolling a (5, 6) (ordered). In the former, you have a 1/6 chance of rolling a 1, then another 1/6 of rolling the next one. In the latter, you have a 1/6 chance of rolling a five, then a 1/6 chance of rolling a 6.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That means that each permutation is equally likely, so the likelihood of rolling a specific sum is proportional to the number of permutations that can create it.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In other words, when you roll two dice, you have six ways to roll a 7, but only one way to roll a 2. Then, it would make sense that our distribution curve of combined dice values show 7 being six times as common as a 2.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The more dice you combine, the more you shift the distribution more closely to a normal distribution. Why does this approximate the normal curve shape specifically? It&#x27;s explained by the <a href="https://en.wikipedia.org/wiki/Central_limit_theorem">central limit theorem</a>, though honestly I don&#x27;t quite understand it.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In lieu of that, here is a <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">live demo</strong> I&#x27;ve created for you to simulate the probability of outcomes. It generates all possible sums of N rolls of an M-sided die, and plots the count of each sum:</p>
<style data-emotion="css dg6unz">.css-dg6unz{background-color:rgb(255, 247, 232);border:2px solid #0e707e;border-radius:8px;padding:12px;padding-top:8px;padding-bottom:8px;}</style><div class="css-dg6unz e19usug60"><div class="css-0 e19usug62"></div><style data-emotion="css 1sjo1tg">.css-1sjo1tg{color:#111111;font-family:Lora,Quattro,Charter;font-style:italic;font-weight:800;text-align:center;margin-top:100px;margin-bottom:100px;}</style><div class="css-1sjo1tg e19usug61">[Note for reader]<br/>Javascript must be supported to see the live demo that appears in this block.</div></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Moving back to our real-world application, how can we create a bimodal distribution, with our normal probability distribution?</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="creating-a-bimodal-distribution" class="css-1oc01jt evim1t94">Creating a bimodal distribution</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Well, the easiest way is to simply alternate between picking samples from two transformed normal probabilities:</p>
<pre><div style="font-size:12px"><div style="color:#f8f8f2;background:#282a36;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;padding:1em;margin:.5em 0;overflow:auto;border-radius:0.3em"><code class="language-js" style="color:#f8f8f2;background:none;text-shadow:0 1px rgba(0, 0, 0, 0.3);font-family:Consolas, Monaco, &#x27;Andale Mono&#x27;, &#x27;Ubuntu Mono&#x27;, monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none"><span class="token" style="color:#6272a4">// Where randNormal is a random-number-generating function</span><span>
</span><span></span><span class="token" style="color:#6272a4">// with a normal probability distribution</span><span>
</span>
<span></span><span class="token" style="color:#8be9fd">const</span><span> </span><span class="token" style="color:#ff79c6">PEAK_DISTANCE</span><span> </span><span class="token" style="color:#f8f8f2">=</span><span> </span><span class="token" style="color:#bd93f9">0.7</span><span class="token" style="color:#f8f8f2">;</span><span>
</span><span></span><span class="token" style="color:#8be9fd">const</span><span> </span><span class="token" style="color:#ff79c6">PEAK_WEIGHT</span><span> </span><span class="token" style="color:#f8f8f2">=</span><span> </span><span class="token" style="color:#bd93f9">0.5</span><span class="token" style="color:#f8f8f2">;</span><span>
</span><span></span><span class="token" style="color:#8be9fd">function</span><span> </span><span class="token" style="color:#f1fa8c">bimodalSample</span><span class="token" style="color:#f8f8f2">(</span><span class="token" style="color:#f8f8f2">)</span><span> </span><span class="token" style="color:#f8f8f2">{</span><span>
</span><span>	</span><span class="token control-flow" style="color:#8be9fd">return</span><span> </span><span class="token known-class-name" style="color:#f1fa8c">Math</span><span class="token" style="color:#f8f8f2">.</span><span class="token method property-access" style="color:#f1fa8c">random</span><span class="token" style="color:#f8f8f2">(</span><span class="token" style="color:#f8f8f2">)</span><span> </span><span class="token" style="color:#f8f8f2">&lt;</span><span> </span><span class="token" style="color:#ff79c6">PEAK_WEIGHT</span><span>
</span><span>		</span><span class="token" style="color:#f8f8f2">?</span><span> </span><span class="token" style="color:#f1fa8c">randNormal</span><span class="token" style="color:#f8f8f2">(</span><span class="token known-class-name" style="color:#f1fa8c">Math</span><span class="token" style="color:#f8f8f2">.</span><span class="token property-access">random</span><span class="token" style="color:#f8f8f2">)</span><span> </span><span class="token" style="color:#f8f8f2">*</span><span> </span><span class="token" style="color:#f8f8f2">(</span><span class="token" style="color:#bd93f9">1</span><span> </span><span class="token" style="color:#f8f8f2">-</span><span> </span><span class="token" style="color:#ff79c6">PEAK_DISTANCE</span><span class="token" style="color:#f8f8f2">)</span><span>
</span><span>		</span><span class="token" style="color:#f8f8f2">:</span><span> </span><span class="token" style="color:#f1fa8c">randNormal</span><span class="token" style="color:#f8f8f2">(</span><span class="token known-class-name" style="color:#f1fa8c">Math</span><span class="token" style="color:#f8f8f2">.</span><span class="token property-access">random</span><span class="token" style="color:#f8f8f2">)</span><span> </span><span class="token" style="color:#f8f8f2">*</span><span> </span><span class="token" style="color:#f8f8f2">(</span><span class="token" style="color:#bd93f9">1</span><span> </span><span class="token" style="color:#f8f8f2">-</span><span> </span><span class="token" style="color:#ff79c6">PEAK_DISTANCE</span><span class="token" style="color:#f8f8f2">)</span><span> </span><span class="token" style="color:#f8f8f2">+</span><span> </span><span class="token" style="color:#ff79c6">PEAK_DISTANCE</span><span class="token" style="color:#f8f8f2">;</span><span>
</span><span></span><span class="token" style="color:#f8f8f2">}</span><span>
</span></code></div></div></pre>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If this seems too easy, note that bimodal distributions are frequently caused by just this: sampling two different groups into the same dataset.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/bimodal-code-output.png" alt="caption: Sampling the above function gives us this plot." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Sampling the above function gives us this plot.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You can change the <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">PEAK_DISTANCE</code> and <code class="css-1hue6hc e1mpr5v84">PEAK_WEIGHT</code> parameters to change the distribution shape:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/transforming-distributions/images/bimodal-modified-code-output.png" alt="caption: Here, we set `PEAK_DISTANCE` to 0.6, and `PEAK_WEIGHT` to 0.2." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Here, we set <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">PEAK_DISTANCE</code> to 0.6, and <code class="css-1hue6hc e1mpr5v84">PEAK_WEIGHT</code> to 0.2.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For my use case, I kept the distribution even between the two sides. You can see its effects live on <a href="https://blog.cyrusroshan.com">my blog homepage</a>. Note that post angles won&#x27;t change between updates or page refreshes. This consistency is achieved by using a <style data-emotion="css 1hue6hc">.css-1hue6hc{background-color:#f6f6f6;color:#e01d5a;border:1px solid #dadada;border-radius:4px;padding:4px;padding-top:1px;padding-bottom:1px;overflow-wrap:break-word;}</style><code class="css-1hue6hc e1mpr5v84">Math.random()</code>-like function which can be seeded with the post&#x27;s ID. Seeding the function this way gives us the same angle for each post across refreshes.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And that&#x27;s it! You now have a bimodal distribution using only a uniform distribution function as your randomness source.</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/transforming-distributions</link><guid isPermaLink="false">transforming-distributions</guid><pubDate>Tue, 02 Jan 2024 00:00:00 GMT</pubDate></item><item><title><![CDATA[Building a Network Stack for our Browser Extension]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This probably sounds a bit crazy. Or, you may have forgotten what a network stack is.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But before you dismiss the concept of a layered protocol stack inside of a browser extension as ravings by a madman, or a concept too convoluted to bother understanding, let me provide some context.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We’ll go over the background info of:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">What our browser extension does</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">What the architecture of a MV2 browser extension looks like</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">How the components of a browser extension communicate</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Our communication system’s breaking point (the problem)</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And then we’ll break down what a network stack is, and why it made sense as the solution to our problem.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="so-what-does-jam-do-anyway" class="css-1oc01jt evim1t94">So, <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">what does Jam do</strong>, anyway?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At Jam, our engineering team builds a browser extension for reporting bugs.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Our extension automatically captures bug data, such as:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">console logs</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">network requests</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">screenshot/video/DOM instant replay</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">page metadata</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">repro steps</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">device info, timestamp, viewport size, etc.,</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So that when a Product Manager, QA specialist, Designer, etc., files a bug, the bug automatically contains all the info an engineering team needs to debug the bug.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Engineers like this because they don’t need to hop on call. Bug reporters (PMs, QAs) like Jam because it integrates with issue trackers (like Jira and Linear) so they can rapidly fire off a bug report with all the data embedded inside it.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That’s the gist. Underneath the surface, there are a lot of moving pieces that make this possible.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-do-the-components-of-a-browser-extension-look-like" class="css-1oc01jt evim1t94">What do the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">components of a browser extension</strong> look like?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">Note: at time of writing, we’re using the Manifest v2 (MV2) architecture, supported by Firefox and Chrome/Chromium-based browsers.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Within a browser extension, there are a handful of different pieces (all of which are optional):</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">One <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">background script</em>, which is persistent in the background</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">One <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">popup window</em> per browser window</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">One or more <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">content scripts</em> per browser tab</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">One or more <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">host scripts</em> per browser tab</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">Note: This is a simplified model. For example, if your extension is running in <a href="https://developer.chrome.com/docs/extensions/mv2/manifest/incognito">split mode</a> (which is a non-default behavior), you can have multiple background script instances. But generally, this structure applies for nearly all browser extensions.</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Take for example a Chrome instance with two windows open, with each window having two tabs open. A browser extension running on this Chrome instance could be arranged like so:</p>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/extension-network-stack/images/image-1.png" alt="Browser extension components" class="css-1k43lf1 ef55ps60"/>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="how-can-the-components-of-a-browser-extension-communicate" class="css-1oc01jt evim1t94">How can the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">components</strong> of a browser extension <strong class="css-13l2ows evim1t910">communicate?</strong></h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Across the different components of the browser extension, there are a few different messaging APIs. Each API is used to communicate between different components.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">These APIs bridge the following components:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">We can use <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">chrome.runtime.sendMessage</strong> between:
<ul>
<li class="css-1650jxb e1mpr5v80"><strong class="css-13l2ows evim1t910">popup</strong> and <strong class="css-13l2ows evim1t910">background</strong> (bidirectional)</li>
<li class="css-1650jxb e1mpr5v80"><strong class="css-13l2ows evim1t910">content script</strong> to <strong class="css-13l2ows evim1t910">popup</strong> (one way)</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">We can use <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">chrome.tabs.sendMessage</strong> between:
<ul>
<li class="css-1650jxb e1mpr5v80"><strong class="css-13l2ows evim1t910">background</strong> to <strong class="css-13l2ows evim1t910">content script</strong> (one way)</li>
<li class="css-1650jxb e1mpr5v80"><strong class="css-13l2ows evim1t910">popup</strong> to <strong class="css-13l2ows evim1t910">content script</strong> (one way)</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">We can use <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">window.postMessage</strong> between:
<ul>
<li class="css-1650jxb e1mpr5v80"><strong class="css-13l2ows evim1t910">content script</strong> and <strong class="css-13l2ows evim1t910">host script</strong> (bidirectional)</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In essence, all of the components are connected, like so:</p>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/extension-network-stack/images/image-2.png" alt="Connected components" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But of course, if sending messages was as easy as this diagram seems, this blog post wouldn’t exist.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-messaging-difficulties-does-this-setup-have" class="css-1oc01jt evim1t94">What <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">messaging difficulties</strong> does this setup have?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For a long time, we used the native APIs directly.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">However, with native APIs alone, we have the following issues:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Different underlying messaging APIs:</strong> Each component has its unique way of sending messages.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Messages have size constraints (on some APIs):</strong> Some messages are too big to fit through the API pipeline.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Some components cannot communicate directly:</strong> Certain components can&#x27;t talk directly, requiring a &#x27;middleman&#x27;.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Multiple Tabs, Popups can exist independently:</strong> Keeping track of multiple, independent components can be tricky.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Messages can be dropped:</strong> e.g. Popup is closed, Tab gets closed while receiving, Tab’s thread is processing so much that the event loop can’t pull queued messages + respond/ack them before they time out.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Sharing object URLs not allowed to/from an incognito context:</strong> sending object URLs (a trick for circumventing message size constraints) from your background script to a content script won’t work, if the content script is in an incognito tab.</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This last point was what finally forced us to build a network stack.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="hitting-our-breaking-point-incognito" class="css-1oc01jt evim1t94">Hitting our <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">breaking point</strong>: Incognito</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, let me provide the business context behind this feature.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Some of Jam’s biggest power-users do Quality Assurance (QA). They aim to test and break an app as fast as possible, going through dozens of flows over the course of a day, doing manual regression tests, and putting new features under a stress test before release.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When you’re testing so many flows, Incognito Mode is an essential part of your toolkit. It lets you instantly access a logged-out instance of your web app, which makes testing new user flows much easier. Plus, some apps have different behavior in incognito mode, which requires additional testing (looking at you Netflix, why won’t you let me use incognito mode).</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">All that to say, adding incognito support to Jam was important.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="why-did-we-need-to-rebuild" class="css-1oc01jt evim1t94">Why did we need to <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">rebuild?</strong></h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In order to understand our problem with our system up until now, we need to understand the flow for a user creating a bug report in incognito.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Before a user can submit a bug report, we need to display a <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">preview</strong> of the bug report in the tab they’re filing the bug from.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This preview shows the user their network errors, lets them trim videos/instant replays, annotate screenshots, write a title/description, and directly file bug reports to an issue tracker or Slack channel, if they wish:</p>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/extension-network-stack/images/image-3.png" alt="Jam Modal showing an instant replay preview" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To create this preview, data is sent from the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">background script</strong> to the <strong class="css-13l2ows evim1t910">content script</strong>. Some elements of preview data (e.g. DOM Instant Replay) <strong class="css-13l2ows evim1t910">can’t fit in a single message:</strong> they exceed the size constraint of the <strong class="css-13l2ows evim1t910">chrome.tabs.sendMessage</strong> API.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To get around this on non-incognito tabs, we use a neat trick: you can <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">create a URL</strong> for a JavaScript object using <strong class="css-13l2ows evim1t910">window.URL.createObjectURL</strong> on one end, and <strong class="css-13l2ows evim1t910">fetch the URL</strong> on the other end to transfer large objects. Using this method, both processes can share large objects that wouldn’t fit in a single message.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Except this method won’t work between the background script and an incognito tab. Incognito tabs have different object URL contexts. Without this trick, we can’t circumvent message size constraints. <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Message chunking must be implemented.</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But our existing system is a simple layer directly above native messaging APIs, so <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">adding chunking requires a rebuild.</strong></p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="do-our-problems-seem-familiar" class="css-1oc01jt evim1t94">Do our problems seem familiar?</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Remember our messaging difficulties from before? Those problems are actually <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">…general networking problems.</em></span></p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Different underlying messaging APIs?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Different link layer protocols (Ethernet vs Wifi)</em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Messages have size constraints (on some APIs)?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Wifi/Ethernet packet-size limit</em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Some components cannot communicate directly?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Routing can require hops</em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Multiple Tabs, Popups can exist independently?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Multiple independent devices</em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Messages can be dropped?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Packet loss</em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Sharing object URLs not allowed to/from an incognito context?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Separate machines, data must be serialized</em></span></li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Looks like our browser extension’s components have similar communication problems to devices accessing the Internet. The solution to our shared problem set? <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Create a network stack.</strong></p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="what-is-a-network-stack" class="css-1oc01jt evim1t94">What is a <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">network stack?</strong></h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">A network stack is a set of <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">layered protocols</strong> for communication. Each protocol solves a <strong class="css-13l2ows evim1t910">specific problem.</strong> Each protocol layer <strong class="css-13l2ows evim1t910">builds on guarantees</strong> offered by previous layers.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Take the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">TCP/IP stack</strong>, for example. This stack is used by Internet applications, such as websites or video games:</p>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/extension-network-stack/images/image-4.png" alt="TCP/IP stack diagram" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At the bottom, we have the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">link layer</strong>, connecting physical devices.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Next, the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Internet layer</strong> builds on top of the link layer, allowing routing and forwarding across devices, so messages can be sent between devices that aren’t physically connected.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The internet layer makes use of a <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">routing table.</strong> This table is used to determine where packets should be sent, based on their IP address. Since each machine isn’t directly connected to every other machine on the internet, a per-machine routing table keeps track of which addresses should be used for packet forwarding.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This routing table can be populated by a few sources. At the highest level, routing can be determined by a protocol called <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">BGP (Border Gateway Protocol)</strong>, the communication protocol between Internet Service Providers (ISPs), such as Xfinity and Verizon. From there, your ISP can populate the routing table for your router, which can populate the routing table for your individual machine.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Above the internet layer sits the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">transport layer</strong>, which can be as simple as UDP (a simple wrapper and checksum of an IP packet), but in the Internet’s case is typically TCP, which provides more reliability. TCP allows streaming, retries, and prevents double-delivery.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Finally, the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">application layer</strong> gives a well-featured layer for developers to build applications on. This layer gives us cookies, headers, encryption, status codes, and user-readable domain names. It’s much easier to build software on this layer than to attempt to use TCP directly.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">These are the same abstractions we used for our extension’s messaging system.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="jams-extension-network-stack" class="css-1oc01jt evim1t94">Jam’s <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">extension</strong> network stack</h2>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/extension-network-stack/images/image-5.png" alt="Our extension&#x27;s network stack diagram" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At the bottom of our extension component network stack, we have our <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">link layer</strong>, which handles communication between directly-connected components.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Above that, our <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">packet layer</strong> handles routing, forwarding, and dropping packets, much like the <strong class="css-13l2ows evim1t910">internet layer</strong> from the TCP/IP stack.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The packet layer makes use of a <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">routing table</strong>, which is used for routing packets to the correct extension component. Since our extension components will always have the same configuration (host script is connected to content script, content script is connected to background, etc.,), we can use a static routing table, no BGP-like dynamic routing algorithm required.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Above the packet layer, we have the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">datagram layer</strong>. This layer was essential for implementing <strong class="css-13l2ows evim1t910">incognito mode</strong> support on Jam, because it allows large messages to/from incognito tabs to be automatically chunked and sent in pieces. If we need to implement message streaming in the future, we would implement it at this layer.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Finally, we have the <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">application layer</strong>. This layer gives us a comfortable send/receive pattern that automatically creates response listeners and ties a message request back to a message response. (Imagine if HTTP requests didn’t have responses, and you’ll understand what using this stack would feel like without this layer).</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="did-we-solve-our-problems" class="css-1oc01jt evim1t94">Did we <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">solve our problems?</strong></h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Do you remember our earlier messaging difficulties from before? Well, here are their solutions.</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Different underlying messaging APIs?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Abstracted by the <strong class="css-13l2ows evim1t910">link layer</strong></em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Messages have size constraints (on some APIs)?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Chunking at the <strong class="css-13l2ows evim1t910">datagram layer</strong></em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Some components cannot communicate directly?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Packet forwarding at <strong class="css-13l2ows evim1t910">packet layer</strong></em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Multiple Tabs, Popups can exist independently?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Independent addressing at <strong class="css-13l2ows evim1t910">packet layer</strong></em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Messages can be dropped?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Packet retries at <strong class="css-13l2ows evim1t910">datagram layer</strong></em></span></li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Sharing object URLs not allowed to/from an incognito context?</strong> <style data-emotion="css 10zf7g3">.css-10zf7g3{display:inline;}.css-10zf7g3 *{color:#b51900!important;}</style><span class="css-10zf7g3 ef55ps61"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">← Automatically switch to chunking if the sender/receiver is incognito (and message size is too large to fit in a single packet), at the <strong class="css-13l2ows evim1t910">datagram layer</strong></em></span></li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">So, yes! These problems feel solved. And if this system worked for the internet, it will probably scale for any other complicated communication scenarios you may imagine, where we can’t use HTTP (a second extension, a native desktop app, etc.,).</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="outcomes-of-this-project" class="css-1oc01jt evim1t94"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Outcomes</strong> of this project</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This extension component network stack has been in production and stable for around 9 months at time of writing.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here are a few choice benefits that our approach gave us:</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="smooth-rollout" class="css-1887rzz evim1t95">Smooth rollout</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Prior to this network stack we had a simpler setup, with an application layer built on top of native messaging APIs. By <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">keeping our final application layer the same</strong> for this project, we were able to simply cutover to the new network stack, and have Incognito Mode just work.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Not only that, but as this stack was built, the rest of our team was able to continue writing code that introduced new application message types, and used more application message calls. Switching to this new system <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">didn’t impact developer velocity.</strong></p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="simpler-debugging" class="css-1887rzz evim1t95">Simpler debugging</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Separation of concerns</strong> across each layer makes it easier to narrow down where an issue is happening. Tests at every layer (with simulated native message APIs) give us <strong class="css-13l2ows evim1t910">confidence on every layer and the system overall.</strong></p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="focus-on-building-features" class="css-1887rzz evim1t95">Focus on building features</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Developers doing feature-work no longer need to bother with message length constraints, forwarding messages over the content-script-to-host-script-hop. <style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Our network stack abstracts away these problems.</strong> This cuts down the amount of code we need to make a cross-component feature work, and lets our engineers <strong class="css-13l2ows evim1t910">focus on building product features.</strong></p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/extension-network-stack</link><guid isPermaLink="false">extension-network-stack</guid><pubDate>Tue, 30 Jan 2024 00:00:00 GMT</pubDate></item><item><title><![CDATA[Documenting my open-market Job Search]]></title><description><![CDATA[<div><style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Some personal news: I&#x27;ve accepted an offer to join Ramp as a Staff Software Engineer. It seems like a wonderful fit, and I&#x27;m very excited to start at the end of the month.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you&#x27;re a senior engineer who hasn&#x27;t done an open-market search in nearly a decade, this post is for you.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Hesitating to run a broad search often means staying underpaid in a role that&#x27;s no longer the best fit. Here, I share my own search — from prep to offers — along with the exact pipeline I used, tactical tips for each stage, and open-sourced data on today&#x27;s market. The goal is to leave you with a clear map of how hiring works now, and a practical framework you can reuse with confidence.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Table of contents:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="#background">Personal background and goals</a>
<ul>
<li class="css-1650jxb e1mpr5v80">Start here if you&#x27;re interested in the context behind my search.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="#goal-qualifying-success">Determining success criteria</a>
<ul>
<li class="css-1650jxb e1mpr5v80">Read this if you&#x27;re not sure what you want from a role.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="#architecture-the-pipeline">Documentation of the process</a>
<ul>
<li class="css-1650jxb e1mpr5v80">This section contains my interview pipeline, along with strategy and tips for each stage.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="#incident-playbook">Incident playbook (when life blows up mid-search)</a>
<ul>
<li class="css-1650jxb e1mpr5v80">A simple playbook for dealing with unexpected and urgent life events.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80"><a href="#numbers-and-market-commentary">Open-sourced data and market commentary</a>
<ul>
<li class="css-1650jxb e1mpr5v80">A sankey diagram of my search data, plus commentary on recent market trends.</li>
</ul>
</li>
</ul>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="background" class="css-1oc01jt evim1t94">Background</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After roughly four years at <a href="https://jam.dev">Jam.dev</a>, I felt it was time for a change.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Four years ago, I simply wanted to improve my Product and Marketing skills, while continuing to do Engineering work.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Coincidentally Dani and Irtefa—the two best PMs I knew from Cloudflare—had been calling me to join their new startup for a year. Their marketing was strong, their product ability was stronger, and we had a proven trust in each other from our days launching zero-to-one products at Cloudflare. It was a great fit.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">At Jam, I accomplished my initial goals (Product and Marketing), and then some (Eng leadership).</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But over those four years, some things had changed. The pandemic had ended, I had proposed to my then-girlfriend, moved from SF to NYC, bought a condo, and married my now-wife.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">There was a tension between my desires and my reality: my financial risk profile had changed, my desired learnings had changed, and covid lockdowns no longer restricted me from working from an office—but Jam was fundamentally a remote company.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Leaving this mismatch unaddressed was painful, so I decided to make the switch.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="goal-qualifying-success" class="css-1oc01jt evim1t94">Goal: Qualifying Success</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When starting any process, it&#x27;s useful to approach it with a goal in mind. Naturally, in a job search, we want to find the best role and secure an offer.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But what &quot;best&quot; means is hard to define. I believe it&#x27;s not simply the total compensation. So in this stage, I came up with a qualifier to determine which role offers I was most likely to accept.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">My qualifier here was personal and likely different from yours. So while I&#x27;ll share my qualifier (less relevant to you), I&#x27;ll also share the process I used to derive it, which you can use for yourself.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="my-qualifier" class="css-1887rzz evim1t95">My qualifier:</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I decided that my ideal role would have NYC engineering presence, series C or later fundraising stage, good role fit (people, work environment, learnings — more detail below), and competitive comp.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In the unlikely event that I completed the process with two strong offers that I truly couldn&#x27;t decide between, I planned to use a long-tail of minor selection criteria to decide (e.g. commute path, office&#x27;s distance to nearest gym location, etc.).</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="determining-your-qualifier" class="css-1887rzz evim1t95">Determining your qualifier:</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I had a two-part process to decide this qualifier. First, I had already introspected to determine what was pushing me to search for a new role.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Second, I had the fortune to bring in a wonderful external consultant who kindly did some pro-bono work:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/martin-doc.png" alt="caption: Caption: A consultant-turned-designer, Martin briefed me on strategy live in FigJam" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Caption: A consultant-turned-designer, Martin briefed me on strategy live in FigJam</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Before joining Jam, Martin had spent 7 years at BCG, a prominent consulting firm. Martin has a well-structured thinking process, and I was generally curious on his advice, so I reached out to chat with him before taking sabbatical.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">During our call, Martin created 6 cards to represent attributes of a role:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Work location: In-person/hybrid (you could change this to &quot;remote&quot;, if that&#x27;s what you prefer)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">People and work environment</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Learnings</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Compensation</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Career trajectory</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Nature of the work</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The above is the ordering that I selected. You can try reordering these to reflect your own preferences. The hard part is that there can be no ties.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I took the editorial liberty to cut and condense this down into three bullet points:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">NYC engineering presence (hybrid)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">&quot;Fit&quot; (a combination of people, work environment, learnings)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Compensation</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In order to more-effectively screen companies, I added &quot;Series C or later&quot; as a requirement. This was a proxy indicator for both my learning and comp requirements.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We now have our qualifier. This will come in handy for both qualifying leads (apply this qualifier loosely) <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">and</em> selecting an offer (apply this qualifier strictly).</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="architecture-the-pipeline" class="css-1oc01jt evim1t94">Architecture: the Pipeline</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Imagine a minimal interview funnel:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Find a role</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Submit an application</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Interview</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Receive the offer</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Sign the offer</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It works in theory, but has obvious failure points: What if your application is rejected? What if you fail a round? What if the offer is uncompetitive?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The naive solution is to flood the funnel with more applications, and hope a strong offer appears.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But the response rate of direct job applications is not high. If your qualifier is strict, you may have difficulty finding qualified roles. And as a mere human, you do not have infinite time or energy. I believe there is a better solution.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="pipeline-overview" class="css-1887rzz evim1t95">Pipeline Overview</h3>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/pipeline.png" alt="caption: The pipeline" class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">The pipeline</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This is the pipeline I gradually refined over the course of my search.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Its scope is broad:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Prospecting, qualifying, closing, and negotiation — roles traditionally across: BDR/SDR (junior sales), AE (senior sales), and Deal Desk (sales ops), in a standard sales pipeline</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">SEO (a form of marketing)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Due diligence (finance)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Contract review (legal)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">And more...</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">On top of <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">actually interviewing</em>, of course.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That said, every stage within this pipeline either provided a significant benefit, or was outright necessary to secure the comp and role I was targeting.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="prep-stage" class="css-2md8qb evim1t96">Prep Stage</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-prep.png" alt="prep stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The first stage in the pipeline is preparation.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For both inbound and outbound opportunities, three things are essential:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">An intro you can comfortably and confidently rattle off.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A resume that showcases your work.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A LinkedIn profile that makes you look like a good candidate.</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you are rusty with leetcode style problems, this is also the time to sharpen up. I set up a weekly practice call with my younger sister, who also works in tech. Most candidates have trouble clearly communicating while coding, so I&#x27;d highly recommend pairing rather than solo nonverbal problem solving.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Optimizing your narrative</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Do you feel awkward or unrehearsed when asked to introduce yourself? A weak intro can give a bad first impression and start the interview with lower confidence, in turn affecting your performance.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">A strong intro, on the other hand, helps the interviewer contextualize your background and better assess fit.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In general, a good intro can cover the following areas:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Brief technical overview</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Key career choices and the reasoning behind them</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Big wins or standout projects, with relevant business context</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Why you&#x27;re interested in this company</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To come up with this, look at your resume and connect the dots into a coherent story. If you know someone in consulting, they can be helpful. Consultants are trained to structure narratives effectively.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Here&#x27;s what my intro looked like:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Broad overview
<ul>
<li class="css-1650jxb e1mpr5v80">Positioned myself as a &quot;product-leaning full-stack engineer&quot;.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Career moves
<ul>
<li class="css-1650jxb e1mpr5v80">Highlighted my major project at Cloudflare (role + business context), briefly mentioned my 2 intermediate (failed) startups, and explained my transition to Jam — outlining the reasoning behind each move.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Jam context
<ul>
<li class="css-1650jxb e1mpr5v80">Explained Jam&#x27;s core product at a high-level, walked through the multi-year roadmap, and described my role in shaping it.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Major project
<ul>
<li class="css-1650jxb e1mpr5v80">Briefly described and framed the business need behind my most recent large initiative: TLM&#x27;ing our new product, <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">Jam for Customer Support</em>.</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I didn&#x27;t memorize this intro word-for-word. This kept it natural, and let me adjust on-the-fly. Since it was on the longer side, I trimmed details if I sensed an interviewer was impatient or less-likely to be interested.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Updating your resume</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Plenty has been written about resumes. I&#x27;ll add just two points I found useful.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">First, you can bold text to improve readability. My resume is quite dense. To counteract this, I bolded key points to draw the eye.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/resume-example.png" alt="caption: Feel free to judge this technique&#x27;s effectiveness for yourself." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Feel free to judge this technique&#x27;s effectiveness for yourself.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Second, provide context. The weakest part of most resumes is the lack of context.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you worked at a startup: what did the company actually do? If you drove a change within a large org: what was its business impact? When possible, reinforce this with metrics. Answering just these two questions helps readers understand both your experience and its significance.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Assume a critical reader will interpret ambiguity against you. Providing context increases your odds of passing a resume screen.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Optimizing your LinkedIn</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In today&#x27;s world, role listings are overwhelmed with applications. Optimizing your inbound funnel is arguably your highest-impact lever — and like it or not, LinkedIn is the most effective tool.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Consider this anecdote:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">With a referral, I applied to a well-known public ridesharing company 3 times (Staff, Staff, Senior). Rejected. Then again twice more (Senior, Senior), all rejected at resume screen.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Later, that same company&#x27;s recruiter instead reached out to me on LinkedIn about a separate Staff-level role.</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In my search, referrals were not more effective than cold applications, whereas inbound consistently surfaced strong opportunities. My take is that during the ZIRP-era tech bubble, rapid growth and low-signal referrals (amplified by Blind users) diluted applicant quality. From my experience, larger companies in particular no longer view referrals as strong signal.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To optimize your LinkedIn, I recommend two key steps:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Think like a recruiter
<ul>
<li class="css-1650jxb e1mpr5v80">Recruiters use LinkedIn&#x27;s Recruiter tool to search by company, keywords, job titles, and years of experience. In that sense, I treated my profile as an SEO problem.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Think like a human reader
<ul>
<li class="css-1650jxb e1mpr5v80">Next, when a recruiter, HM, or interviewer views your profile, what do they see? Profile photo, header, tagline, description, and role description should be clear, compelling, and human-readable. Avoid simply stuffing with keywords.</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For tangible LinkedIn optimizations, I recommend:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Profile photo — professional, approachable, and intelligent-looking</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Cover photo — visually reinforces your work or industry</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Tagline — brief and role-specific</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">&quot;About&quot; section — balances keywords with clear human-readable content</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Experience descriptions — similar to resume entries, concise and achievement-oriented</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Skills section — crammed with relevant skills (these are essentially keywords that don&#x27;t take up space on your profile)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Featured posts — showcase work you are proud of (ideally with media assets, which increase clickthrough rates)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Activity section — professional, or hidden (no dumb comments on friends&#x27; posts)</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Finally, enable &quot;Open to Work&quot; with settings you&#x27;re comfortable with. I recommend avoiding the green profile picture banner. Fair or not, it signals desperation, which is negative signal for a candidate.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">One caution: after enabling &quot;Open to Work&quot;, I noticed a sharp rise in spam calls. To minimize this, remove your phone number from LinkedIn, or disable the setting that allows user lookup by phone number.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="inbound-stage" class="css-2md8qb evim1t96">Inbound Stage</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-inbound.png" alt="inbound stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">With your prep complete, you are ready for inbound.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When a recruiter reaches out, their first goal is simply to confirm fit. In most cases, this means scheduling an initial call to cover your background and collect your resume, which will then be screened again by the hiring manager.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you&#x27;re working with a third-party recruiter (rather than an internal one), expect a few key differences:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">They&#x27;ll try to match you with multiple companies.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">After their initial screen, they&#x27;ll hand you off to an internal recruiter so the company can integrate you into its pipeline.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Most third-party recruiters function mainly as sourcers — they generally can&#x27;t answer detailed questions about the company, compensation, or process. <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">(An exception in my own experience was Lewis Fegan, who supported my Ramp process and was excellent.)</em></li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Two things to keep in mind before talking with any recruiter:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Screen inbound carefully
<ul>
<li class="css-1650jxb e1mpr5v80">The biggest mistake is wasting time on low-quality inbound that won&#x27;t convert. Just as BDRs and SDRs qualify leads before handing them to AEs, you should qualify recruiter outreach before investing time. If you&#x27;re unsure how, don&#x27;t worry — after a couple dozen calls, you&#x27;ll develop an instinct for which messages lead to quality opportunities and which do not.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Present yourself well on the call
<ul>
<li class="css-1650jxb e1mpr5v80">When you do take a call, speak comfortably and confidently. Share your background without going too deep in the weeds — they&#x27;ll ask if they want more detail. Be prepared to answer common questions like <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">&quot;What are you looking for?&quot;</em> and <em class="css-5hfsd2 e1mpr5v81">&quot;Why are you leaving your current role?&quot;</em> (I cover my answers to these in the section on qualifiers above).</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Practical tip: Save the recruiter&#x27;s number as a contact. This helps distinguish scheduled calls from spam, and reminds you of their name and company when you pick up — especially useful when calls are back-to-back.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="sourcing-stage" class="css-2md8qb evim1t96">Sourcing Stage</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-sourcing.png" alt="sourcing stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The purpose of sourcing is to gather intellilgence needed to enable outbound.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Outbound is the act of reaching out: crafting the pitch and sending the email. Sourcing, by contrast, is the preparation: identifying the right person to contact and the right context to frame the outreach.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">There are three main types of sourcing, best tackled in this order:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Role listings</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Relevant cold contacts</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Relevant 1st-degree connections</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Sourcing Role Listings</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In my experience, sourcing role listings is still a surprisingly manual process.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">A couple reasons stand out:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">No single aggregator for all roles (LinkedIn does well, but doesn&#x27;t have everything)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Poor search filters and discovery (even LinkedIn struggles with filtering its own content)</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Despite this, it&#x27;s worth the effort. Sourcing roles feeds directly into the next two sourcing steps: cold contacts and first-degree connections. Without a qualified role, you don&#x27;t have a reason to run outbound in the first place.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Today, LinkedIn Jobs is probably the best broad aggregator. Beyond that, think of specific companies and check their careers pages directly. You can also borrow sourcing tools from other domains — for example, Crunchbase (venture) or Apollo (sales) — to expand your search. I&#x27;ll cover more on that in the cold-contact sourcing section below.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">As part of role sourcing, the next step is to apply your qualifier to decide whether a role is worth pursuing. This doesn&#x27;t require the full rigor of your final criteria. A lighter version is enough (e.g., assume more comp flexibility, or allow for a weaker NYC engineering presence). Casting a slightly wider net both increases options and provides better market signal.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">As you begin identifying relevant roles, it&#x27;s also useful to start tracking them systematically. I cover this in more detail in the &quot;Monitoring System&quot; section.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Sourcing Relevant 1st-degree connections</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">With a list of roles in hand, the next step is to see if you know someone to reach out to. On LinkedIn, this is straightforward: search the company and see if anyone in your network works there.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Sourcing Relevant Cold Contacts</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">But first, why do we even bother with cold contacts?</p>
<blockquote>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To explain why sourcing cold contacts matters, we also have to acknowledge its counterpart: cold outbound. Unfortunately, the idea of sending cold outbound makes many engineers recoil.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The good news is, you don&#x27;t need to do much. In my entire search, I sent just two cold emails.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">One email went poorly. Everything from targeting (director without an open Staff role), to addressing (mail bounceback on first attempt), to the actual contents (uncompelling copy) were bad. Predictably, it received no response. It was a low-effort cold email, and it was a waste of time.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The other email got me into the pipeline for one of my top choice companies (one of the two leading AI startups), and matched me with the exact team I was interested in. How? I cold emailed the HM with compelling pitch for a role he was hiring for. It was a high-effort, well-targeted email, and it was very effective.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">So, cold outbound can be very effective. But it also needs to be high-quality.</em></p>
</blockquote>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The most important part of sourcing is finding the right person. Who&#x27;s more likely to respond to a cold email: a random engineer, or the hiring manager actively looking to fill the exact role you want?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Additonally, why are you emailing <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">them</em>? Why is their team interesting? Why did their company catch your eye? Targeted cold outbound comes off as genuine interest, while untargeted cold outbound comes off as spam.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">On tools: aside from LinkedIn, I recommend <a href="https://www.apollo.io/">Apollo</a> over <a href="https://crunchbase.com/">Crunchbase</a>. Though built for sales, Apollo is excellent for sourcing both companies and contacts, and even role listings. A few killer features:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Office-level filtering: Crunchbase limits you to headquarters, but Apollo lets you filter by <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">any</em> office location. This is invaluable when targeting NYC offices for SF-headquartered companies.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Role-level filtering: Apollo can filter for companies with open roles by title and location. In fact, I found LinkedIn postings through Apollo that LinkedIn itself failed to surface in search.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Contact discovery: Apollo also surfaces company contacts and associated work emails.</li>
</ul>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="outbound-stage" class="css-2md8qb evim1t96">Outbound Stage</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-outbound.png" alt="outbound stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">With roles and contacts in hand, it&#x27;s time to run outbound.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Direct application</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The simplest form of outbound is filling out an application form and hitting submit. Because the barrier to entry is so low, these channels are flooded, so success rates are generally low.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That said, here&#x27;s one useful LinkedIn-specific tip: even without Premium, LinkedIn shows how closely your profile matches a role. While recruiters may not see this score, it&#x27;s a reasonable proxy for how your profile ranks in their searches. Conveniently, the match score updates when you add skills. This means that every job listing can be treated as training data to fine-tune your profile and increase inbound.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11">
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/sales-before.png" alt="sales-before" class="css-1k43lf1 ef55ps60"/>
</div></div>
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11">
<img src="/images/post/open-market-job-search/images/sales-after.png" alt="sales-after" class="css-1k43lf1 ef55ps60"/>
</div></div>
</div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Before and after: adding a &quot;prospecting&quot; skill to your profile, and checking the role fit score.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Cold outbound</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Cold outbound is extensively covered in the sales world, and there are resources written by people far more knowledgeable than myself. My simple advice is this:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Provide context: why are you reaching out to them?</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Provide background: why you?</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Make a clear ask: define the next step, and keep it low-effort.</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Then... send the email. Don&#x27;t overthink it, and keep expectations low — after all, how many cold emails do <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">you</em> reply to?</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Warm outbound</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Warm outbound should feel like asking a friend for a small favor. Pop in, say hello, request a referral, and keep them updated as you move forward. Keep it light: not transactional, but not an essay either. They&#x27;re likely busy, and this is still a work-related request.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The primary goal of warm outbound is usually a referral. In my case, though, referral success rates were about the same as cold applications (see the Sankey diagram below).</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">That said, reach out anyway. And once you&#x27;re later in the process, call them, catch up, and ask for their perspective. It&#x27;s always useful to get insider context on the team and company. I cover this further in the &quot;backchannel diligence&quot; section.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="company-interview-subpipeline" class="css-2md8qb evim1t96">Company Interview Subpipeline</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-company-interview.png" alt="company interview stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Each company runs its own interview process, which I&#x27;ll call the company interview subpipeline: this spans everything from the initial recruiter screen to team matching.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Naturally, this means the diagram above will vary in practice. A few examples I encountered:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Async coding screens before live coding screens (ranging from leetcode-style automated assessments to manually-reviewed CTF submissions)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Hiring manager calls before technical screens</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">System Design interviews as the first technical round, before the onsite</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Informal team matching prior to onsite (not uncommon, often with the hiring manager conducting the onsite leadership round)</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">With that variance noted, let&#x27;s now walk through the standard interview pipeline.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Internal Recruiter Screen</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The internal recruiter is your first real company contact. They begin the process with a screening call.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Recruiters aren&#x27;t exactly your friends, but you should be friendly with them. They prep you on what to expect, are your point of contact for urgent updates or scheduling changes, and serve as your first-line advocate in negotiation.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">An internal recruiter screen is similar to a third-party recruiter call (covered earlier), but here you can ask substantive questions about the company, process, or team.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Use this call to gather details that matter to you. For example, if you&#x27;re screening companies based on equity liquidity, you&#x27;ll want clarity on structure:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Public stock (e.g. Google, Meta, Uber)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Standard 7-year RSUs (e.g. Ramp)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">ISOs with a long post-termination exercise window (e.g. <a href="https://hightouch.com">Hightouch</a>)</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Recruiters often confuse PTEW with vesting schedules, so you may need to push for specifics. In my case, I discounted equity value by 50% for companies offering ISOs with &lt;7-year PTEW.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Sometimes this call is run by a junior recruiter or coordinator, who may later hand you off to a senior recruiter. Junior recruiters often can&#x27;t answer detailed questions, so save those for the next stage.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Recruiters may also ask for your salary range, or share theirs and ask for feedback. At this stage, I answered honestly and said I was prioritizing fit over comp, and would look at numbers later. This helped keep my options open and gave me more market data. You can always decline to proceed later. To pre-screen roles with obviously below-market comp, check salary ranges on job postings or use sources such as <a href="https://levels.fyi">levels.fyi</a>.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">You may get rejected after this stage for two common reasons:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Salary expectations too high (if you&#x27;ve stated them)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">&quot;Not a good fit&quot;: typically after call, recruiter passes resume to EM, who decides to pass. (Especially if headcount is limited)</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Core interviews</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">One tip for everything after the recruiter screen: do light background research on your interviewers.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Before each call, I&#x27;d skim my interviewer&#x27;s LinkedIn profile. This gave me a sense of their focus areas, but the main benefit was in shaping my post-interview questions. I found it valuable to hear their personal anecdotes — especially around role transitions — as it helped me understand their perspective and how they viewed their own role.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Tech Screen</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The tech screen is usually a straightforward coding round, typically one or two medium-level leetcode style questions. That said, my tech screens and coding rounds often leaned towards practical problems.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I recommend the following flow:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Clarify the problem
<ul>
<li class="css-1650jxb e1mpr5v80">Ask questions, get details on the problem, confirm your understanding.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Walk through examples
<ul>
<li class="css-1650jxb e1mpr5v80">Test understanding of normal cases, and confirm expected behavior for edge cases.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Talk through your solution verbally
<ul>
<li class="css-1650jxb e1mpr5v80">I recommend commenting this out as you walk through, so you can implement code from your comments.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Implement the solution
<ul>
<li class="css-1650jxb e1mpr5v80">After confirming your interviewer understands and agrees, you can code out the solution.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Validate the test cases to confirm correct behavior
<ul>
<li class="css-1650jxb e1mpr5v80">You can either do this manually, or by writing tests. Check with your interviewer on what they prefer. On top of any pre-supplied test cases, add your own test cases here to ensure confidence.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Refine and optimize
<ul>
<li class="css-1650jxb e1mpr5v80">Often, there are still optimizations left (code quality, runtime performance, memory, etc,). You can ask your interviewer what they&#x27;d prefer you to dig into.</li>
<li class="css-1650jxb e1mpr5v80">Alternatively, you may have new follow-up requirement to implement, for which you can repeat the above steps until completion.</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Anecdotally, I found tech screens and coding rounds to be the most relaxed interviews. The structure is clear, and once the solution and optimizations are complete, the remaining is free for you to chat and ask questions.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Onsite</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In most processes, once you pass the tech screen you move to the onsite. Scheduling the onsite, however, involves strategy of its own.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Negotiation depends on having <a href="https://en.wikipedia.org/wiki/Best_alternative_to_a_negotiated_agreement">viable alternatives</a> — that&#x27;s what gives you leverage. Onsite scheduling affects this in two ways:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Offers expire — you can&#x27;t hold them open indefinitely.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Leverage peaks right after an offer — the best time to negotiate is immediately upon receiving one.</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">We&#x27;ll cover negotiation in more detail later. For now, let&#x27;s talk about scheduling.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Onsite scheduling</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When scheduling onsites, I considered two approaches:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Clustered onsites
<ul>
<li class="css-1650jxb e1mpr5v80">All onsites are grouped within a 1–2 week window.</li>
<li class="css-1650jxb e1mpr5v80">The main advantage is efficiency: you can take a single PTO block and complete multiple onsites without disrupting your day job.</li>
<li class="css-1650jxb e1mpr5v80">The tradeoff is that you only get one &quot;snapshot&quot; of the market, with limited room to adjust if better opportunities appear later.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Rolling onsites
<ul>
<li class="css-1650jxb e1mpr5v80">The pipeline never stops: sourcing, inbound responses, and tech screens continue while you move through onsite rounds.</li>
<li class="css-1650jxb e1mpr5v80">Early onsites are clustered, but additional onsites are scheduled as opportunities arise. This keeps multiple offers in play, collects more data, and retains ongoing leverage for negotiation.</li>
<li class="css-1650jxb e1mpr5v80">Lower-priority roles are often scheduled first, giving you time to practice before interviewing with your top choices.</li>
<li class="css-1650jxb e1mpr5v80">Conceptually, this is similar to the <a href="https://en.wikipedia.org/wiki/Secretary_problem">secretary problem</a>: you keep sampling until you&#x27;re confident you&#x27;ve seen enough of the market. This strategy is especially useful if you&#x27;re unfamiliar with current conditions.</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I chose rolling onsites, the safer but more-demanding option.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Unfortunately, a series of life events cut into my timeline (more on that later). To stay on track with my three-month timeline, I condensed the schedule: some days included two onsites, or an onsite plus recruiter and tech screen calls. My instant coffee consumption probably went up tenfold for a month or so. Still, no regrets: the results were worth the sleep debt.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Coding Round</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The coding round is usually the first onsite round. For whatever reason, it often gets scheduled earlier in the day.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">It&#x27;s similar to the tech screen, with one key difference: you may have a shadow interviewer. This slightly changes the dynamic during post-interview questions.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For deeper conversations, direct your questions to a specific interviewer based on their background. But you can also ask quick, open-ended questions that invite both to respond. For example: <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">&quot;In terms of resourcing, would you say your current team is bottlenecked on engineering, product, design, or something else?&quot;</em></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">System Design Round</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">System Design interviews vary widely. In my search, I encountered differences in:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">High-level format
<ul>
<li class="css-1650jxb e1mpr5v80">live system design vs project retrospective deep-dives</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Low-level format
<ul>
<li class="css-1650jxb e1mpr5v80">whiteboard vs written document</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Area of focus
<ul>
<li class="css-1650jxb e1mpr5v80">fullstack product engineering vs backend infrastructure</li>
</ul>
</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Because of this variation, System Design is one of the harder rounds to prepare for. I recommend the following:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Speak calmly and confidently, this has a strong impact in qualitative rounds.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Explain tradeoffs when selecing an option.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">For product-leaning interviews (e.g. Meta Product Eng), start by defining the product domain, outlining business requirements, and clarifying constraints and upstream APIs. These often have flexibility, which lets you simplify your design.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Surface risk explicitly. When adding a component that introduces risk, point it out and explain mitigation.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Review your past projects. Know not just the architecture but also the business drivers, timeline, and impact.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Refresh scaling fundamentals, e.g. Kafka and similar tools: review internals, failure modes, and usage patterns.</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For structured practice, I recommend <a href="https://www.hellointerview.com/">hellointerview</a> — both for their interactive practice problems and their YouTube walkthroughs.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Leadership or Collaboration Round</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">This round is meant to judge your leadership and collaboration skills. It is typically conducted by your HM or an equivalent engineering leader.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The <a href="https://en.wikipedia.org/wiki/Situation,_task,_action,_result">STAR</a> format (Situation, Task, Action, Result) is a common recommendation for answering questions. Think of it as a guideline rather than a strict rule. What matters most is providing clear situational context and walking through your structured thought process. The goal is to leave the interviewer confident you&#x27;d be a capable teammate or leader, can influence without authority, and make pragmatic, well-evaluated decisions.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Anecdotally, I&#x27;ve found it useful to talk with people from finance or operations backgrounds: they often think in more process-oriented ways than early-stage engineers, which can help you verbalize your own processes.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">For Staff-level interviews, it also helps to have well-formed views on leadership and management philosophy. Personally, I&#x27;ve always enjoyed organizational theory and human dynamics, so these were fun interviews for me.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Team Matching Call</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Team matching is usually the final step before an offer. By this point, you&#x27;ve already cleared the interviews. The purpose here is for both you and the hiring manager to confirm mutual fit.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Treat this call as your opportunity to interview the HM. Come prepared with questions on topics like team and org structure, role expectations, past challenges, and the roadmap ahead. This is your chance to understand what it would actually be like to join the team.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To make the most of it:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Prepare questions in advance.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Keep a notes doc open to capture details.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Approach the call with neutral expectations.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Do deep background research on your HM. (For example, before my Ramp team-matching call, I looked into my HM&#x27;s previous startup, their past role transitions, and carefully read several posts on their personal blog.)</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Verbal offer number call</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The verbal offer call is unique: it&#x27;s part of the company&#x27;s interview subpipeline, but it also marks the start of your diligence and negotiation stages.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">From the company&#x27;s perspective, the call is a quick touchpoint to check your flexibility on numbers, build excitement, lightly sell you, and answer surface-level questions.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">From your perspective, two things matter:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Negotiation
<ul>
<li class="css-1650jxb e1mpr5v80">The numbers presented act as an anchor. Your response signals how much flexibility you have.</li>
<li class="css-1650jxb e1mpr5v80">My approach: take the numbers, write them down, and thank the recruiter. If pressed on an opinion, I&#x27;d say I was waiting on additional data points for comparison, which was true.</li>
<li class="css-1650jxb e1mpr5v80">The energy you show in your response should be balanced:
<ul>
<li class="css-1650jxb e1mpr5v80">Show too little enthusiasm, and they may see you as a lost deal—not worth fighting comp committee for.</li>
<li class="css-1650jxb e1mpr5v80">Show too much, and it signals emotional overinvestment and lack of options, weakening your leverage at the negotiation table.</li>
<li class="css-1650jxb e1mpr5v80">The reason you state for your excitement is a key lens into your decision-making framework. Give excitement grounded in reason, rather than under-explained emotion, if you want to signal seniority and build trust.</li>
</ul>
</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Direct diligence
<ul>
<li class="css-1650jxb e1mpr5v80">The recruiter is a resource. Use this call to gather information that matters to you.</li>
<li class="css-1650jxb e1mpr5v80">My focus was on equity, since most offers I received were late-stage private equity. I recommend asking for, at minimum:
<ul>
<li class="css-1650jxb e1mpr5v80">Past 5 years of ARR data</li>
<li class="css-1650jxb e1mpr5v80">Equity details (RSU vs. ISO, vesting schedule, PTEW duration)</li>
<li class="css-1650jxb e1mpr5v80">Anecdotally, companies with strong financials share them readily. Companies with weaker numbers often hedge and pivot to &quot;future growth story&quot; narratives instead.</li>
</ul>
</li>
<li class="css-1650jxb e1mpr5v80">This is a good time to mention scheduling calls with the rest of the team, part of your direct diligence covered below.</li>
</ul>
</li>
</ol>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="direct-diligence" class="css-2md8qb evim1t96">Direct Diligence</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-direct-diligence.png" alt="direct diligence stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">After compensation discussions, my next step was meeting the team I&#x27;d be working with. Since this stage takes about as much time as an onsite, I prioritized it only for offers I was most likely to accept.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Who to meet (in order of priority, especially the first two):</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Engineering leadership (CTO, Head of Eng, or VP)
<ul>
<li class="css-1650jxb e1mpr5v80">Purpose: understand how engineering is run as an org, and get a read on your leadership chain.</li>
<li class="css-1650jxb e1mpr5v80">If you don&#x27;t respect your leadership chain, you&#x27;ll have a bad time. This call lets you gauge whether leadership feels out of touch, or conversely too in-the-weeds.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Product counterpart
<ul>
<li class="css-1650jxb e1mpr5v80">Purpose: get the most realistic view of how the business is run day to day, at the ground level.</li>
<li class="css-1650jxb e1mpr5v80">As a Senior or Staff product engineer, your PM is often your closest collaborator, so their perspective is critical.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Engineering peer
<ul>
<li class="css-1650jxb e1mpr5v80">Purpose: understand what the role feels like from the inside.</li>
<li class="css-1650jxb e1mpr5v80">Ask about what they enjoy, what challenges they face, and what you should watch out for.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Engineering junior
<ul>
<li class="css-1650jxb e1mpr5v80">Purpose: get an unfiltered sense of how the org treats new talent.</li>
<li class="css-1650jxb e1mpr5v80">If juniors are under-resourced or poorly treated, that&#x27;s a red flag — the canary in the coal mine.</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Since scheduling these conversations isn&#x27;t automatic, you&#x27;ll likely need to ask your recruiter or set expectations during the verbal offer call. Don&#x27;t skip this step — it&#x27;s the data you need to make a confident decision.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="backchannel-diligence" class="css-2md8qb evim1t96">Backchannel Diligence</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-backchannel.png" alt="backchannel diligence stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">To build confidence in a company&#x27;s valuation, I recommend speaking with two final personas:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">An investor
<ul>
<li class="css-1650jxb e1mpr5v80">Ideally a friend in VC (or, if not, other late-stage founders).</li>
<li class="css-1650jxb e1mpr5v80">The goal isn&#x27;t a detailed model — just an honest, high-level perspective on the company&#x27;s financial trajectory.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">A customer
<ul>
<li class="css-1650jxb e1mpr5v80">Customers reveal where a company may be cutting corners.</li>
<li class="css-1650jxb e1mpr5v80">Downstream complaints often signal upstream issues.</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In Ramp&#x27;s case, I spoke with both VC friends and a former skip manager who had worked with them as an enterprise customer. The feedback was strong: some literally said <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">&quot;I love Ramp&quot;</em>, while others said Ramp was great but also pitched one of their portfolio startups (also a good sign).</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Taken together, these conversations were a useful gut-check to confirm I wasn&#x27;t missing any red flags from either the customer or investor perspective.</p>
</div><div><style data-emotion="css 2md8qb">.css-2md8qb{color:#111111;font-size:20px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-2md8qb{font-size:18px;}}</style><h4 id="negotiation" class="css-2md8qb evim1t96">Negotiation</h4>
<style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/stage-negotiation.png" alt="negotiation stage" class="css-1k43lf1 ef55ps60"/>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Negotiate comp</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Once you&#x27;re confident in the company and role, it&#x27;s time to lock down your numbers.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Candidates love the idea of a bidding war between companies. HMs and recruiters dread it. In my case, I had other strong offers, but with Ramp I wanted to maintain excitement on both sides — it felt like a great fit, and their offer was already competitive.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">My strategy was to define the numbers I&#x27;d be comfortable signing even without every offer in hand, and present those as my <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">&quot;yes numbers&quot;</em>. I added the caveat that I was awaiting another hiring committee decision for a top-choice role the following week, so my stance might change by Monday. Ramp moved quickly: same-day approval came through within hours.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98"><style data-emotion="css 13l2ows">.css-13l2ows{color:#111111;font-family:Lora,Quattro;}</style><strong class="css-13l2ows evim1t910">Negotiate contract</strong></p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Once you have the contract, read it carefully.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Even at this stage, you still have negotiation leverage: the hiring manager and recruiter want to close the process as much as you do. That said, any new ask typically involves legal, which adds friction and can slow things down.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">In my case, my contract came in on Friday. Everyone wanted to close before the weekend. I quickly reviewed it and decided to use my leverage on a single ask. However, in my rush to close (and with ChatGPT&#x27;s half-baked contract advice), I asked for an equity clause I didn&#x27;t actually need... The contract already had better terms. Because I framed it as my &quot;will sign&quot; ask, I lost some opportunity to negotiate further. That said, the fairness of the equity clause and smoothness of the email thread with Legal gave me more confidence in the company.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">And with that, I signed! Officially a &quot;Rampling&quot;.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="monitoring-and-incident-management" class="css-1oc01jt evim1t94">Monitoring and Incident Management</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Visibility into your process is essential. Many applicants rely only on their email inbox, but a smart candidate builds a dashboard.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Your dashboard should answer key questions such as:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Which companies am I actively interviewing with right now?</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Where is each company in the process?</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">When was the last time I heard from them?</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">What are my top 5 active companies, ranked by expected total comp or base pay?</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Which companies do I plan to get referrals for?</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">A simple spreadsheet works well. Recommended columns:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Company name</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Expected level</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Process stage (see picture below)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Date of latest update (last email, application, or interview)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Compensation numbers
<ul>
<li class="css-1650jxb e1mpr5v80">Early: expected TC and base</li>
<li class="css-1650jxb e1mpr5v80">Later: final TC and base for comparison</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">NYC office (or whatever your key location criterion is)</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Outbound method: referral, direct apply, cold outbound — as well as contact name, if applicable.</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Notes</li>
</ul>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Each time you source a company or receive inbound, add a row. Update it whenever the status changes, e.g. a new interview scheduled or an email from a recruiter.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I started with a simple Google Sheet, one company per row. It allowed for fast entry, easy sorting, and a quick at-a-glance view of my pipeline.</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11">
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/gsheets-state-dropdown.png" alt="caption: Numeric prefixes: Adding a numeric prefix to the process stage column enables ordered sorting." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Numeric prefixes: Adding a numeric prefix to the process stage column enables ordered sorting.</span></div></span></div>
<div class="css-1twrc1d egjctx10"><div class="css-rfznso egjctx11"><img src="/images/post/open-market-job-search/images/gsheets-date-formatting.png" alt="caption: Conditional formatting: Applying formatting to the &quot;date of latest update&quot; column gives you instant visibility into which processes are moving and which ones may need a follow-up." class="css-1k43lf1 ef55ps60"/></div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">Conditional formatting: Applying formatting to the &quot;date of latest update&quot; column gives you instant visibility into which processes are moving and which ones may need a follow-up.</span></div></span></div>
</div><span class="css-u4grrt egjctx12"><div><span class="css-oxjc1v evim1t99">A couple useful spreadsheet tricks.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Later in my process, I switched to Notion. It was slower to update, but had one killer feature: a proper notes document could be embedded directly in each row. The ease of organized note-taking justified the switch: for every recruiter call, interview Q&amp;A, or HM conversation, I could quickly open the linked doc to take notes or reference pre-written questions.</p>
</div><div><style data-emotion="css 1887rzz">.css-1887rzz{color:#111111;font-size:24px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1887rzz{font-size:20px;}}</style><h3 id="incident-playbook" class="css-1887rzz evim1t95">Incident playbook</h3>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">During my three-month search, I faced both planned disruptions (a months-long home renovation) and unplanned crises (medical issues, bathroom leak into a neighbor apartment, and a major family emergency abroad).</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The small silver lining was that none of these incidents caused me to lose offers. By proactively communicating updates and setting expectations, I retained trust, and recruiters remained flexible and friendly, even when quickly pivoting.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">When communicating a process change, I recommend the following:</p>
<ol>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Give context
<ul>
<li class="css-1650jxb e1mpr5v80">Explain why a process is being paused, without oversharing.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Give expected timeline for resolution
<ul>
<li class="css-1650jxb e1mpr5v80">Even a placeholder like &quot;I&#x27;ll update by EOD tomorrow, nothing resolved yet&quot; maintains trust.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Set expectations around responsiveness
<ul>
<li class="css-1650jxb e1mpr5v80">If replies will be delayed (e.g., different timezone, other priorities), state it upfront.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Track status
<ul>
<li class="css-1650jxb e1mpr5v80">Mark paused items on your dashboard so you can unpause quickly once things stabilize.</li>
</ul>
</li>
</ol>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">I applied this approach across both professional and personal stakeholders to keep everyone aligned. For example, when I flew unexpectedly to Vietnam, I paused more than seven active company processes and notified all parties. On return to JFK, I immediately restarted: scheduling three onsites and several calls in the first week. For slow processes, I was able to apply timeline leverage using existing offers and an ongoing team-matching process with a major social media company.</p>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="numbers-and-market-commentary" class="css-1oc01jt evim1t94">Numbers and Market commentary</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Below is a Sankey diagram summarizing the stats across stages of my search:</p>
<style data-emotion="css 1twrc1d">.css-1twrc1d{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding:12px;max-width:100%;min-width:200px;-webkit-flex:1;-ms-flex:1;flex:1;margin-top:1em;margin-bottom:1em;background-color:rgb(255, 247, 232);border:1px solid #111111;}</style><div class="css-1twrc1d egjctx10"><style data-emotion="css rfznso">.css-rfznso{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:8px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;-webkit-justify-content:space-evenly;justify-content:space-evenly;-webkit-box-flex-wrap:wrap;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-align-items:baseline;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline;width:100%;}.css-rfznso img,.css-rfznso video{max-width:100%;max-height:600px;}</style><div class="css-rfznso egjctx11"><style data-emotion="css 1k43lf1">.css-1k43lf1{max-width:100%;margin-top:1em;margin-bottom:1em;}</style><img src="/images/post/open-market-job-search/images/sankey-data.png" alt="caption: Note: for simplicity, nonstandard stages have been normalized.&lt;br/&gt;&lt;br/&gt;Second note: the &quot;Paused&quot; stage corresponds to stages left in a paused state until offer signing, all other processes were unpaused." class="css-1k43lf1 ef55ps60"/></div><style data-emotion="css u4grrt">.css-u4grrt{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;undefined font-size:14px;border-top:1px solid black;text-align:center;font-style:italic;margin-bottom:0;}.css-u4grrt *{font-size:14px!important;}</style><span class="css-u4grrt egjctx12"><div><style data-emotion="css oxjc1v">.css-oxjc1v{display:block;margin-block-start:1em;margin-block-end:1em;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;color:#111111;font-family:Lora,Quattro,Charter;font-size:32px;}</style><span class="css-oxjc1v evim1t99">Note: for simplicity, nonstandard stages have been normalized.<br/><br/>Second note: the &quot;Paused&quot; stage corresponds to stages left in a paused state until offer signing, all other processes were unpaused.</span></div></span></div>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Some market commentary based on my experience:</p>
<ul>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Large orgs are slowing hiring, while smaller orgs remain more nimble.
<ul>
<li class="css-1650jxb e1mpr5v80">Public companies seem more exposed to recent macroeconomic shifts than startups.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Hiring is consolidating around core offices and proven models.
<ul>
<li class="css-1650jxb e1mpr5v80">Just as investors retreat from risk, orgs appear to pull back to their strongest locations (often in-person, HQ offices).</li>
<li class="css-1650jxb e1mpr5v80">Anecdotally, one of my largest orgs stopped ingesting new NYC-based candidates — fortunately after I had entered the pipeline.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Physical onsites have mostly disappeared, except where relocation isn&#x27;t required.
<ul>
<li class="css-1650jxb e1mpr5v80">Across dozens of processes, only one strongly pushed for in-person onsite, and only a handful even offered it as an option.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Base salary and equity strength tend to correlate.
<ul>
<li class="css-1650jxb e1mpr5v80">Successful startups tend to outperform on both cash and equity, likely because less funding pressure frees budget for hiring.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">Companies that <style data-emotion="css 5hfsd2">.css-5hfsd2{color:#111111;font-family:Lora,Quattro,Charter;}</style><em class="css-5hfsd2 e1mpr5v81">are</em> hiring may be struggling to fill roles.
<ul>
<li class="css-1650jxb e1mpr5v80">Many roles had 3+ separate independent recruiters reach out over the span of my search, a handful had 5+. This suggests difficulty closing candidates.</li>
</ul>
</li>
<style data-emotion="css 1650jxb">.css-1650jxb{margin-top:8px;margin-bottom:8px;color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><li class="css-1650jxb e1mpr5v80">AI is slowly entering more processes, but is not very common.
<ul>
<li class="css-1650jxb e1mpr5v80">Only a couple companies allowed or encouraged AI as part of their process.</li>
<li class="css-1650jxb e1mpr5v80">Ironically, none of the foundational AI companies permitted AI in their own processes.</li>
</ul>
</li>
</ul>
</div><div><style data-emotion="css 1oc01jt">.css-1oc01jt{color:#111111;font-size:32px;font-weight:500;font-family:Lora,Quattro;position:-webkit-sticky;position:sticky;top:0;padding-top:8px;background:#FDFDFD;box-shadow:0px 4px 4px #FDFDFD;padding-bottom:2px;margin-bottom:-2px!important;z-index:1;}@media screen and (max-width: 500px){.css-1oc01jt{font-size:24px;}}</style><h2 id="afterword" class="css-1oc01jt evim1t94">Afterword</h2>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">The best advice I received was simple: protect your mental clarity. Find an activity that restores your energy and make it routine. For me, it was long walks in the park, often while calling a friend or mentor. Martin used mountain biking to the same effect. Anything that combines light cardio with a flow state seems to work well.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">Don&#x27;t forget your support system. I leaned heavily on my wife, friends, mentors, and former colleagues for advice and sanity. Though the outcome was positive, there were plenty of ups and downs from both life and the process itself.</p>
<style data-emotion="css wurtue">.css-wurtue{color:#111111;font-family:Lora,Quattro,Charter;font-size:18px;}</style><p class="css-wurtue evim1t98">If you enjoyed this post, consider sending it to a friend.</p></div>]]></description><link>https://blog.cyrusroshan.com/post//post/open-market-job-search</link><guid isPermaLink="false">open-market-job-search</guid><pubDate>Wed, 24 Sep 2025 00:00:00 GMT</pubDate></item></channel></rss>