<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Hacker News Personal Blogs 2020 | All Blog Posts</title><link>https://hn-blogs.kronis.dev/feed.xml</link><description>A collection of blog posts from users of Hacker News, based on RSS feeds.</description><language>en-US</language><lastBuildDate>Fri, 10 Jul 2026 04:03:21 GMT</lastBuildDate><generator>rfeed v1.1.1</generator><docs>https://github.com/svpino/rfeed/blob/master/README.md</docs><item><title>My favourite books of 2020</title><link>https://gaganpreet.in/posts/books-of-2020/</link><description>&lt;p&gt;Working and living from home gave me a lot of free time that I could dedicate to reading. I read &lt;a href="https://www.goodreads.com/user/year_in_books/2020/7515314" rel="noreferrer" target="_blank"&gt;40 books&lt;/a&gt; this year. I usually read fiction, however this year I aimed to read a mix of fiction and non-fiction.&lt;/p&gt;</description><author>Gaganpreet Arora</author><pubDate>Thu, 31 Dec 2020 23:34:38 GMT</pubDate><guid isPermaLink="true">https://gaganpreet.in/posts/books-of-2020/</guid></item><item><title>A smart guide for your career as a software engineer</title><link>https://www.mootoday.com/blog/a-smart-guide-for-your-career-as-a-software-engineer</link><description>Do you want to earn a six figure income, work from anywhere, live a lifestyle of your choosing and be a part of the people who develop the next generation software applications? Are you a software engineer already, but want to change jobs or advance in your current role to get promoted?</description><author>www.mootoday.com - RSS Feed</author><pubDate>Thu, 31 Dec 2020 21:29:05 GMT</pubDate><guid isPermaLink="true">https://www.mootoday.com/blog/a-smart-guide-for-your-career-as-a-software-engineer</guid></item><item><title>New Year's Resolution 2021</title><link>https://oo.svbtle.com/new-year-s-resolution-2021</link><description>&lt;p&gt;Well, here is something more personal and also something that has been kind of a tradition for me: publish my New Year’s Resolution on my blog.&lt;/p&gt;

&lt;p&gt;I’ve spent the past couple of days occasionally thinking what my NYR’s could be… My incentive behind writing those down is that I’ve honestly had success in the past following them (in contrary to what many other people say about theirs) and also it helps me focusing on something I want in my life.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;start psychotherapy 😒&lt;/li&gt;
&lt;li&gt;read 12 books (spoiler I’ve only read one in 2020) 🤓&lt;/li&gt;
&lt;li&gt;start studying at a university (remote or in person, I live close to TU Berlin)&lt;/li&gt;
&lt;li&gt;get my driver’s license 🚗&lt;/li&gt;
&lt;li&gt;get my digital life organized 💽&lt;/li&gt;
&lt;li&gt;learn reading/playing piano notes 🎶&lt;/li&gt;
&lt;li&gt;become self-organized (calendar, ToDo, notes)&lt;/li&gt;
&lt;li&gt;more intimacy 💜&lt;/li&gt;
&lt;li&gt;stand up for myself 💪🏼&lt;/li&gt;
&lt;li&gt;get pierced 💎&lt;/li&gt;
&lt;li&gt;try contact lenses 👀&lt;/li&gt;
&lt;li&gt;finish three projects 🙈&lt;/li&gt;
&lt;li&gt;add more art in my life 🎨&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides these 13 things I’m of course hoping to keep this blog active and to making new internet friends.&lt;/p&gt;</description><author>Syd Norpol</author><pubDate>Thu, 31 Dec 2020 18:48:02 GMT</pubDate><guid isPermaLink="true">https://oo.svbtle.com/new-year-s-resolution-2021</guid></item><item><title>Soul</title><link>https://olshansky.info/movie/soul/</link><description>Olshansky's review of Soul</description><author>🦉 olshansky 🦁</author><pubDate>Thu, 31 Dec 2020 14:08:05 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/soul/</guid></item><item><title>Object Detection at 2530 FPS with TensorRT and 8-Bit Quantization</title><link>https://paulbridger.com/posts/tensorrt-object-detection-quantized/</link><description>This article is a deep dive into the techniques needed to get SSD300 object detection throughput to 2530 FPS. We will rewrite Pytorch model code, perform &lt;a href="https://github.com/NVIDIA/TensorRT/tree/master/tools/onnx-graphsurgeon"&gt;ONNX graph surgery&lt;/a&gt;, optimize &lt;a href="https://github.com/NVIDIA/TensorRT/tree/master/plugin/batchedNMSPlugin"&gt;a TensorRT plugin&lt;/a&gt; and finally we&amp;rsquo;ll quantize the model to an 8-bit representation. We will also examine divergence from the accuracy of the full-precision model.</description><author>Machine Learning Articles on paulbridger.com</author><pubDate>Thu, 31 Dec 2020 08:43:23 GMT</pubDate><guid isPermaLink="true">https://paulbridger.com/posts/tensorrt-object-detection-quantized/</guid></item><item><title>Sex workers must go POSSE</title><link>https://stop.zona-m.net/2020/12/sex-workers-must-go-posse/</link><description>&lt;p&gt;And no, I don&amp;rsquo;t mean &amp;ldquo;a large group often with a common&amp;hellip; interest&amp;rdquo;.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 31 Dec 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/sex-workers-must-go-posse/</guid></item><item><title>Implementer's Guide to SOCKS</title><link>https://cookie.engineer/weblog/articles/implementers-guide-to-socks.html</link><description>Tutorial on how to implement a SOCKS version 4/5 client and server from scratch, explaining related RFCs and potential quirks along the way.</description><author>Cookie Engineer's Web Log</author><pubDate>Thu, 31 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://cookie.engineer/weblog/articles/implementers-guide-to-socks.html</guid></item><item><title>2020 Year in Review</title><link>https://solomon.io/2020-year-in-review/</link><description>What a wild year 2020 has been. Even those of us that were closely monitoring the pandemic had no idea how it would change things.</description><author>Sam Solomon</author><pubDate>Thu, 31 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://solomon.io/2020-year-in-review/</guid></item><item><title>My Favorite Privacy Apps and Services</title><link>https://nelson.cloud/my-favorite-privacy-apps-and-services/?ref=rss</link><description>My favorite privacy-respecting tools, apps, and services.</description><author>Nelson Figueroa</author><pubDate>Thu, 31 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nelson.cloud/my-favorite-privacy-apps-and-services/?ref=rss</guid></item><item><title>2020 in 13 Seconds</title><link>https://huphtur.nl/2020-in-13-seconds/</link><description>&lt;p&gt;Right after we moved into &lt;a href="https://www.instagram.com/p/B4DR4uCFLMR/"&gt;our new house&lt;/a&gt;, I took a photo with my iPhone every morning at 8 am. So, 300+ photos later, here’s a timelapse in ~13 seconds:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://youtu.be/kHypqsFAysU"&gt;https://youtu.be/kHypqsFAysU&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The sound is the final track of The KLF’s &lt;em&gt;Chill Out&lt;/em&gt; album but reversed (thanks &lt;a href="https://audiomass.co/"&gt;AudioMass&lt;/a&gt;) for extra dramatic effect.&lt;/p&gt;
&lt;h2&gt;Highlights&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Houses with frost on the roofs." src="https://huphtur.nl/images/timelapse-first.jpg" /&gt;
December 3. The first photo I shot. Freezing cold morning with frost on the roofs.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Houses with a tree in full bloom." src="https://huphtur.nl/images/timelapse-bloom.jpg" /&gt;
March 11. The neighbor’s maple tree is now in full bloom, temperatures have risen a bit. Spring is here!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Houses and trees covered in snow." src="https://huphtur.nl/images/timelapse-snow.jpg" /&gt;
March 14. What spring? It’s snowing! Crazy to see the foliage bend under the weight of the snow. A week later we will bend under the pressure of COVID-19 and enter lock-down.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Couple houses and a big tree." src="https://huphtur.nl/images/timelapse-squirrel.jpg" /&gt;
July 1. SQUIRREL! Gotta zoom in a bit to spot it, but it’s sitting on top of the roof.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Houses and a big tree and the air is covered in a thick layer of smoke." src="https://huphtur.nl/images/timelapse-smoke.jpg" /&gt;
September 12. The entire west coast of America is on fire. Crazy thick smoke, and even though our house is well insulated, we still have some smoke seep in.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Houses in the winter with a seagull in the air." src="https://huphtur.nl/images/timelapse-bird.jpg" /&gt;
November 25. Pretty much the end of the year, a seagull flying away…&lt;/p&gt;
&lt;h2&gt;Lowlights&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;iPhone was not always aligned straight, so images jump around. Messed around in Affinity Photo for a couple of hours to get them aligned somewhat better. Wish I had used a tripod instead.&lt;/li&gt;
&lt;li&gt;Forgot about daylight savings nonsense. Kept shooting at 8 am, so shadows jump around.&lt;/li&gt;
&lt;li&gt;There are gaps in the sequence. Traveling (pre-pandemic), and when I forgot to take photos because life got busy. Oh, and that one time when I almost died from eating too much licorice (more on that in a future blog post).&lt;/li&gt;
&lt;li&gt;2020&lt;/li&gt;
&lt;/ul&gt;</description><author>huphtur</author><pubDate>Thu, 31 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://huphtur.nl/2020-in-13-seconds/</guid></item><item><title>Underusing the NHS</title><link>https://nindalf.com/posts/underusing-the-nhs/</link><description>A personal reflection on the author's experiences with the UK's National Health Service (NHS) and the challenges of overusing and underusing healthcare.</description><author>Krishna's blog</author><pubDate>Thu, 31 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/underusing-the-nhs/</guid></item><item><title>Dynamic Programming (i): Multiplying Matrices</title><link>https://alexmolas.com/2020/12/31/dynamic-programming-i.html</link><description>Learning how to multiply matrices in the best possible order, ie solving the Matrix Chaing Multiplication problem.</description><author>Alex Molas Blog</author><pubDate>Thu, 31 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://alexmolas.com/2020/12/31/dynamic-programming-i.html</guid></item><item><title>My Path to Developer Relations and Thoughts on the Future of DevRel</title><link>https://www.swyx.io/adventcado-qna</link><description>Alex Lakatos interviewed me for the Devrel Advent calendar he put together</description><author>swyx's site RSS Feed</author><pubDate>Thu, 31 Dec 2020 00:06:02 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/adventcado-qna</guid></item><item><title>My Journey from No CS Degree to AWS from Age 30 - 34</title><link>https://www.swyx.io/nocsdegree-pete</link><description>I was interviewed by Pete from No CS Degree on my journey, here are some extracts!</description><author>swyx's site RSS Feed</author><pubDate>Wed, 30 Dec 2020 23:21:47 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/nocsdegree-pete</guid></item><item><title>Swyx Interview on Daily Dev Tips</title><link>https://www.swyx.io/dailydevtips1</link><description>I was interviewed by Chris Bongers on Daily Dev Tips, here are some extracts.</description><author>swyx's site RSS Feed</author><pubDate>Wed, 30 Dec 2020 23:04:35 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/dailydevtips1</guid></item><item><title>Financialization of Big Tech is BIG</title><link>https://stop.zona-m.net/2020/12/financialization-of-big-tech-is-big/</link><description>&lt;p&gt;It really seems Too Big To Remain.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 30 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/financialization-of-big-tech-is-big/</guid></item><item><title>The Road Chose Me Volume 2: Three years and 54,000 miles around Africa</title><link>https://theroadchoseme.com/the-road-chose-me-volume-2-three-years-and-54000-miles-around-africa</link><description>I&amp;#8217;m extremely proud to announce I&amp;#8217;ve published my second major book in print! &amp;#8216;The Road Chose Me Volume 2&amp;#8217; documents my entire three year African expedition from start to finish. It covers the adventures,&amp;#46;&amp;#46;&amp;#46;</description><author>The Road Chose Me</author><pubDate>Wed, 30 Dec 2020 05:04:54 GMT</pubDate><guid isPermaLink="true">https://theroadchoseme.com/the-road-chose-me-volume-2-three-years-and-54000-miles-around-africa</guid></item><item><title>Python write_file utility</title><link>https://www.pinecoder.dev/blog/2020-12-30/python-write_file-utility/</link><description>Recently I wrote a python script for syncing data to a 3rd party service. I needed to output various text files during its run, both for debugging and audit history. Ideally, I wanted a simple function which would allow the following:
# Set some base directory via config working_dir = 'data' # Pass filenames and contents, with any directories # automatically created as necessary: # should output to: data/job_2/stats.csv write_file('/job_2/stats.csv.', raw_policy_data) # should output to: data/job_2/applications/results.</description><author>Home on Pinecoder blog</author><pubDate>Wed, 30 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.pinecoder.dev/blog/2020-12-30/python-write_file-utility/</guid></item><item><title>The ideal blog platform</title><link>https://nutcroft.mataroa.blog/blog/the-ideal-blog-platform/</link><description>&lt;p&gt;WordPress, Tumblr, Blogger, Medium, Ghost. Posthaven, Svbtle, Write.as.&lt;/p&gt;
&lt;p&gt;Blogging. The most elegant and natural process of idea diffusion on the web—since its infancy. Started barebones; developed massively; evolving continuously.&lt;/p&gt;
&lt;p&gt;I’m excited about the next step. Lately, in my social bubble of technology and startups, I notice a revisited focus to simplicity and minimalism. It’s probably part of a constant cycle, regardless, now it exists. In addition to that, there is a much wider, across the world, appreciation for controlling one’s data.&lt;/p&gt;
&lt;p&gt;Towards expressing this second part, it’s great if a blogging platform is open source. It’s also a good idea for a blogging web citizen to control their web estate: the blog domain. One can do that with a lot of blog platforms. To account for simplicity and minimalism, though, the most &lt;a href="https://sive.rs/polut"&gt;unwasteful&lt;/a&gt; and efficient way to run one’s blog is to serve static HTML. That is, to utilise a static site generator, rather than running a backend, a database, and all that entails. It’s a much simpler, more efficient, more elegant, and significantly faster way of web existence.&lt;/p&gt;
&lt;h2 id="self-hosted-blogs"&gt;Self hosted blogs&lt;/h2&gt;
&lt;p&gt;How to empower people to create their own self-hosted blog? There are some ideas. Drew instated the &lt;a href="https://drewdevault.com/make-a-blog"&gt;Make a blog&lt;/a&gt; initiative. Stavros made the &lt;a href="https://quicksite.stavros.io/"&gt;Quick Site&lt;/a&gt; guide. My idea was &lt;a href="https://mataroa.blog/"&gt;mataroa.blog&lt;/a&gt;, a blogging platform that makes it easy to get off it.&lt;/p&gt;
&lt;p&gt;There is a certain difficulty in starting to blog. It is inspiration that lights the fire, and inspiration is not on tap. I remember when I wanted to start a blog or write an article, I would dive into all the technicalities (re-styling, updating, refactoring, etc) and eventually not write anything.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mataroa.blog/"&gt;Mataroa.blog&lt;/a&gt; is designed for when inspiration comes. This is the time to just write, focus on the essence and get the words out. When done writing, there is lots of uninspired time to think about the best way to design, rework, speed up your blog. Mataroa enables one to do that by having export as a first-class feature. One can export into simple markdown text files, or &lt;a href="https://www.getzola.org/"&gt;Zola&lt;/a&gt; sources, or &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt; sources with a single click. One can also set a redirect domain, so that their mataroa blog automatically redirects to a new blog home.&lt;/p&gt;
&lt;p&gt;The greatest benefit of blogging platforms is that you can start writing immediately. No domain decisions, no servers, no coding. This comes at a cost, though: potential lock-in.&lt;/p&gt;
&lt;p&gt;To account for this and the aforementioned need for simplicity, the features I’d like to see in an ideal blog platform are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;absolutely no vendor lock-in&lt;/li&gt;
&lt;li&gt;it even helps you get off it&lt;/li&gt;
&lt;li&gt;open source&lt;/li&gt;
&lt;li&gt;simple&lt;/li&gt;
&lt;li&gt;minimal&lt;/li&gt;
&lt;li&gt;fast&lt;/li&gt;
&lt;li&gt;focus on the essence&lt;/li&gt;
&lt;li&gt;follow open standards such as RSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://mataroa.blog/"&gt;Mataroa.blog&lt;/a&gt; is designed with all these in mind.&lt;/p&gt;
&lt;p&gt;But, actually, I don’t want to sell mataroa to you; as much as I want to convince you on the merits of self-hosted personal blogs.&lt;/p&gt;
&lt;p&gt;The foundational platform of the web—the web itself—is more democratic than any medium (wink) has ever been—at least until now.&lt;/p&gt;
&lt;p&gt;Let’s build directly on it without intermediate layers.&lt;/p&gt;
&lt;h2 id="addendum-on-hosting"&gt;Addendum on hosting&lt;/h2&gt;
&lt;p&gt;During the last 10 years of massive web centralisation, there have been instances when the internet giants fall. AWS, Google, Cloudflare—bad days exist for them too.&lt;/p&gt;
&lt;p&gt;It’s funny to see your blog up when Google is down. Especially when the only reason is the choice of an indie cloud/server/hosting provider&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;. I used to depend on EC2 for servers, Netlify for CDN, Google for fonts, other CDNs for JavaScript libraries. Now, this blog loads fully from a single server with just two small requests, one HTML and one CSS file. So much fun!&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I have found &lt;a href="https://www.hetzner.com/"&gt;Hetzner&lt;/a&gt; to be pretty reliable during the last couple of years. I think it’s a good recommendation, though, I’m sure they have bad days too.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>nutcroft</author><pubDate>Wed, 30 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/the-ideal-blog-platform/</guid></item><item><title>BOINC dans un conteneur Docker</title><link>/post/2020/12/30/boinc-dans-un-conteneur-docker/</link><description>&lt;p&gt;J&amp;rsquo;ai déjà écrit &lt;a href="https://dbeley.ovh/post/2020/11/20/aider-la-science-avec-le-projet-boinc/"&gt;un article&lt;/a&gt; sur ce qu&amp;rsquo;était BOINC sans en détailler l&amp;rsquo;installation. L&amp;rsquo;installation classique de BOINC passe par le téléchargement du &lt;a href="https://boinc.berkeley.edu/download.php"&gt;client BOINC&lt;/a&gt;, mais il est aussi possible d&amp;rsquo;utiliser BOINC dans un conteneur docker.&lt;/p&gt;
&lt;p&gt;Cette méthode d&amp;rsquo;installation est plus facile à scripter et à automatiser, ce qui la rend très intéressante sur un serveur headless par exemple.&lt;/p&gt;
&lt;h2 id="installation-de-docker"&gt;Installation de docker&lt;/h2&gt;
&lt;p&gt;Tout d&amp;rsquo;abord, installons docker et docker-compose. Sur une distribution linux utilisant le gestionnaire de paquets apt (comme Debian ou Ubuntu), il suffit d&amp;rsquo;installer les paquets &lt;code&gt;docker.io&lt;/code&gt; et &lt;code&gt;docker-compose&lt;/code&gt;.&lt;/p&gt;</description><author>Accueil on dbeley</author><pubDate>Wed, 30 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">/post/2020/12/30/boinc-dans-un-conteneur-docker/</guid></item><item><title>The globalization of evil autocompletion</title><link>https://stop.zona-m.net/2020/12/the-globalization-of-evil-autocompletion/</link><description>&lt;p&gt;Beware of cliche' search engines!&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 29 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/the-globalization-of-evil-autocompletion/</guid></item><item><title>A Modernist Christmas</title><link>https://www.masswerk.at/nowgobang/2020/modernist-xmas</link><description>Festive architecture &amp; optimism</description><author>mass:werk – Now Go Bang!</author><pubDate>Tue, 29 Dec 2020 17:30:00 GMT</pubDate><guid isPermaLink="true">https://www.masswerk.at/nowgobang/2020/modernist-xmas</guid></item><item><title>Single Sign-On and Resource Separation on AWS</title><link>https://manuel.kiessling.net/2020/12/29/single-sign-on-and-resource-separation-on-aws/</link><description>Introduction Most AWS projects start small and simple, with just a single AWS account that contains all the resources and services to build, deploy, and run one or more software projects. Up to a certain point, this is just fine. And even with just one account, resources can be isolated from each other – for example, you can run the EC2 instances of your preproduction stage in a different VPC than the instances of your production stage.</description><author>Home on The Log Book of Manuel Kießling</author><pubDate>Tue, 29 Dec 2020 13:50:00 GMT</pubDate><guid isPermaLink="true">https://manuel.kiessling.net/2020/12/29/single-sign-on-and-resource-separation-on-aws/</guid></item><item><title>Kendall Peak Lakes Snowshoe</title><link>https://sam.hooke.me/trip/2020/12/kendall-peak-lakes-snowshoe/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;table class="stats-table"&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;th&gt;Distance&lt;/th&gt;
 &lt;th&gt;8.59 km / 5.34 miles&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Elevation gain&lt;/th&gt;
 &lt;th&gt;236 m / 773 ft&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Duration&lt;/th&gt;
 &lt;th&gt;4h25m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Moving&lt;/th&gt;
 &lt;th&gt;2h25m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
&lt;p&gt;We were mostly following the Kendall Peak Lakes Trail which starts at Gold Creek Sno-Park, though didn&amp;rsquo;t plan to actually reach the lakes. The main trail was quite popular, so we followed a side trail instead, which offered good views of the ski resort (smothered in mist) and inquisitive wildlife (camp robbers after our lunch). A tiny waterfall by the first switchback showcased some elaborate icy sculptures.&lt;/p&gt;</description><author>Sam Hooke</author><pubDate>Tue, 29 Dec 2020 04:20:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/12/kendall-peak-lakes-snowshoe/</guid></item><item><title>Swift package code coverage (plus Emacs overlay)</title><link>https://xenodium.com/swift-package-code-coverage</link><description>&lt;p&gt;While playing around with Swift package manager, I had a quick look into code coverage options. Luckily, coverage reporting and exporting are supported out of the box (via &lt;a href="https://llvm.org/docs/CommandGuide/llvm-cov.html"&gt;llvm-cov&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Ensure tests are invoked as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;swift test --enable-code-coverage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A high level report can be generated with:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;xcrun llvm-cov report .build/x86_64-apple-macosx/debug/FooPackageTests.xctest/Contents/MacOS/FooPackageTests \
      -instr-profile=.build/x86_64-apple-macosx/debug/codecov/default.profdata -ignore-filename-regex=&amp;quot;.build|Tests&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;llvm-cov can export as lcov format:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;xcrun llvm-cov export -format=&amp;quot;lcov&amp;quot; .build/x86_64-apple-macosx/debug/FooPackageTests.xctest/Contents/MacOS/FooPackageTests -instr-profile=.build/x86_64-apple-macosx/debug/codecov/default.profdata -ignore-filename-regex=&amp;quot;.build|Tests&amp;quot; &amp;gt; coverage.lcov
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the report in lcov format, we can look for an Emacs package to visualize coverage in source files. Found &lt;a href="https://github.com/twada/coverlay.el"&gt;coverlay.el&lt;/a&gt; to require minimal setup. I was interested in highlighting only untested areas, so I set &lt;em&gt;tested-line-background-color&lt;/em&gt; to nil:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(use-package coverlay
  :ensure t
  :config
  (setq coverlay:tested-line-background-color nil))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After installing coverlay, I enabled the minor mode via &lt;em&gt;M-x coverlay-minor-mode&lt;/em&gt;, invoked &lt;em&gt;M-x coverlay-watch-file&lt;/em&gt; to watch &lt;em&gt;coverage.lcov&lt;/em&gt; for changes, and voilà!&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/swift-package-code-coverage/coverage.png" /&gt;&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Tue, 29 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/swift-package-code-coverage</guid></item><item><title>Hiking bookmarks</title><link>https://xenodium.com/hiking-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=25568856"&gt;A growing list of long distance hikes around the world (Hacker News)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Tue, 29 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/hiking-bookmarks</guid></item><item><title>LitElement Web Components in React App</title><link>https://www.tderflinger.com/en/litelement-react-app</link><description>LitElement is a Web Component library by Google. It succeeds the Polymer library and strives for speed and compatibility with the Web Components standard. How to integrate LitElements into your React application and use event handling, I want to show in this article.</description><author>Thoughts by Thomas Derflinger</author><pubDate>Tue, 29 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.tderflinger.com/en/litelement-react-app</guid></item><item><title>Things I worked on in 2020</title><link>https://gilmi.me/post/2020/12/29/my-2020</link><description>In this post I'd like to look back and mention a few (programming related) things I worked on in 2020.</description><author>λm.me</author><pubDate>Tue, 29 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://gilmi.me/post/2020/12/29/my-2020</guid></item><item><title>Accurate Estimations</title><link>https://camhashemi.com/essays/accurate-estimations/</link><description>&lt;p&gt;We&amp;rsquo;re constantly asked to give estimations:&lt;/p&gt;&lt;p&gt;&lt;em&gt;How long will it take?&lt;br /&gt;How much will it cost?&lt;/em&gt;&lt;br /&gt;&lt;em&gt;What time should we leave?&lt;/em&gt;&lt;br /&gt;&lt;em&gt;How much do you want?&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Estimations are information about the unknown. We constantly use this information to make decisions: allocating resources, changing strategies, and choosing partners. But despite all this practice, we&amp;rsquo;re horrible at accurate estimations.&lt;/p&gt;&lt;h2 id="why-estimations-are-hard"&gt;Why Estimations are Hard&lt;/h2&gt;&lt;p&gt;Estimations are hard for both technical and social reasons.&lt;/p&gt;&lt;p&gt;We don&amp;rsquo;t know what we don&amp;rsquo;t know. Naive estimators fail to account for surprises. They estimate based on known factors and best-case scenarios. These estimates may be &lt;em&gt;perfectly accurate&lt;/em&gt; beforehand, but they&amp;rsquo;re instantly broken by the first surprise.&lt;/p&gt;&lt;p&gt;Experienced estimators account for this problem by &amp;lsquo;adding some buffer&amp;rsquo;. But even then, how much should they add? Even knowing that surprises &lt;em&gt;can&lt;/em&gt; happen, it&amp;rsquo;s impossible to know &lt;em&gt;how many&lt;/em&gt; will happen or &lt;em&gt;the impact&lt;/em&gt; of those surprises. Choosing the right amount of buffer is a lot like making the right estimation in the first place. We still don&amp;rsquo;t know what we don&amp;rsquo;t know. And adding too much buffer can be as expensive as failing to account for surprise at all.&lt;/p&gt;&lt;p&gt;In addition to this technical problem, there&amp;rsquo;s a strong social problem. Let&amp;rsquo;s imagine two common scenarios.&lt;/p&gt;&lt;p&gt;In the first scenario, you&amp;rsquo;re giving an estimate to your team. You perfectly estimate that a project will take three weeks; but your manager gives you a puzzled look. Your teammate snickers, claiming they could do it in a week, tops. The feeling is that you must be either lazy or incompetent to give such a padded estimation. Your newly shortened estimate is wrong, so you go on to extend the project&amp;rsquo;s deadline twice in three weeks. Rather than holding you accountable to that one-week estimate, your manager commends you for being able to handle the unforeseen surprises on such a complicated project.&lt;/p&gt;&lt;p&gt;In the other scenario, you&amp;rsquo;re giving an estimate to a potential client. You perfectly estimate that a project will take three weeks; but your competitor only estimates it&amp;rsquo;ll take a week. The client signs with your competitor. Since their estimate was wrong, your competitor goes on to extend the deadline twice in three weeks. Even though your estimate was accurate, your client&amp;rsquo;s estimate got them paid.&lt;/p&gt;&lt;p&gt;I&amp;rsquo;ve been in countless scenarios like this. Sometimes people outright pressure us into shortening our estimations, and sometimes the voice in our head pushes us to. Either way, giving accurate estimates is both technically hard and socially challenging &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&lt;h2 id="two-types-of-estimators"&gt;Two Types of Estimators&lt;/h2&gt;&lt;p&gt;In response to this hard problem, we become systematic underestimators or systematic overestimators.&lt;/p&gt;&lt;p&gt;Underestimators fail to give enough buffer. This strategy has two key benefits. First, it signals (unrealistically) high performance. Like our virtue-signalling teammate, we can underestimate ahead of time, then point at concrete surprises for our eventual underperformance. And like our overpromising competitor, we can underestimate during a bid and do whatever we want after the contract is signed. Second, tight estimates demand efficiency. Underestimators set deadlines that they and their teams must work hard to meet. Underestimation works well when the costs of going over-budget are small. But when those costs are large, underestimations lead to disasters. On the whole, underestimators systematically run the risk of being burnt out, past-deadline, and over-budget.&lt;/p&gt;&lt;p&gt;Overestimators are instead biased towards large buffers. Extreme overestimators might send you articles titled &amp;ldquo;Estimations are a Scam&amp;rdquo;, or claim that estimations are simply tools for worker exploitation. Overestimation works when the costs of buffer are low and the costs of going over budget are high. But overestimators are constantly taxed by Parkinson&amp;rsquo;s Law. Parkinson&amp;rsquo;s Law is the pattern where projects fill the time and resources they&amp;rsquo;re allocated, instead of the time and resources they need &lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;. Rather than pushing towards peak performance, overestimators systematically move at a bored, leisurely pace. Overestimators are also demotivating. Rather than inspiring the team to reach competitive goals, they disparage those who do. So while underestimators run the risk of their teams burning out, overestimators run the risk of their teams shutting down.&lt;/p&gt;&lt;p&gt;This line between underestimators and overestimators forms a classic &amp;ldquo;spectrum problem&amp;rdquo;. A spectrum problem occurs when we oversimplify the solution to a given tradeoff. In this case, we&amp;rsquo;re splitting the spectrum of estimation strategies in half. Underestimators fall on one side of the line, and overestimators fall on the other. With many spectrum problems, the better solution is to cut the spectrum into three pieces, choosing the middle strategy between extremes. In doing so, we acknowledge the costs and rewards of both sides, maximizing the upsides and minimizing the downsides systematically.&lt;/p&gt;&lt;h2 id="playing-single-pointed-darts"&gt;Playing Single-Pointed Darts&lt;/h2&gt;&lt;p&gt;Imagine a game of darts with very simple rules. I throw my dart first, and you only score by hitting that same exact dart-sized point. This game is very simple, but so difficult that nobody would play it. To make darts playable, we specify scoring &lt;em&gt;ranges&lt;/em&gt;. These same ranges are missing from our everyday estimations.&lt;/p&gt;&lt;p&gt;The most common estimate sounds something like: &amp;ldquo;I&amp;rsquo;ll have it ready by 5pm.&amp;rdquo; But this is just like playing single-point darts! Imagine that this estimate is perfectly precise: the project can&amp;rsquo;t be ready one second before or one second after 5pm. While impressive, there&amp;rsquo;s zero room for error. If we end up sick, or if the project ends up more complex than expected, our estimate becomes instantly wrong.&lt;/p&gt;&lt;p&gt;To account for surprises, we can add buffer. But adding buffer only shifts the dart board over a few inches. &amp;ldquo;I&amp;rsquo;ll have it ready by 5pm &lt;em&gt;tomorrow&lt;/em&gt;&amp;rdquo; faces all the same problems as the first estimation. Two days of surprises still makes me wrong. We&amp;rsquo;re still playing single-pointed darts.&lt;/p&gt;&lt;p&gt;It&amp;rsquo;s a losing game. And yet we see it played again and again, day after day, project after project.&lt;/p&gt;&lt;h2 id="playing-darts-with-ranges"&gt;Playing Darts with Ranges&lt;/h2&gt;&lt;p&gt;To enjoy this game of darts, we need to change the rules. Rather than giving a single-pointed estimate, we give two points: one for the best case, and one for the worst case. These two points create a range of targets to hit, just like the game of darts we know and love.&lt;/p&gt;&lt;p&gt;To demonstrate, I can give an example from my personal life. My girlfriend is very punctual, and I&amp;rsquo;m not. She&amp;rsquo;s a classic overestimator, giving as much buffer as we can afford. And I&amp;rsquo;m a classic underestimator, giving the most optimistic estimates. So whenever we have somewhere to be, and she asks me &amp;ldquo;what time should we be ready?&amp;quot;… it&amp;rsquo;s a classic estimation problem!&lt;/p&gt;&lt;p&gt;Recently, I&amp;rsquo;ve started giving her two answers. The first answer is &amp;ldquo;the green time&amp;rdquo;. &lt;strong&gt;The green time tells us when we should leave so that we&amp;rsquo;re pleasantly early&lt;/strong&gt;. The second answer is &amp;ldquo;the red time&amp;rdquo;. &lt;strong&gt;The red time is the last minute we can leave, without definitely being late&lt;/strong&gt;. If we can be ready by the green time without stress or shortcuts, that&amp;rsquo;s perfect. Once we pass the green time, we go into the &amp;ldquo;yellow zone.&amp;rdquo; &lt;strong&gt;The yellow zone is the buffer between early and late&lt;/strong&gt;. There&amp;rsquo;s no need to take shortcuts or change plans yet, but we&amp;rsquo;re getting close. Once we approach the red line, we start discussing the need to take shortcuts, or to start telling others that we may be a little late.&lt;/p&gt;&lt;p&gt;Having a green time, a yellow zone, and a red time transforms our game of single-pointed darts into a proper dartboard, with zones of success. The green time makes my girlfriend happy: she can be ready early without worry. The red time makes me happy: I can fill my buffer time up with other activities. And the yellow zone is a signal for both of us to get focused or to start taking shortcuts &lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&lt;p&gt;Ranges make uncertainty explicit. Adding buffer doesn&amp;rsquo;t just shift the dartboard a few inches, it expands our range of accuracy. Larger buffers signal more uncertainty and require less precision, while smaller buffers signal more confidence and require more precision. The expression of certainty and confidence isn&amp;rsquo;t possible to communicate with a single-pointed estimate.&lt;/p&gt;&lt;p&gt;By estimating with two numbers instead of one, a richness of new information and strategies become available to us.&lt;/p&gt;&lt;h2 id="simple-changes"&gt;Simple Changes&lt;/h2&gt;&lt;p&gt;Using two numbers instead of one, these so-called &amp;ldquo;confidence intervals&amp;rdquo; aren&amp;rsquo;t complicated. Then why are they so absent from everyday life?&lt;/p&gt;&lt;p&gt;Although nothing prevented us from discovering them earlier, the first mention of confidence intervals in scientific literature wasn&amp;rsquo;t until 1937. And it wasn&amp;rsquo;t until the 1980s that they were required in scientific journals. So if it took forty years for the most knowledgeable people to apply a simple solution towards the most urgent problems, it&amp;rsquo;s not surprising that it&amp;rsquo;s taken the rest of us at least as long. That said, the goal of this essay is to speed up that process.&lt;/p&gt;&lt;p&gt;We can move towards accurate estimations by practicing two simple rules. The first: &lt;strong&gt;When giving an estimate, state the best- and worst-case answers.&lt;/strong&gt; The second: &lt;strong&gt;Whenever getting an estimate, ask for the best- and worst-case answers.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&amp;ldquo;It&amp;rsquo;ll take two weeks&amp;rdquo; should raise a red flag. A better answer sounds like: &amp;ldquo;in the best case, one week; in the worst case, three&amp;rdquo;. Boom! Now we have a range of days to deliver the project, instead of one. Not only do we have a picture of the optimal scenario, we have an idea for the hidden risks lurking in the future.&lt;/p&gt;&lt;p&gt;As a bonus, we&amp;rsquo;re capable of using the &amp;ldquo;green line, yellow zone, red line&amp;rdquo; imagery to guide our actions &lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;. The green line is how we strive for the best and signal our competence. The red line is our insurance policy in case of surprises. The yellow zone is where time is critical, and we need to coordinate in case our plans need to change.&lt;/p&gt;&lt;p&gt;In a world of uncertainty, this extra byte of information is enough to create more accurate thought and action.&lt;/p&gt;&lt;h3 id="footnotes"&gt;Footnotes&lt;/h3&gt;&lt;div class="footnotes"&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id="fn:1"&gt;&lt;p&gt;Though questionable, accurate estimations are worth the effort. First of all, accurate estimations build trust. After a few false promises, people catch on. Like compound interest, commitments founded on years of accrued trust are worth much more than short-term deals based on deceptive estimates. Secondly, inaccurate estimations kick off a vicious cycle of degrading quality. Underestimations lead to insufficient resources, insufficient resources lead to shortcuts, shortcuts lead to poor quality, and poor quality leads to greater consumption of resources. These teams work harder and harder to do less and less. Inversely, overestimations lead to too many resources, too many resources lead to inefficiency, inefficiency leads to overestimations. These teams take longer and longer to do less and less.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id="fn:2"&gt;&lt;p&gt;Parkinson&amp;rsquo;s Law is the insight that projects tend to consume the resources given to them, be it time, money, or people. Fear of Parkinson&amp;rsquo;s Law motivates people to justify tight deadlines. They claim that without tight deadlines, people tend to get lazy or unfocused.But if Parkinson&amp;rsquo;s Law was the whole story, we&amp;rsquo;d never see projects go over budget! But since we see projects go over deadline and budget all the time, adjusting deadlines can&amp;rsquo;t be the only factor. Instead, keeping deadlines as tight as possible leads to burnout, in addition to all the other costs of underestimating. Though useful for timeboxing projects in general, Parkinson&amp;rsquo;s Law should not be used as the sole guiding principle for estimations.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id="fn:3"&gt;&lt;p&gt;In professional projects, the same concepts apply a bit differently. The green time is the earliest a project can be ready, satisfying the &lt;em&gt;underestimators&lt;/em&gt;; and the red time would be the latest a project can be ready, satisfying the &lt;em&gt;overestimators&lt;/em&gt;. Underestimators can still push for the green time, while overestimators still find peace of mind in knowing the red time exists.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li id="fn:4"&gt;&lt;p&gt;&amp;ldquo;One week, give or take two days&amp;rdquo; in a common way to convey a similar amount of information. I focused on the &amp;ldquo;best case / worst case&amp;rdquo; framing, because it opens the door to the green / yellow / red style of project management. That said, two answers are always better than one, so if adding a &amp;ldquo;give or take&amp;rdquo; is an easier way to make this transition in how we estimate, I&amp;rsquo;m all for it.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description><author>Cam Hashemi</author><pubDate>Mon, 28 Dec 2020 18:15:04 GMT</pubDate><guid isPermaLink="true">https://camhashemi.com/essays/accurate-estimations/</guid></item><item><title>Plan Your Year</title><link>http://evantravers.com/articles/2020/12/28/plan-your-year/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/12/planyouryear.jpg" /&gt;&lt;/p&gt;&lt;p&gt;This will be the fourth year my wife and I purchased and used &lt;a href="https://thefocuscourse.com/plan-your-year/"&gt;Plan Your Year from The Focus Course&lt;/a&gt;. This year I am going paperless… I even spent some time this morning scanning in all the previous year's editions.&lt;/p&gt;
&lt;p&gt;I &lt;strong&gt;really&lt;/strong&gt; like this tool. Some quick thoughts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I &lt;em&gt;love&lt;/em&gt; that this is a system designed to be used as a family to build a shared vision.&lt;/li&gt;
&lt;li&gt;It's encouraging to read back over these as an overview. Lots of &lt;a href="http://evantravers.com/articles/2020/10/30/new-book-same-story/"&gt;reasons to praise the Lord for his faithful hand&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;That which we planned for… largely happened. Even in 2020!&lt;/li&gt;
&lt;li&gt;Any month we didn't have a design for… fell into default behaviors. Good or bad. (Mostly bad.)&lt;/li&gt;
&lt;li&gt;Plan Your Year does a great job of balancing personal growth vs. accomplishing projects. &lt;em&gt;Both&lt;/em&gt; are critical.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Shawn and the team at The Focus Course built a great tool and wisely modified this version for this specific and stressful year… flipping through its pages I'm excited to learn and grow with my little family, and I recommend it to y'all, &lt;em&gt;especially&lt;/em&gt; if you don't have a shared vision for investing your time and talents in 2021.&lt;/p&gt;</description><author>trv.rs</author><pubDate>Mon, 28 Dec 2020 16:33:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/12/28/plan-your-year/</guid></item><item><title>node.example.com Is An IP Address</title><link>https://tuckersiemens.com/posts/node-example-com-is-an-ip-address/</link><description>&lt;p&gt;Hello! Welcome to the once-yearly blog post! This year I'd like to examine the
most peculiar bug I encountered at work. To set the stage, let's start with a
little background.&lt;/p&gt;</description><author>Reilly Tucker Siemens</author><pubDate>Mon, 28 Dec 2020 16:13:05 GMT</pubDate><guid isPermaLink="true">https://tuckersiemens.com/posts/node-example-com-is-an-ip-address/</guid></item><item><title>Working at Amazon</title><link>https://purpleidea.com/blog/2020/12/28/working-at-amazon/</link><description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I&amp;rsquo;ve got a new job working for &lt;a href="https://aws.amazon.com/"&gt;Amazon&lt;/a&gt;, in
the &amp;ldquo;Open Source Program Office&amp;rdquo;. I&amp;rsquo;m now an Amazoner!
More information below&amp;hellip;
&lt;br /&gt;
&lt;br /&gt;&lt;/p&gt;
&lt;table style="text-align: center; width: 80%; margin: 0 auto;"&gt;&lt;tr&gt;&lt;td&gt;
&lt;a href="https://purpleidea.com/blog/2020/12/28/working-at-amazon/amazon.jpg"&gt;&lt;img class="alignnone size-full" src="https://purpleidea.com/blog/2020/12/28/working-at-amazon/amazon.jpg" width="100%" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The Amazon. Source: https://en.wikipedia.org/wiki/Amazon_rainforest&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;



&lt;br /&gt;&lt;span style="text-decoration: underline; font-weight: bold;"&gt;Background&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;

&lt;p&gt;A little over three months ago, &lt;a href="https://purpleidea.com/blog/2020/09/10/james-is-available-for-hire/"&gt;I decided to get back into full-time work&lt;/a&gt;.
For the past 2.5 years since &lt;a href="https://purpleidea.com/blog/2018/04/04/leaving-redhat/"&gt;I left my job at Red Hat&lt;/a&gt;,
I&amp;rsquo;ve been mostly working full-time on &lt;a href="https://purpleidea.com/projects/mgmt-config/"&gt;Mgmt Config&lt;/a&gt; and
my &lt;a href="https://purpleidea.com/projects/mentoring-program/"&gt;DevOps/SWE Mentoring Program&lt;/a&gt;. To do such
things, I had to live off of my savings, which isn&amp;rsquo;t sustainable long-term. I am
thankful that I was able to do so for so long. It was time to dive back in, and
here I am.&lt;/p&gt;</description><author>The Technical Blog of James on purpleidea.com</author><pubDate>Mon, 28 Dec 2020 15:27:35 GMT</pubDate><guid isPermaLink="true">https://purpleidea.com/blog/2020/12/28/working-at-amazon/</guid></item><item><title>jlink's Missing Link: API Signature Validation</title><link>https://www.morling.dev/blog/jlinks-missing-link-api-signature-validation/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_the_example"&gt;The Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_the_api_signature_check_jlink_plug_in"&gt;The API Signature Check jlink Plug-in&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_summary"&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Discussions around Java’s &lt;a href="https://openjdk.java.net/jeps/282"&gt;jlink&lt;/a&gt; tool typically center around savings in terms of (disk) space.
Instead of shipping an entire JDK,
a custom runtime image created with jlink contains only those JDK modules which an application actually requires,
resulting in smaller distributables and &lt;a href="blog/smaller-faster-starting-container-images-with-jlink-and-appcds/"&gt;container images&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;But the contribution of jlink — as a part of the Java module system at large — to the development of Java application’s is bigger than that:
with the notion of &lt;em&gt;link time&lt;/em&gt; it defines an optional complement to the well known phases &lt;em&gt;compile time&lt;/em&gt; and application &lt;em&gt;run-time&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="quoteblock"&gt;
&lt;blockquote&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Link time is an opportunity to do whole-world optimizations that are otherwise difficult at compile time or costly at run-time. An example would be to optimize a computation when all its inputs become constant (i.e., not unknown). A follow-up optimization would be to remove code that is no longer reachable.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Mon, 28 Dec 2020 13:20:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/jlinks-missing-link-api-signature-validation/</guid></item><item><title>Speedrunning Computer Games History with a 6yr Old - Part 1</title><link>https://duncanlock.net/blog/2020/12/27/speedrunning-computer-games-history-with-a-6yr-old-part-1/</link><description>&lt;section id="preamble"&gt;&lt;figure class="image-block"&gt;&lt;img alt="Galaxians vector" src="https://duncanlock.net/images/posts/speedrunning-computer-games-history-with-a-6yr-old-part-1/galaxians-blueprint-crop-compressed.svg" width="500" /&gt;
&lt;figcaption&gt;Figure 1. Galaxians.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;As a family gift for Christmas 2020, I set up a &lt;a href="https://www.raspberrypi.org/products/raspberry-pi-400/"&gt;Raspberry Pi 400&lt;/a&gt; with &lt;a href="https://retropie.org.uk/"&gt;Retropie&lt;/a&gt;. The plan is to load a selection of the &amp;#8220;best of the best&amp;#8221; games from computer game history, starting with games up to, roughly,&amp;nbsp;1985.&lt;/p&gt;
&lt;p&gt;The kid doesn&amp;#8217;t really know any better, so we can play Space Invaders unsullied by time and expectations and enjoy a speedrun through gaming history, playing &lt;em&gt;just&lt;/em&gt; the&amp;nbsp;highlights.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll add more games as we go along, progressing through gaming history, one classic game at a&amp;nbsp;time.&lt;/p&gt;
&lt;aside class="admonition-block note"&gt;&lt;h6 class="block-title"&gt;&lt;span class="title-label"&gt;Note: &lt;/span&gt;Screen&amp;nbsp;time&lt;/h6&gt;&lt;p&gt;I&amp;#8217;m going to mention screen time up-front. The kids get very little screen time Monday to Friday - partly because we want it this way and partly because there just isn&amp;#8217;t&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;In the mornings, &lt;em&gt;if they get ready early&lt;/em&gt;, they get the rest of the time before we leave, and the bedtime glide path starts with dinner at about 6pm - and no screens after dinner is a hard rule. They generally &lt;em&gt;don&amp;#8217;t&lt;/em&gt; get ready early, so they generally get about 0-30 mins &lt;em&gt;total&lt;/em&gt; screen time &lt;em&gt;per week&lt;/em&gt;,&amp;nbsp;Monday-Friday.&lt;/p&gt;
&lt;p&gt;Weekends&amp;#8230;&amp;#8203; we have a lie-in and they watch cartoons until we get up, so usually an hour or&amp;nbsp;two.&lt;/p&gt;&lt;/aside&gt;&lt;/section&gt;
&lt;section class="doc-section level-1"&gt;&lt;h2 id="_why"&gt;Why?&lt;/h2&gt;&lt;figure class="image-block"&gt;&lt;img alt="A black screen, with the BBC Basic prompt and flashing cursor." src="https://duncanlock.net/images/posts/speedrunning-computer-games-history-with-a-6yr-old-part-1/Hard_reset_BBC_Micro_32K_Acorn_DFS-crop.webp" /&gt;
&lt;figcaption&gt;Figure 2. The Mighty &lt;span class="caps"&gt;BBC&lt;/span&gt; &lt;span class="caps"&gt;BASIC&lt;/span&gt; prompt. This is what you saw when you booted it up - straight into an interactive programming environment: a 1980s &lt;span class="caps"&gt;REPL&lt;/span&gt;. Just type in &lt;span class="caps"&gt;BASIC&lt;/span&gt; code/commands and press Enter.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;When I was around 8 yrs old, my parents bought a &lt;a href="https://en.wikipedia.org/wiki/BBC_Micro"&gt;&lt;span class="caps"&gt;BBC&lt;/span&gt; Micro Model B&lt;/a&gt; - an early 8-bit home computer. Home computers were very new back then and I&amp;#8217;d never used one before. We played games on it. A lot. &lt;a href="http://bbcmicro.co.uk/game.php?id=3525"&gt;Asteriods&lt;/a&gt;, &lt;a href="http://bbcmicro.co.uk/game.php?id=1934"&gt;Frogger&lt;/a&gt;, &lt;a href="http://bbcmicro.co.uk/game.php?id=353"&gt;Missile Strike&lt;/a&gt;, &lt;a href="http://bbcmicro.co.uk/game.php?id=89"&gt;Twin Kingdom Valley&lt;/a&gt;, &lt;a href="http://bbcmicro.co.uk/game.php?id=2647"&gt;Racer&lt;/a&gt;, &lt;a href="http://bbcmicro.co.uk/index.php?search=Repton&amp;amp;on_Z=on"&gt;Repton&lt;/a&gt;, &lt;a href="http://bbcmicro.co.uk/game.php?id=25"&gt;Chuckie Egg&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Elite_(video_game)"&gt;Elite&lt;/a&gt;, etc, etc&amp;#8230;&amp;#8203; all loaded (very slowly) from &lt;a href="https://en.wikipedia.org/wiki/Cassette_tape"&gt;cassette tape&lt;/a&gt;. There were also lots of games and other programs that came as code, printed out in books or magazines, which you then typed&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;Later, I started writing my own little &lt;span class="caps"&gt;BASIC&lt;/span&gt; programs. I think partly because that was what Mum &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Dad actually &lt;em&gt;wanted&lt;/em&gt; us to do with this rather expensive computer, and partly because it was &lt;em&gt;interesting&lt;/em&gt; to get the computer to do things - and gratifying when they &lt;em&gt;finally&lt;/em&gt;&amp;nbsp;worked.&lt;/p&gt;
&lt;p&gt;Like many others, this little machine changed the trajectory of my life. I&amp;#8217;ve been fortunate to have made a reasonable living out of programming computers. It&amp;#8217;s &lt;em&gt;still&lt;/em&gt; interesting to get computers to do things that you thought up - and it&amp;#8217;s &lt;em&gt;still&lt;/em&gt; gratifying when it &lt;em&gt;finally&lt;/em&gt; works, even after all this&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;I have no illusions that we can re-create this experience - you can&amp;#8217;t step into the same river twice. However, I hope that we might be able to capture a &lt;em&gt;few&lt;/em&gt; of the best bits, the most fun &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; most useful, while making new memories of our&amp;nbsp;own.&lt;/p&gt;
&lt;p&gt;I think that the 6yr old is currently in a narrow window where this might be possible. They haven&amp;#8217;t really had much exposure to computer games, and the &lt;span class="caps"&gt;COVID&lt;/span&gt;-19 pandemic will keep them out of their peers houses for a while longer. But, because kids these days are surrounded by advanced computers, with modern 3D graphics and sound, I can&amp;#8217;t leave it until they&amp;#8217;re 8 or 9 - the window will have closed and modernity will have forever changed&amp;nbsp;expectations.&lt;/p&gt;
&lt;p&gt;I think that I&amp;#8217;ve got about a year or so, at the most, before Minecraft and Roblox sweep this all away and close the window. I&amp;#8217;m going to see if we can get to 1992 before then - it&amp;#8217;s around this time that I think the games will start to stand up on their own, graphics &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; fun wise, against Minecraft. Maybe? Alright, probably not. We&amp;#8217;ll see how it goes - either way, it&amp;#8217;ll be fun while it&amp;nbsp;lasts.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s also around that point that the Raspberry Pi 400 will start to struggle to emulate the more demanding games &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; systems, so we&amp;#8217;ll have to do something else then&amp;nbsp;anyway.&lt;/p&gt;
&lt;section class="doc-section level-2"&gt;&lt;h3 id="_what_do_you_have_against_minecraftroblox"&gt;What do you have against&amp;nbsp;Minecraft/Roblox?&lt;/h3&gt;&lt;p&gt;Absolutely nothing, I think they&amp;#8217;re great! The problem is, once you play modern games with modern(-ish) 3d graphics, your expectations are forever changed. It makes it harder to appreciate games which don&amp;#8217;t have similarly modern graphics. This isn&amp;#8217;t a fault of older games, it&amp;#8217;s just a change in expectations - it&amp;#8217;s hard to put that toothpaste back into the tube.
When we get there, I hope we&amp;#8217;ll play Minecraft &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Roblox together too - and maybe &lt;a href="https://www.codeadvantage.org/coding-for-kids-blog/minecraft-vs-roblox"&gt;use them to introduce coding&lt;/a&gt;.&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section class="doc-section level-1"&gt;&lt;h2 id="_a_modern_home_computer"&gt;A Modern &amp;#8220;Home&amp;nbsp;Computer&amp;#8221;&lt;/h2&gt;&lt;p&gt;I&amp;#8217;m intending the Raspberry Pi 400 to be &amp;#8220;the family/kids/home computer&amp;#8221; for a&amp;nbsp;while:&lt;/p&gt;
&lt;div class="quote-block"&gt;&lt;blockquote&gt;&lt;p&gt;Featuring a quad-core 64-bit processor, &lt;span class="caps"&gt;4GB&lt;/span&gt; of &lt;span class="caps"&gt;RAM&lt;/span&gt;, wireless networking, dual-display output, and 4K video playback, as well as a 40-pin &lt;span class="caps"&gt;GPIO&lt;/span&gt; header, Raspberry Pi 400 is a powerful, easy-to-use computer built into a neat and portable&amp;nbsp;keyboard.&lt;/p&gt;&lt;footer&gt;&amp;#8212; &lt;cite&gt;&lt;a class="bare" href="https://www.raspberrypi.org/products/raspberry-pi-400/"&gt;https://www.raspberrypi.org/products/raspberry-pi-400/&lt;/a&gt;&lt;/cite&gt;&lt;/footer&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;p&gt;We can use it to play games on - but it&amp;#8217;s also a regular Linux box, running Raspbian (a Debian distro) and can run a huge array of Linux software. It&amp;#8217;s easy to change its personality but just booting it off a different &lt;span class="caps"&gt;USB&lt;/span&gt; stick/&lt;span class="caps"&gt;SD&lt;/span&gt; card, with a different &lt;span class="caps"&gt;OS&lt;/span&gt; &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; apps on. I&amp;#8217;m intending to use it to introduce the kids to programming, as well as basic electronics and robotics - all of which are well-supported by the Pi&amp;#8217;s hardware and huge maker&amp;nbsp;community.&lt;/p&gt;&lt;/section&gt;
&lt;section class="doc-section level-1"&gt;&lt;h2 id="_hardware"&gt;Hardware&lt;/h2&gt;&lt;p&gt;We live in a pretty small apartment, so everything needed to be able to pack away as small as possible, without breaking the bank. The combination of the Raspberry Pi 400, which released at just the right time for this project, and a portable monitor - means that the system packs away fairly&amp;nbsp;neatly.&lt;/p&gt;
&lt;figure class="image-block"&gt;&lt;img alt="The assembled system, with Raspberry Pi, monitor and controllers, sitting on an Ikea Lack table. Underneath the table are two boxes and a small pouch; the system packs away into these when not in use." src="https://duncanlock.net/images/posts/speedrunning-computer-games-history-with-a-6yr-old-part-1/IMG_20210331_155217-small.jpg" /&gt;
&lt;figcaption&gt;Figure 3. The assembled system, with Raspberry Pi, monitor and controllers, sitting on an Ikea Lack table. Underneath the table are two boxes and a small pouch; the system packs away into these when not in use.&lt;/figcaption&gt;&lt;/figure&gt;
&lt;div class="ulist"&gt;&lt;ul&gt;&lt;li&gt;The system itself is a &lt;a href="https://www.raspberrypi.org/products/raspberry-pi-400/"&gt;Raspberry Pi&amp;nbsp;400&lt;/a&gt;&lt;/li&gt;&lt;li&gt;The monitor is a &lt;a href="https://amzn.to/3fxx5BN"&gt;Portable 15.6&amp;#8221; &lt;span class="caps"&gt;TN&lt;/span&gt; Screen Full &lt;span class="caps"&gt;HD&lt;/span&gt;&amp;nbsp;1920×1080&lt;/a&gt;&lt;/li&gt;&lt;li&gt;The controllers are some retro &lt;span class="caps"&gt;NES&lt;/span&gt; style &lt;span class="caps"&gt;USB&lt;/span&gt; ones. I actually bought two pairs, &lt;a href="https://amzn.to/2Ppq2jR"&gt;these ones&lt;/a&gt; and some Buffalo ones from this &lt;a href="https://www.ebay.ca/usr/ship_japan"&gt;awesome seller on eBay&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;p&gt;The monitor arrived without the bent metal wire stand, so I ended up making some decorative stands out of cardboard and covering them with retro game&amp;nbsp;artwork:&lt;/p&gt;
&lt;figure class="image-block"&gt;&lt;img alt="The monitor stands I made from cardboard." src="https://duncanlock.net/images/posts/speedrunning-computer-games-history-with-a-6yr-old-part-1/IMG_20210331_155229-small.jpg" /&gt;
&lt;figcaption&gt;Figure 4. These stands came out pretty well, if I do say so myself - and they&amp;#8217;ve unexpectedly been a hit with the kid, too. I often get &amp;#8220;Which game is this?&amp;#8221; or &amp;#8220;I want to play this one&amp;#8221; - pointing at one of the pictures on these stands.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/section&gt;
&lt;section class="doc-section level-1"&gt;&lt;h2 id="_software"&gt;Software&lt;/h2&gt;&lt;p&gt;It&amp;#8217;s running &lt;a href="https://retropie.org.uk/"&gt;Retropie&lt;/a&gt;, which is a nice retro gaming system, which makes installing and configuring everything pretty&amp;nbsp;simple:&lt;/p&gt;
&lt;div class="quote-block"&gt;&lt;blockquote&gt;&lt;p&gt;[Retropie] builds upon Raspbian, EmulationStation, RetroArch and many other projects to enable you to play your favourite Arcade, home-console, and classic &lt;span class="caps"&gt;PC&lt;/span&gt; games with the minimum set-up. For power users it also provides a large variety of configuration tools to customise the system as you&amp;nbsp;want.&lt;/p&gt;&lt;footer&gt;&amp;#8212; &lt;cite&gt;&lt;a href="https://retropie.org.uk/"&gt;Retropie&lt;/a&gt;&lt;/cite&gt;&lt;/footer&gt;&lt;/blockquote&gt;&lt;/div&gt;
&lt;p&gt;I used the Retropie image to install this, which means you just need to write the image to an &lt;span class="caps"&gt;SD&lt;/span&gt; card and boot it up. You can use &lt;a href="https://www.balena.io/etcher/"&gt;Balena Etcher&lt;/a&gt;, the &lt;a href="https://www.raspberrypi.org/blog/raspberry-pi-imager-imaging-utility/"&gt;Raspberry Pi Imager&lt;/a&gt;, or &lt;a href="https://www.raspberrypi.org/documentation/installation/installing-images/linux.md"&gt;dd&lt;/a&gt; to do this. &lt;a href="https://retropie.org.uk/docs/First-Installation/"&gt;Installation instructions are here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The games were selected from my memory, and various&amp;nbsp;lists:&lt;/p&gt;
&lt;div class="ulist"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/List_of_video_games_considered_the_best"&gt;Wikipedia: List of video games considered the&amp;nbsp;best&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.denofgeek.com/games/the-15-greatest-zx-spectrum-games-ever-made/"&gt;The 15 Greatest &lt;span class="caps"&gt;ZX&lt;/span&gt; Spectrum Games Ever&amp;nbsp;Made&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.retrogamer.net/top_10/top-ten-commodore-64-games/"&gt;Top Ten Commodore 64&amp;nbsp;Games&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.lemon64.com/games/votes_list.php"&gt;The Lemoners Top Commodore 64&amp;nbsp;Games&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.retrogamer.net/top_10/top-ten-apple-ii-games/"&gt;Top Ten Apple &lt;span class="caps"&gt;II&lt;/span&gt;&amp;nbsp;Games&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;p&gt;We started with the following emulated systems &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;games:&lt;/p&gt;
&lt;section class="doc-section level-2"&gt;&lt;h3 id="_arcade"&gt;Arcade&lt;/h3&gt;&lt;p&gt;These all work flawlessly in &lt;code&gt;lr-mame&lt;/code&gt;, with perfect controller mappings out of the&amp;nbsp;box.&lt;/p&gt;
&lt;div class="ulist three-columns"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Galaga_%2788"&gt;Galaga &amp;#8216;88&lt;/a&gt;&amp;nbsp;(1988)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Galaxian"&gt;Galaxian&lt;/a&gt;&amp;nbsp;(1979)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Pac-Man"&gt;Pac-Man&lt;/a&gt;&amp;nbsp;(1980)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Frogger"&gt;Frogger&lt;/a&gt;&amp;nbsp;(1981)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Qix"&gt;Qix&lt;/a&gt;&amp;nbsp;(1981)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Defender_(1981_video_game)"&gt;Defender&lt;/a&gt;&amp;nbsp;(1981)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Q*bert"&gt;Qbert&lt;/a&gt;&amp;nbsp;(1982)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Donkey_Kong_(video_game)"&gt;Donkey Kong&lt;/a&gt;&amp;nbsp;(1981)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Centipede_(video_game)"&gt;Centipede&lt;/a&gt;&amp;nbsp;(1981)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/BurgerTime"&gt;BurgerTime&lt;/a&gt;&amp;nbsp;(1982)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Arkanoid"&gt;Arkanoid&lt;/a&gt;&amp;nbsp;(1986)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section class="doc-section level-2"&gt;&lt;h3 id="_zx_spectrum"&gt;&lt;span class="caps"&gt;ZX&lt;/span&gt;&amp;nbsp;Spectrum&lt;/h3&gt;&lt;p&gt;The &lt;a href="https://github.com/chernandezba/zesarux"&gt;Zesarux emulator&lt;/a&gt; is a pretty great, but the speccy graphics are a bit basic, and they&amp;#8217;re mostly intended for keyboard play, so we have to remap them for the&amp;nbsp;controllers.&lt;/p&gt;
&lt;div class="ulist three-columns"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Bubble_Bobble"&gt;Bubble Bobble&lt;/a&gt;&amp;nbsp;(1987)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Tetris"&gt;Tetris&lt;/a&gt;&amp;nbsp;(1988)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/R-Type"&gt;R-Type&lt;/a&gt;&amp;nbsp;(1988)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Manic_Miner"&gt;Manic Miner&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Knight_Lore"&gt;Knight Lore&lt;/a&gt;&amp;nbsp;(1984)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Jet_Set_Willy"&gt;Jet Set Willy&lt;/a&gt;&amp;nbsp;(1984)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Head_over_Heels_(video_game)"&gt;Head Over Heels&lt;/a&gt;&amp;nbsp;(1987)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Dizzy_(series)"&gt;Dizzy&lt;/a&gt;&amp;nbsp;(1987)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Chuckie_Egg"&gt;Chuckie Egg&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Chase_H.Q."&gt;Chase &lt;span class="caps"&gt;H.Q.&lt;/span&gt;&lt;/a&gt;&amp;nbsp;(1989)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Chaos:_The_Battle_of_Wizards"&gt;Chaos - The Battle of the Wizards&lt;/a&gt;&amp;nbsp;(1985)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Atic_Atac"&gt;Atic Atac&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Deathchase"&gt;Deathchase&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section class="doc-section level-2"&gt;&lt;h3 id="_atari_2600"&gt;Atari&amp;nbsp;2600&lt;/h3&gt;&lt;div class="ulist"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Pitfall!"&gt;Pitfall!&lt;/a&gt;&amp;nbsp;(1982)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section class="doc-section level-2"&gt;&lt;h3 id="_apple_ii"&gt;Apple &lt;span class="caps"&gt;II&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;This is a keyboard oriented emulator, so controller mapping, etc&amp;#8230;&amp;#8203; Also, the sound is pretty&amp;nbsp;bleepy.&lt;/p&gt;
&lt;div class="ulist three-columns"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Lode_Runner"&gt;Lode Runner&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Choplifter"&gt;Choplifter&lt;/a&gt;&amp;nbsp;(1982)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Cavern_Creatures"&gt;Cavern Creatures&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Where_in_the_World_Is_Carmen_Sandiego%3F_(1985_video_game)"&gt;Where in the World is Carmen Sandeigo&lt;/a&gt; (1985) - this has two floppy disks and it&amp;#8217;s annoying to swap disks in the emulator. Also text&amp;nbsp;heavy.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/section&gt;
&lt;section class="doc-section level-2"&gt;&lt;h3 id="_commodore_64"&gt;Commodore&amp;nbsp;64&lt;/h3&gt;&lt;p&gt;This emulator doesn&amp;#8217;t seem to work very well and the games are difficult to get working &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; figure out controls. Consequently, we really haven&amp;#8217;t played any of these so far. I&amp;#8217;m sure it&amp;#8217;s just a matter of me sitting down and figuring out how to configure it&amp;nbsp;properly.&lt;/p&gt;
&lt;div class="ulist three-columns"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Zak_McKracken_and_the_Alien_Mindbenders"&gt;Zak McKracken &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; the Alien Mindbenders&lt;/a&gt;&amp;nbsp;(1988)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Wizball"&gt;Wizball&lt;/a&gt;&amp;nbsp;(1987)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Winter_Games"&gt;Winter Games&lt;/a&gt;&amp;nbsp;(1985)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Turrican"&gt;Turrican 1&lt;/a&gt;&amp;nbsp;(1990)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Turrican_II:_The_Final_Fight"&gt;Turrican 2: Final Fight&lt;/a&gt;&amp;nbsp;(1991)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Turbo_Outrun"&gt;Turbo OutRun&lt;/a&gt;&amp;nbsp;(1989)&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.c64-wiki.com/wiki/The_Sentinel"&gt;The Sentinel&lt;/a&gt;&amp;nbsp;(1986)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/M.U.L.E."&gt;&lt;span class="caps"&gt;M.U.L.E.&lt;/span&gt;&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Manic_Miner"&gt;Manic Miner&lt;/a&gt;&amp;nbsp;(1983)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Maniac_Mansion"&gt;Maniac Mansion&lt;/a&gt;&amp;nbsp;(1987)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Lemmings_(video_game)"&gt;Lemmings&lt;/a&gt;&amp;nbsp;(1991)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Laser_Squad"&gt;Laser Squad with Expansion Missions&lt;/a&gt;&amp;nbsp;(1988)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/International_Karate_%2B"&gt;International Karate +&lt;/a&gt;&amp;nbsp;(1987)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Boulder_Dash"&gt;Boulder Dash&lt;/a&gt;&amp;nbsp;(1984)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
&lt;p&gt;We should probably play the LucasArts games on &lt;a href="https://www.scummvm.org/"&gt;ScummVM&lt;/a&gt;&amp;nbsp;anyway.&lt;/p&gt;&lt;/section&gt;
&lt;section class="doc-section level-2"&gt;&lt;h3 id="_zmachine"&gt;ZMachine&lt;/h3&gt;&lt;p&gt;These are all text adventures, so require reading &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt;&amp;nbsp;writing.&lt;/p&gt;
&lt;div class="ulist three-columns"&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Zork"&gt;Zork I&lt;/a&gt;&amp;nbsp;(1980)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Zork_II"&gt;Zork &lt;span class="caps"&gt;II&lt;/span&gt;&lt;/a&gt;&amp;nbsp;(1981)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Zork_III"&gt;Zork &lt;span class="caps"&gt;III&lt;/span&gt;&lt;/a&gt;&amp;nbsp;(1982)&lt;/li&gt;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Starcross_(video_game)"&gt;Starcross&lt;/a&gt;&amp;nbsp;(1982)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/section&gt;&lt;/section&gt;
&lt;section class="doc-section level-1"&gt;&lt;h2 id="_ill_report_back_later"&gt;I&amp;#8217;ll report back&amp;nbsp;later&amp;#8230;&amp;#8203;&lt;/h2&gt;&lt;p&gt;I realize that&amp;#8217;s too many games, but&amp;#8230;&amp;#8203; I got a bit carried away? Probably we won&amp;#8217;t get around to playing all of these before we pass them by for newer pastures, but that&amp;#8217;s&amp;nbsp;life.&lt;/p&gt;
&lt;p&gt;So, we&amp;#8217;ll try it out and see how we get on&amp;#8201;&amp;#8211;&amp;#8201;and I&amp;#8217;ll report back later on our&amp;nbsp;progress.&lt;/p&gt;&lt;/section&gt;</description><author>duncan­lock­.net</author><pubDate>Mon, 28 Dec 2020 08:13:51 GMT</pubDate><guid isPermaLink="true">https://duncanlock.net/blog/2020/12/27/speedrunning-computer-games-history-with-a-6yr-old-part-1/</guid></item><item><title>Horrors and errors of SOME independent book sellers</title><link>https://stop.zona-m.net/2020/12/horrors-and-errors-of-some-independent-book-sellers/</link><description>&lt;p&gt;And what they tell us, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 28 Dec 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/horrors-and-errors-of-some-independent-book-sellers/</guid></item><item><title>Wenatchee Crest Snowshoe</title><link>https://sam.hooke.me/trip/2020/12/wenatchee-crest-snowshoe/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;table class="stats-table"&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;th&gt;Distance&lt;/th&gt;
 &lt;th&gt;12.26 km / 7.62 miles&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Elevation gain&lt;/th&gt;
 &lt;th&gt;222 m / 728 ft&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Duration&lt;/th&gt;
 &lt;th&gt;5h25m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Moving&lt;/th&gt;
 &lt;th&gt;2h50&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;We left Seattle early, but due to the long drive across the Cascades it was already 10:30am by the time we set off.&lt;/p&gt;
&lt;p&gt;I had read that the views from this hike were spectacular, but there was a thick mist as far as we could see. This was quite atmospheric and felt like being lost in a cloud.&lt;/p&gt;</description><author>Sam Hooke</author><pubDate>Mon, 28 Dec 2020 04:30:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/12/wenatchee-crest-snowshoe/</guid></item><item><title>Patience</title><link>https://xenodium.com/patience</link><description>&lt;p&gt;Via &lt;a href="https://twitter.com/orangebook_/status/1291844997097099265?s=12"&gt;Orange Book&lt;/a&gt;, a reminder to myself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In investing, patience is rewarded.&lt;/li&gt;
&lt;li&gt;In growing a talent, patience is rewarded.&lt;/li&gt;
&lt;li&gt;In building a business, patience is rewarded.&lt;/li&gt;
&lt;li&gt;In love and friendships, patience is rewarded.&lt;/li&gt;
&lt;li&gt;Patience = success&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I feel like there's an Emacs lesson somewhere in there…&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Mon, 28 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/patience</guid></item><item><title>Futureproof</title><link>https://mattkeeter.com/projects/futureproof</link><description>A shader editor in Zig, WebGPU, and Neovim</description><author>Matt Keeter</author><pubDate>Mon, 28 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://mattkeeter.com/projects/futureproof</guid></item><item><title>The Pragmatic Programmer - Review</title><link>https://lukesingham.com/pragmatic-programmer-review/</link><description>&lt;p&gt;📚 Book: &lt;a href="https://www.goodreads.com/book/show/4099.The_Pragmatic_Programmer"&gt;The Pragmatic Programmer&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;⭐️ Rating: 4/5 Sagely advice that is written in an engaging and highly consumable form.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://lukesingham.com/content/images/2020/pragmatic-programmer-frontcover.png#thumbnail" /&gt;&lt;/p&gt;
&lt;p&gt;The Pragmatic Programmer is a very good book full of practical advice. It's written with little &lt;em&gt;Tip&lt;/em&gt; boxes which are the tl:dr; of a particular section. Plus, there's a healthy sprinkling of Dad jokes throughout the book 😁.&lt;/p&gt;
&lt;p&gt;Unlike, a &lt;a href="https://lukesingham.com/mythical-man-month-review/"&gt;Mythical Man Month&lt;/a&gt;, I would recommend this to seasoned professionals as well as newbies. Though this also has a lot of content for the seasoned professional, it is much easier to parse. Instead of having long anecdotes about long since dead technology to glean the lesson, this book is to the point, with helpful tip boxes, exercises and the examples are mostly relevant to today.&lt;/p&gt;
&lt;h2 id="%E2%9D%97%EF%B8%8F-some-criticisms-of-the-book%3A"&gt;❗️ Some criticisms of the book: &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%E2%9D%97%EF%B8%8F-some-criticisms-of-the-book%3A"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h4 id="tip-17%3A-program-close-to-the-problem-domain"&gt;Tip 17: Program close to the problem domain &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#tip-17%3A-program-close-to-the-problem-domain"&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Whilst I agree with the principle, the accompanying pages advocate for the creation of &lt;em&gt;mini languages&lt;/em&gt; in order to get closer to the domain. The project manager senses in me (I am not a project manager) can see this quickly becoming a rabbit hole distraction where developers end up on an academic pursuit of these mini languages, the necessary language parsers, documentation etc. The suggestion to create languages for all makes me cringe,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There's the end user, who understands the business rules and the required outputs. There are also secondary users: operations staff, configuration and test managers, support and maintenance programmers, and future generations of developers. Each of these users has their own problem domain and you can generate mini-environments and languages for all of them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I've not observed anyone creating a mini-language during a project. What I think is more practical and occurs in real-world projects is creating packages of functions whose scope is limited to a particular domain. Such that the ontological representation, the digital recreation of real world concepts happens with a set of classes and/or functions that map to the domain.&lt;/p&gt;
&lt;h4 id="chp-3---the-basic-tools"&gt;Chp 3 - The Basic Tools &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#chp-3---the-basic-tools"&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This chapter discusses tools that a pragmatic programmer should have in their tool kit. Inevitably the technological tools have changed in the intervening years. Well, Emacs and Vi are still around, but the recommended plugins etc. are out of date. If you don't have a good toolset already, I'd recommend going through MIT's &lt;a href="https://missing.csail.mit.edu/"&gt;The Missing Semester of Your CS Education.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="%E2%9C%85-major-(useful)-points-of-the-book"&gt;✅ Major (Useful) Points of the Book &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%E2%9C%85-major-(useful)-points-of-the-book"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="%E2%9A%96%EF%B8%8F-involve-your-users-in-the-trade-off"&gt;⚖️ Involve Your Users in the Trade-Off &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%E2%9A%96%EF%B8%8F-involve-your-users-in-the-trade-off"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It's quite a common occurrence for technical people when asked by a stakeholder to feel anxious or pressured to provide an estimate of when something can be done on the spot. For a particular data request, this might mean involving the stakeholder in the tradeoff between how accurate vs how quick the deliverable's turnaround is.&lt;/p&gt;
&lt;h3 id="%F0%9F%8D%B8-dry"&gt;🍸 DRY &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%8D%B8-dry"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Don't repeat yourself (DRY) is a commonly held maxim of programming. The Pragmatic Programmer exposits the common causes for duplication. This can arise from multiple places, project requirements, multiple target platforms, multiple programming languages being used in one system, laziness etc. A programmer may have to duplicate the schema of a database table to represent it as a class in their program. Documentation in code as comments and as a separate accompanying document. But these can be duplicative of each other.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;good code has lots of comments&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;☝️ A slight digression from DRY, but this go-to book for the industry is in favour of lots of comments in code. I've come across a few developers who like to argue the code &lt;em&gt;is&lt;/em&gt; documentation. But code will never tell you &lt;em&gt;why&lt;/em&gt; the code has been written this way, or the &lt;em&gt;trade offs&lt;/em&gt; considered in choosing a particular approach. I've never heard anyone complain &lt;em&gt;'there are just too many comments in this codebase'&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;With all rules there are &lt;a href="https://orbifold.xyz/dry-trade-off.html"&gt;exceptions and trade-offs with DRY&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="%F0%9F%93%90-orthogonality"&gt;📐 Orthogonality &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%93%90-orthogonality"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip 13: Eliminate effects between unrelated things&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I know orthogonality as &lt;em&gt;modularity&lt;/em&gt; or &lt;em&gt;decoupling&lt;/em&gt;. A great example of modularity is the way unix command line was designed with lots of modular tools that you can chain together using &lt;code&gt;|&lt;/code&gt; pipes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are two main benefits of orthogonality increased productivity and reduced risk.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="%F0%9F%8E%AF-tracer-bullets"&gt;🎯 Tracer Bullets &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%8E%AF-tracer-bullets"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Better known these days as 'agile development', 'MVP' and 'iteration'. &lt;em&gt;Tracer Bullets&lt;/em&gt; are discussed over several pages. Most people could probably skip this as the doctrine of Agile has mostly replaced Waterfall.&lt;/p&gt;
&lt;h3 id="%F0%9F%A4%94-estimates"&gt;🤔 Estimates &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%A4%94-estimates"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip 18:  Estimate to avoid surprises&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Involve your users&lt;/em&gt; and ask if they need high accuracy or a ballpark figure for the estimate. First understand the problem space, this will involve working with your user to understand not just what they are asking, but what their &lt;em&gt;actual problem&lt;/em&gt; is. Then whiteboard what the system is you will build to solve it. If this is large enough a system, then estimate how long each component could take to build. Keep track of this estimate so you can track the accuracy of your estimates. As you go through each project iteration (sprint) update the estimate based on any change in delivery schedule that may now be apparent.&lt;/p&gt;
&lt;p&gt;A fun fact from a footnote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is the value of π? &amp;quot;3&amp;quot;... if you are a legislator. In 1897, Indiana State Legislature House Bill No. 246 attempted to decree that henceforth π should have the value of &amp;quot;3&amp;quot;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Lastly, when asked for an estimate &lt;em&gt;you say, &amp;quot;I'll get back to you&amp;quot;&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="%F0%9F%90%9B-debugging"&gt;🐛 Debugging &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%90%9B-debugging"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is a good chapter and great if you're new to tech. &lt;em&gt;The first rule of debugging&lt;/em&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip 25: Don't Panic&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I've done this, and seen others do it. But it really is counterproductive. Take a deep breath 🧘‍♀️, and approach it with the Zen of a master. This will help avoid the myopia of jumping on fixes for the symptoms that you immediately see rather than taking a step back to assess the bigger picture here. This is something I usually call, &lt;em&gt;developing hypotheses&lt;/em&gt; of the root causes or, what are the possible &lt;em&gt;solution paths&lt;/em&gt; we could go down - it's best to get a range of options before jumping down one that could prove fruitless. Instead, rank the hypotheses in order of most likely, then proceed with the highest ranked hypothesis.&lt;/p&gt;
&lt;h4 id="various-debugging-tips"&gt;Various debugging tips &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#various-debugging-tips"&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Reproduce the bug&lt;/em&gt; on your machine or a dev environment.&lt;/li&gt;
&lt;li&gt;Visualise your data. Log it to a console, use code breaks.&lt;/li&gt;
&lt;li&gt;🐥 &lt;a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging"&gt;Rubber Duck&lt;/a&gt; with someone else - if they have the time, doing this at the outset can help develop more hypotheses as to what is causing the problem and get a better assessment on which is most likely.&lt;/li&gt;
&lt;li&gt;If there's not an obvious place to start, apply the principle of binary search.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Tip 27: Don't assume it, prove it&lt;/em&gt;, this can help avoid putting fixes in place that aren't really fixes. This can happen because your dev environment is different to prod. Or you accidentally were on the wrong branch of code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="%F0%9F%93%83-design-by-contract"&gt;📃 Design by Contract &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%93%83-design-by-contract"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The book talks about Java Object Oriented examples. However the principle applies to all code. Does your code return the expected data with the expected types? Does the logic do what it promises to do? Include assertions, tests and document assumptions. An example of the principle applied to a data pipeline where each model is some Spark or SQL code &lt;code&gt;A -&amp;gt; B -&amp;gt; C&lt;/code&gt;. The final select of model &lt;code&gt;A&lt;/code&gt; uses &lt;code&gt;SELECT *&lt;/code&gt; or &lt;code&gt;SELECT *EXCEPT(x,y,z)&lt;/code&gt; this is not enforcing model &lt;code&gt;A&lt;/code&gt;'s side of the contract. When model &lt;code&gt;B&lt;/code&gt; consumes from model &lt;code&gt;A&lt;/code&gt;, if similar shorthand &lt;code&gt;SELECT *&lt;/code&gt; is applied, you can end up with a minor code fix that introduces a new column, changing the schema of tables flowing right through this simple pipeline all the way to model &lt;code&gt;C&lt;/code&gt;. This can be easily avoided by explicitly naming the columns to be returned such that downstream models won't accidentally have their schemas changed by an upstream model. Even better, enforce the contract when you select columns from an upstream data model.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip 33: If it can't happen, use assertions[or tests] to ensure that it won't&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip 36: Minimise coupling between modules&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="%F0%9F%8E%9B-design-for-concurrency"&gt;🎛 Design for Concurrency &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%8E%9B-design-for-concurrency"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The book uses the example of making a cocktail and all the tasks that are required from 'open blender' to 'get pink umbrellas'. If you analyse all of these tasks, some are dependent on others to complete. But many tasks are able to happen in parallel to another task. Diagrams can help design for concurrency.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://lukesingham.com/content/images/2020/design-for-concurrency.svg" /&gt;&lt;/p&gt;
&lt;h3 id="%F0%9F%A7%B9-refactoring"&gt;🧹 Refactoring &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%A7%B9-refactoring"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Code needs to evolve. It is not static. And unfortunately many people perceive software as &lt;em&gt;done&lt;/em&gt; once it is delivered. Software is more like gardening - you might start a gardening project with a plan, plant seedlings according to the plan, but later some plants didn't like the soil others have overgrown. You monitor and regularly tend to the garden to keep it at its best.&lt;/p&gt;
&lt;h4 id="when-to-refactor%3F"&gt;When to refactor? &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#when-to-refactor%3F"&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;These are common qualifiers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Duplication&lt;/li&gt;
&lt;li&gt;Highly coupled components&lt;/li&gt;
&lt;li&gt;Outdated knowledge i.e. does the code still reflect the real world problem&lt;/li&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip 47: Refactor Early, Refactor Often&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If time pressure is used as an excuse from management, explain technical debt is like a cancer that grows and is riskier and more time consuming to remove the longer you leave it.&lt;/p&gt;
&lt;h4 id="how-to-refactor%3F"&gt;How to refactor? &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#how-to-refactor%3F"&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Don't try to refactor and add functionality. Leave TODOs if you must.&lt;/li&gt;
&lt;li&gt;Make sure you have good tests before starting to refactor, otherwise you may not know when you have broken something.&lt;/li&gt;
&lt;li&gt;Take short deliberate changes and test them. Rather than large sweeping changes all at once.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="%F0%9F%93%9A-requirements"&gt;📚 Requirements &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%93%9A-requirements"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To understand what the user needs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip 52: Work with a user to think like a user&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you have the problem of too many requirements, then point out how much each suggested requirement is going to increase project delivery by.&lt;/p&gt;
&lt;h3 id="%F0%9F%A7%AA-testing"&gt;🧪 Testing &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#%F0%9F%A7%AA-testing"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Test Early. Test Often. Test Automatically.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unit Tests&lt;/strong&gt; - is code that exercise a particular piece of code in isolation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration Tests&lt;/strong&gt; - shows that the major subsystems that make up the project work and play well with each other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Testing&lt;/strong&gt; - does it meet the users expectations?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance Testing / Stress Testing&lt;/strong&gt; - does it scale? Is it going to crash as soon as 100 users are using it at the same time?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usability Testing&lt;/strong&gt; - This is about UX. It might pass &lt;em&gt;user testing&lt;/em&gt; but does it feel like the extension of the users hand? Does it feel more like an Apple product or another product that technically does the same but just feels awkward.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="notes"&gt;Notes &lt;a class="direct-link" href="https://lukesingham.com/pragmatic-programmer-review/#notes"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I'd recommend the entirety of chapter 6 &lt;em&gt;While you are coding&lt;/em&gt; - particularly the 'How to program deliberately section'&lt;/li&gt;
&lt;li&gt;One of the simplest explanations of O notation is in this book.&lt;/li&gt;
&lt;li&gt;There's a great section in Chp 8 Pragmatic Projects on team organisation advocating for teams to be organised around functionality which also reflects the decoupled principle.&lt;/li&gt;
&lt;/ul&gt;</description><author>Luke Singham</author><pubDate>Mon, 28 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lukesingham.com/pragmatic-programmer-review/</guid></item><item><title>Art Exercise: Lupine Forest Cabin</title><link>https://blog.yiningkarlli.com/2020/12/lupine-forest-cabin-art-project.html</link><description>&lt;div&gt;

  &lt;p&gt;&lt;/p&gt;
  &lt;h2 id="table-of-contents"&gt;Table of Contents&lt;/h2&gt;

  &lt;div class="tableofcontents"&gt;
    &lt;div class="tableofcontents-row"&gt;
        &lt;div class="tableofcontents-column3"&gt;
            &lt;div class="tableofcontents-content"&gt;
                1. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-introduction"&gt;Introduction&lt;/a&gt;&lt;br /&gt;
                2. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-initial-blocking"&gt;Initial Blocking&lt;/a&gt;&lt;br /&gt;
                3. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-forest-floor"&gt;Forest Floor&lt;/a&gt;&lt;br /&gt;
                4. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-making-moss"&gt;Making Moss&lt;/a&gt;&lt;br /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="tableofcontents-column3"&gt;
            &lt;div class="tableofcontents-content"&gt;
                5. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-filling-out-the-clearing"&gt;Filling out the Clearing&lt;/a&gt;&lt;br /&gt;
                6. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-mist-and-atmospherics"&gt;Mist and Atmospherics&lt;/a&gt;&lt;br /&gt;
                7. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-final-lighting"&gt;Final Lighting&lt;/a&gt;&lt;br /&gt;
                8. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-conclusion"&gt;Conclusion&lt;/a&gt;&lt;br /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="tableofcontents-column3"&gt;
            &lt;div class="tableofcontents-content"&gt;
                9. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-references"&gt;References&lt;/a&gt;&lt;br /&gt;
                10. &lt;a href="/2020/12/lupine-forest-cabin-art-project.html#2020-12-28-footnotes"&gt;Footnotes&lt;/a&gt;&lt;br /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

  &lt;div id="2020-12-28-introduction"&gt;&lt;/div&gt;
  &lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;

  &lt;p&gt;I recently did a small personal art exercise to experiment with building out a detailed forest type of environment.
I have worked with a detailed forest scene before, when I used one while I was &lt;a href="https://blog.yiningkarlli.com/2018/10/bidirectional-mipmap.html"&gt;developing Takua Renderer’s mipmapping and texture caching system&lt;/a&gt;, but in that case I didn’t actually &lt;em&gt;make&lt;/em&gt; the scene, I just took an off-the-shelf scene and ported it to Takua.
I also made a forest for the background of &lt;a href="https://blog.yiningkarlli.com/2019/11/woodville-renderman-challenge.html"&gt;my Woodville RenderMan Art Challenge piece&lt;/a&gt;, but to be honest, I wasn’t very happy with how that turned out.
I think the background forest in my Woodville piece looks decent when viewed from a distance, as it is seen in that scene, but it doesn’t come even remotely close to holding up when viewed close up.
Also, that forest was incredibly difficult to author.
For the Woodville piece, I chose Maya’s MASH toolset over the XGen toolset to create the background forest; I chose MASH because MASH generally feels much more native to Maya and doesn’t have all of the extra file management that XGen requires.
However, I found that MASH has performance problems when the things being instanced have really heavy geometry and there are a lot of instances, as is the case when instancing trees and bushes and the type of stuff generally found in forests.
For this exercise, I wanted to focus on building a forest environment that would be detailed enough to hold up at closer distances, which means including things like leaf litter and twigs and small rocks on the ground, displacement-based bark on trees, moss on various surfaces, and so on.
I also wanted to find a more efficient way to author these kinds of environments.&lt;/p&gt;

  &lt;p&gt;This post is essentially a collated version of my notes from this project, published here mostly because having them all in one place is useful for me to refer back to later but also in case anyone else finds this stuff interesting.
Before I go into the details of how this project went, here’s what the final result looks like:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_day.webp"&gt;&lt;img alt="Figure 1: Final piece, daylight variant. Made for fun and as an environment building exercise. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_day.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-12-28-initial-blocking"&gt;&lt;/div&gt;
  &lt;h2 id="initial-blocking"&gt;Initial Blocking&lt;/h2&gt;

  &lt;p&gt;I didn’t really come into this project with much of a plan on what the final image would look like.
To be honest, the goal of this project wasn’t even necessarily to make the most visually or artistically interesting image; the goal was primarily a technical exercise to practice building a complex scene.
I actually started not with forest related things at all but instead I started with just trying to build an interesting groundplane.
My plan was to use as many off-the-shelf premade assets as possible and focus on assembling everything together into a nice scene and focus on final lighting.
Quixel Megascans has a lot of amazing large-scale 3D scans of rock formations and cliff faces; I had used a few of these back on the Woodville RenderMan Art Challenge and had made a note to myself back then to play with the Megascans large-scale rock formation assets more later.
I started with placing a bunch of Megascans rock formations to get a sense of initial shaping for the scene.
The overall shaping I went with for the scene draws from the principle of “compression and release”- I wanted the foreground to be through a narrower passage opening up into a larger space in the background, which I think helps give a sense that we’re looking into a larger world:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/cliffs.webp"&gt;&lt;img alt="Figure 2: Starting point: kitbashing some Quixel Megascans rock formations together." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/cliffs.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;The next step was to put in a groundplane of dirt and soil.
Since at the time RenderMan didn’t have hex-tiling &lt;a href="https://doi.org/10.1145/3233304"&gt;[Heitz and Neyret 2018&lt;/a&gt;, &lt;a href="http://jcgt.org/published/0008/04/02/"&gt;Burley 2019]&lt;/a&gt; yet, I used the same technique that I used on the Woodville RenderMan Art Challenge to hide tiling in the groundplane textures: the groundplane texture is made up of several different tiled soil and dirt textures, projected using PxrRoundCube with different rotations per texture, blended together using a couple of different noise projections.
One useful trick I added in this time was to also use the displacement maps to drive which texture “wins” at each blend point; this allows for nice things like larger rocks poking through layers of dirt and stuff.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/groundplane.webp"&gt;&lt;img alt="Figure 3: Roughing in a groundplane by blending together a bunch of different tiled soil and dirt textures, partially modulated by displacement height." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/groundplane.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Overall though I didn’t put too much effort into the groundplane since I expected it to be almost entirely covered with vegetation in the final scene, meaning very little of it would be directly visible. After getting the groundplane to a good-enough state, I fired up Maya’s XGen Geometry Instancer and started roughing in what all of the vegetation in the scene would look like.&lt;/p&gt;

  &lt;p&gt;The XGen toolset that ships with Maya today is really two essentially completely different toolsets packaged into a single plugin- &lt;a href="https://help.autodesk.com/view/MAYAUL/2020/ENU/?guid=GUID-496603B0-F929-45CD-B607-1CFCD3283DBE"&gt;XGen Interactive Grooming&lt;/a&gt;, and &lt;a href="https://help.autodesk.com/view/MAYAUL/2020/ENU/?guid=GUID-C6324505-BD4F-4FD2-B340-CF99158D4819"&gt;XGen Geometry Instancer&lt;/a&gt;.
XGen Geometry Instancer was &lt;a href="https://investors.autodesk.com/news-releases/news-release-details/walt-disney-pictures-and-autodesk-sign-xgen-technology-license"&gt;forked from Disney Animation’s internal XGen instancing system over a decade ago&lt;/a&gt;, while XGen Interactive Grooming was then added some years later &lt;a href="https://www.mtodd.work/new-page-1"&gt;[Todd 2013]&lt;/a&gt; as a totally separate authoring interface for hair workflows.
For this project, I only used the Geometry Instancer half of XGen.
I’ve had a fair amount of experience with Disney Animation’s version of XGen, so using the Maya version of XGen Geometry Instancer has been an interesting experience- the version in Maya was fairly heavily reworked to be more integrated into Maya compared with Disney Animation’s standalone version, and the two versions have since diverged even more due to many years of independent development and evolution, but there are still clearly a lot of Disney-isms in Maya’s XGen, such as the use of SeExpr &lt;a href="https://wdas.github.io/SeExpr/"&gt;[Disney Animation 2011]&lt;/a&gt; and Ptex &lt;a href="https://doi.org/10.1111/j.1467-8659.2008.01253.x"&gt;[Burley &amp;amp; Lacewell 2008]&lt;/a&gt; to control instancing distributions and properties.&lt;/p&gt;

  &lt;p&gt;The basic workflow for Xgen Geometry Instancer is to first create a bunch of &lt;em&gt;archives&lt;/em&gt; of geometry that the user wants to instance, and then create a &lt;em&gt;description&lt;/em&gt;, which is a set of instances of the archives scattered across some area of geometry, called a &lt;em&gt;patch&lt;/em&gt;.
When the underlying geometry that XGen instances are being scattered on is a polygon mesh, patches bind to the faces of the mesh.
Multiple decriptions can be organized together as a &lt;em&gt;collection&lt;/em&gt;.
Something that is a bit frustrating about XGen Geometry Instancer is that its integration into Maya is… somewhat strange.
Maya’s XGen Geometry Instancer doesn’t really feel or behave like a native part of Maya- XGen descriptions and collections show up in the Maya outliner, but are edited through a dedicated separate interface instead of the standard Attribute or Channel editors, and instead of storing all data as part of the Maya file, XGen Geometry Instancer creates and depends on a bunch of external sidecar files, and even worse, paths baked into these external files don’t respect the project workspace system that Maya uses, making reusing XGen description between different Maya projects kind of annoying to do.
All of this is the result of XGen Geometry Instancer being derived from an internal standalone tool at Disney Animation- the internal version of XGen makes a lot of sense integrated within the overall Disney Animation pipeline, but none of this was originally designed to be a deeply integrated part of Maya outside of Disney Animation, and even with all of the work that Autodesk put into making the commercially available Maya version of the system better integrated, the outside origin still shows through.
However, I found on this project that XGen Geometry Instancer is nonetheless still super powerful and for huge numbers of instances is vastly more performant than the native Maya MASH instancing toolset.&lt;/p&gt;

  &lt;p&gt;The first vegetation test I did was to put down some basic grass, scattered using a super basic XGen Description setup where the base geometry used for scattering was just the groundplane itself.
The grass is made up of just a couple of off-the-shelf grass models from Evermotion and Megascans, reshaded for the project’s needs, exported as XGen archives and scattered with random rotations applied per instance:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/initial_grass.webp"&gt;&lt;img alt="Figure 4: Initial grass scattered using Maya's XGen Geometry Instancer toolset." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/initial_grass.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Next, I started blocking in trees since this scene was meant to be a forest scene.
Originally I had planned on scattering trees using XGen as well, but I wound up placing the trees by hand.
Part of the reason for placing by hand was simply that there aren’t &lt;em&gt;that&lt;/em&gt; many trees in this scene, but the primary reason was just for more direct control since the trees play a really large role in establishing the overall framing of the scene.&lt;/p&gt;

  &lt;p&gt;The base spruce tree models I used are from Evermotion, but I opted to reshade them using the Evermotion textures as a starting point but then improved using some stuff from Megascans.
The main reason for reshading was to improve how well the trees would hold up to being close to the camera, which requires more detailed displacement on the tree bark.
I also put some work into making sure the spruce needles transmit light in a convincing way, which required some initial reverse-engineering of how the tree’s original Vray materials work in order to understand how to get a similar effect in RenderMan’s PxrSurface material, and then required further tweaking and adjustment to both the spruce needle textures and the material.&lt;/p&gt;

  &lt;p&gt;Here are a couple of lookdev test renders of one of the spruce trees; the first two show the overall look of the trees with my reworked shading, and the last one shows the close-up detail and also how the spruce needles look with backlighting:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/tree.004.webp"&gt;&lt;img alt="Figure 5: Lookdev test render of a spruce tree, upper half." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/tree.004.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/tree.005.webp"&gt;&lt;img alt="Figure 6: Lookdev test render of a spruce tree, lower half." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/tree.005.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/tree.006.webp"&gt;&lt;img alt="Figure 7: Closeup lookdev test render of a spruce tree, focsing on bark displacement detail and backlighting through the needles." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/tree.006.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;One interesting thing I ran into was RenderMan’s &lt;a href="https://rmanwiki-23.pixar.com/space/REN23/19038275/Presence+and+Opacity#Cached-versus-Uncached"&gt;opacity caching system&lt;/a&gt;.
The opacity caching system stores an opacity value per micropolygon, under the assumption that micropolygon sizes in world space should be close to one micropolygon per screen-space pixel.
As long as the one-micropolygon-per-screen-pixel assumption holds more or less true, this opacity caching approach works well; the average opacity value across a single screen-pixel sized micropolygon should match what the filtered mip-mapped texture lookup for opacity should be across the micropolygon, therefore, caching this value on the micropolygon allows for skipping a lot of texture lookups over the course of the render.
However, as soon as micropolygons are larger than a single screen-pixel, the assumptions that allow for opacity caching to work without visual artifacts break, because the frequency that opacity caching can store values at drops below the frequency that the filtered mip-mapped signal from texturing represents; the net visual result is blurring in opacity edges, which can look super strange.&lt;/p&gt;

  &lt;p&gt;PxrSurface in RenderMan for Maya enables opacity caching by default, but for the spruce needles on the trees, I had to disable opacity caching.
The spruce needles on the trees are modeled as a single quad strip per bundle of needles with opacity mapping; I left the quad strips unsubdivided to keep memory usage lower, but this meant that spruce needle polygon sizes were often way larger than one pixel in screen space for trees closer to the camera.
Before doing this project I didn’t realize that RenderMan has an opacity caching system and enables it by default, so figuring out why the spruce needles looked all messed up took me a moment.
This wasn’t a problem in the Woodville project because in that scene, all of the trees are in the background and therefore are so far from camera that all unsubdivided quad strips are subpixel in screen space anyway.&lt;/p&gt;

  &lt;p&gt;Here are the spruce trees blocked out along with the initial grass and rock formations.
While nothing here is as close to the camera as in my lookdev tests, nonetheless the nearest foreground trees are close enough to the camera where the reworked high resolution displacement mapping and exact opacity evaluation on the spruce needles instead of cached opacity start to matter a great deal:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/initial_trees.webp"&gt;&lt;img alt="Figure 8: Initial blocking for where the spruce trees should go, along with initial grass and rock formations." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/initial_trees.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-12-28-forest-floor"&gt;&lt;/div&gt;
  &lt;h2 id="forest-floor"&gt;Forest Floor&lt;/h2&gt;

  &lt;p&gt;At this stage, with conifer trees and large rock formations, the scene was starting to remind me of trips to Yosemite (even though technically Yosemite’s conifers include pine, fir, and sequoia but notably &lt;em&gt;not&lt;/em&gt; spruce).
I’ve seen lupine blooms in Yosemite before, which struck me as really visually interesting since large fields of blue-purple flowers feel somewhat unusual and unexpected normally.
So, to make the foreground in this scene more interesting than just a grassy plane, I added in a couple of layers of lupine flowers to make a purple lupine meadow.
The lupine flowers are placed as a couple of different overlapping XGen descriptions, with varying clustering rules per description.
I also carved a footpath through the grass and flowers by painting a simple density mask.&lt;/p&gt;

  &lt;p&gt;I also realized here that the overall massing of the scene was all vertical but in a horizontal framing, which was starting to make the scene feel claustrophobic to me.
Having the rock formations be completely vertical also didn’t make sense to me for how they probably would have been formed in real life; a completely vertical cut through rock cliffs like that feels like it would have had to been man-made.
So, I tried sloping the rock formations back to give more of an impression of a small valley or something that could have been carved glacially or by water erosion or something.
Sloping the rock formations back also helped bring some more light into the foreground of the scene.
Here is a comparison of what the scene looked like at this point with vertical rock formations versus sloped rock formations:&lt;/p&gt;

&lt;/div&gt;

&lt;div class="embed-container" id="cliffs_compare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 9: Blocking in lupine flowers and carving out a footpath through the grass and flowers, with vertical rock formations (left) versus sloping rock formations (right). For a full screen comparison, &lt;a href="/content/images/2020/Dec/lupineforestcabin/comparisons/cliffs_compare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;

&lt;div&gt;

    &lt;p&gt;One nice thing about XGen Geometry Instancing is that it treats driving properties through painted masks as a first-class citizen, as opposed to the MASH toolset where using textures as masks is a lot more annoying than I feel like it should be.
In my experience, MASH encourages procedural placement or hand placement using the MASH Placer tool over using painted masks to drive everything; using a painted mask only really works well with MASH’s World node, but the World node in turn doesn’t always play well with everything else in MASH’s toolkit; in this sense I really prefer how easy using painted masks is in XGen.
However, in XGen, painted masks also come with a minor complication- one Disney-ism that remains in XGen to this day is that XGen expects painted masks to all be Ptex files, which means the masks either have to be made using a paint tool that natively supports Ptex, or means that masks created as regular UV textures need to be converted to Ptex.
Within Disney Animation, which has a native Ptex workflow, this is not a problem at all, but in a vanilla Maya workflow in the outside world, this Ptex dependency adds some friction and an additional layer of file juggling to the XGen workflow if one is more used to a UV-based painting workflow.&lt;/p&gt;

    &lt;p&gt;Here is what the painted density mask for the footpath looks like in Maya’s viewport.
Since leaving this mask pretty coarse was fine for the use case, I just painted it directly in Maya using the built-in simple surface paint tool:&lt;/p&gt;

    &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/viewport_lupinusmask.webp"&gt;&lt;img alt="Figure 10: Density mask driving the footpath through the lupine flowers and grass." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/viewport_lupinusmask.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Having just the lupine flowers and base grass looked kind of monotonous, so I also threw in some small shrubs here and there to help visually break up the fields of purple.
In the areas where the groundplane show through because of the footpath, I also added several more layered XGen descriptions to scatter various small bits of ground debris that I pulled from Megascans; the debris includes things you’d expect from a conifer forest, such as sticks and twigs and clusters of dead conifer needles, in addition to some pebbles and small rocks and stuff.&lt;/p&gt;

    &lt;p&gt;With all of the debris on the groundplane, even as instanced geometry, the scene was starting to get really heavy to render, so as a small optimization I took the density mask for the footpath through the lupine flowers and grass and simply inverted it and applied it to the debris XGen descriptions.
This way, there’s only debris where it’ll actually be visible.
Putting all of this together got the scene to a point where I think the groundplane was looking pretty good:&lt;/p&gt;

    &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/progress.062.webp"&gt;&lt;img alt="Figure 11: Groundplane with shrubs added in and twigs and leaf debris scattered over the footpath." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/progress.062.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Here’s a top-down view of what all of the footpath debris looks like in the final version of the scene (I’ll get to the moss and volumes next).
The nice thing about using instanced geometry instead of just adding decals to the groundplane texturing, or even adding displacement, is that the instanced geometry provides much more of a feeling of depth, especially in all of the areas where cavities and holes are visible under piles of dried needles:&lt;/p&gt;

    &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_overcam.webp"&gt;&lt;img alt="Figure 12: Top-down detail view of the footpath debris, from the final version of the scene with mossy, volumes, etc." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_overcam.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;div id="2020-12-28-making-moss"&gt;&lt;/div&gt;
    &lt;h2 id="making-moss"&gt;Making Moss&lt;/h2&gt;

    &lt;p&gt;In order to add a bit more detail to the scene, I wanted to add moss to some of the tree trunks and rock formations and stuff.
On the Woodville piece, the vast majority of the mossy surfaces in the scene are made using a purely textured approach, with only a small amount of geometric moss in specific places.
For this scene, I wanted to move to a 100% geometry based moss approach.
Geometry based moss simply holds up better close to camera, and even far away from camera, geometric moss with proper transluscency allows for much more realistic lighting responses completely automatically.&lt;/p&gt;

    &lt;p&gt;I made the pieces of moss by just grabbing a bunch of Megascans atlases of moss bits and cutting out each piece from each atlas as its own little card.
The cards aren’t simple rectangles; each card is shaped to cut as closely to the actual moss shape as possible while still maintaining a very low triangle count.
Using simple rectangular cards means that the vast majority of each card is actually going to be opacity mapped out, and in most raytraced renderers (including RenderMan), somewhat counter-intuitively we’d rather have a few more triangles to deal with in exchange for cutting down opacity map lookups.
The reason is because triangle intersection using a BVH acceleration structure means that the runtime cost of intersecting N triangles is typically less than N times the cost of a single triangle, but having to either interrupt BVH traversal to evaluate an opacity map in-line or having to evaluate opacity as part of shading and then generate continuation rays for hits shading points where opacity is less than 1 is really expensive in the aggregate.
Here’s what some of the moss cards looked like:&lt;/p&gt;

    &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/moss_cards.webp"&gt;&lt;img alt="Figure 13: Some of the moss cards; note that each card's shape tries to minimize the amount of opacity map lookups required. Black indicates areas that are completely transparent to the renderer." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/moss_cards.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;At rendertime each moss card is actually subdivided and displacement mapped as well, so the total number of triangles per moss card actually can end up being relatively high, allowing for more detail.
This card-based technique produced several dozen unique pieces of moss, which when combined with some random hue shifts in the material and some flipping and scaling was more than enough to create the impression of tons of unique moss bits when instanced and scattered.&lt;/p&gt;

    &lt;p&gt;To get an initial sense of how well this approach would work, I did a small-scale test on a single rock before expanding to the whole scene, using a simplified version of the rock for the underlying geometry to grow the XGen descriptions from and using a simple density mask painted directly in Maya:&lt;/p&gt;

    &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/moss_test.001.webp"&gt;&lt;img alt="Figure 14: Initial small-scale moss test on a rock." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/moss_test.001.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;One small problem with using XGen Geometry Instancer with Megascans assets is that XGen can be somewhat difficult to use with super high-resolution meshes.
The reason high-resolution meshes get tricky to use with XGen comes back to XGen needing to bind a patch to every face in the mesh; with a really high-resolution mesh, this can result in a ton of patches, and since Maya and XGen are not particularly well multithreaded in some operations, have a ton of patches in XGen can result in really slow update times as Maya loops over and updates all patches.
XGen in Maya does have a multithreading option, but I found that even with this option enabled, really high-resolution meshes still bogged down instance generation a lot.
So, my workaround was to take all of the meshes that I wanted to grow moss on and create highly decimated versions to serve as base geometry for XGen.&lt;/p&gt;

    &lt;p&gt;Below is a comparison of what the full-resolution geometry that I wanted moss on looks like in the viewport, versus the decimated version of that geometry for XGen.
Note that the decimated XGen base geometry obviously isn’t visible in the final render; XGen allows for seprarately hiding the underlying base geometry versus hiding the generated instances.&lt;/p&gt;

  &lt;/div&gt;

&lt;div class="embed-container" id="supportgeo_compare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 15: Full-resolution geometry that I wanted moss on (left) versus the decimated version used as base geometry for XGen Geometry Instancer (right). For a full screen comparison, &lt;a href="/content/images/2020/Dec/lupineforestcabin/comparisons/supportgeo_compare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;

&lt;div&gt;

      &lt;p&gt;For the moss density masks, I reached for Substance Painter instead of just painting in Maya using the basic built-in paint toolset.
Painting the masks in Substance Painter made getting in nice bits of detail and complexity much easier.
In order to make the Substance Painter workflow slightly easier, I also re-UV’d the decimated meshes to try to reduce the number of different UV islands; this step was much easier to do on low-resolution decimated meshes than it would have been on the full-resolution geometry!&lt;/p&gt;

      &lt;p&gt;Here’s what the painted masks for the “hero” foreground tree trunks look like in Substance Painter:&lt;/p&gt;

      &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/substance_tree_mossmask.webp"&gt;&lt;img alt="Figure 16: Foreground tree trunk moss density masks in Substance Painted." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/substance_tree_mossmask.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

      &lt;p&gt;In order to use UV textures as masks in XGen, the textures have to be converted to Ptex.
Maya’s paint tool actually has functionality for this; when using the paint tool, there’s an option to save and load from UV textures, which XGen then converts to Ptex upon hitting the map save button in the XGen UI.&lt;/p&gt;

      &lt;p&gt;I also used Substance Painter to paint the moss density masks for all of the rock formations and cliff walls.
The viewport screenshot shows that the final resolution of the density masks actually isn’t that high, but in this case that wound up being completely okay:&lt;/p&gt;

      &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/viewport_mossmask.webp"&gt;&lt;img alt="Figure 17: All moss density masks on trees and rock formations." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/viewport_mossmask.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

      &lt;p&gt;One downside of using low-resolution decimated geometry as the base to grow XGen instances from while keeping high-resolution geometry for rendering is that there can be mismatches between where XGen instances are and where the high-resolution surface is; this mismatch means instances can either float in space or be embedded too far down in the high-resolution surface.
XGen Geometry Instancer allows for specifying a displacement map on the base geometry to help correct for this, but in this case I found that the mismatch didn’t really matter.
To address floating geometry I just applied a universal offset back along the surface normal, and for something like moss, pieces being embedded too far down in the high-resolution surface just look like shorter pieces of moss.&lt;/p&gt;

      &lt;p&gt;Here is a test render of what the moss looks like on just the smaller foreground rocks, which I did to confirm that at least for this use case, mismatches between the low-resolution surface used for XGen and the high-resolution render surface weren’t important:&lt;/p&gt;

      &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/progress.070.webp"&gt;&lt;img alt="Figure 18: Isolated test render of XGen moss on the foreground rocks." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/progress.070.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

      &lt;p&gt;Rendering everything together at this point produced the following image; things were starting to look pretty good at this point!
I think the moss really helps with adding in a ton of additional detail, which in turn makes the whole scene look and feel more believable.
In retrospect I suppose I should have adjust the moss so that it only grows in areas that stay in the shade longer, but even without taking that additional real-world factor into account, I think the moss looks pretty convincing:&lt;/p&gt;

      &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/progress.090.webp"&gt;&lt;img alt="Figure 19: Scene rendered with all XGen instanced geometry, including debris, flowers, grass, and moss." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/progress.090.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

      &lt;p&gt;This scene really shows the importance of having a robust instancing system in a production renderer- with all of the XGen instances added in, the scene at this stage took up about 50GB of memory in RenderMan for geometry alone, but 50GB is actually not too bad when considering that the total number of visible triangles is around a billion.
According to RenderMan’s stats breakdown, of that 50GB of geometry memory, around 33GB is used just for storing instancing information!
Most of the triangles just belong to instanced geometry, which is crucial to keeping geometry memory under control.&lt;/p&gt;

      &lt;p&gt;I ran some analytics to count up the total number of XGen instances (debris, grass, lupine flowers, and moss) in this scene; the total tally is 11,433,11.
Here’s a comparison of what the final viewport looks like with only non-instanced geometry, and with every single XGen instance drawn as a blue bounding box on top:&lt;/p&gt;

    &lt;/div&gt;

&lt;div class="embed-container" id="viewport_compare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 20: Final viewport with only non-instanced geometry (left) and with every single XGen instance drawn as a blue bounding box on top (right). For a full screen comparison, &lt;a href="/content/images/2020/Dec/lupineforestcabin/comparisons/viewport_compare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;

&lt;div&gt;

        &lt;p&gt;The original stated goal of this project was to learn to create forest detail that could hold up well when viewed close up, but admittedly the closest tree in the final composition for this project is only in the mid-ground at best.
I wanted to see how ell the moss would hold up when viewed closer, so after I finished the rest of the project, I set up an alternate camera much closer up to one of the trees.
Here’s what the final version of the scene looks like with the alternate close-up camera.
It’s far from perfect; in order to really look convincing this close up, I think the moss actually needs to be even smaller and even denser, but at least at a glance I think it does an okay job of holding up:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/moss_closeup.webp"&gt;&lt;img alt="Figure 21: Alternate close-up view of one of the mossy tree trunks, from the final version of the scene." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/moss_closeup.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;div id="2020-12-28-filling-out-the-clearing"&gt;&lt;/div&gt;
        &lt;h2 id="filling-out-the-clearing"&gt;Filling out the Clearing&lt;/h2&gt;

        &lt;p&gt;To finish building the scene, I wanted to put something in the clearing that the footpath leads to.
Because I started this project with no real plan whatsoever, I was a bit stumped at this point what to put in the clearing!
One initial idea I played with was throwing in a hot air balloon- I figured that a hot air balloon could provide a visually interesting splash of color into the background.
I actually fully carried out this idea, including adding in some emissive volume flames for the hot air balloon’s burners.
I also filled out the background with some more trees:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/balloon.webp"&gt;&lt;img alt="Figure 22: Initial version of the scene including a hot air balloon in the clearing, also with a slighty lower camera angle." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/balloon.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;While I think the hot air balloon concept wasn’t the worse idea, I decided against it after seeing the hot air balloon fully in-context with the rest of the scene.
Visually the balloon stood out, but I felt that it stood out &lt;em&gt;too&lt;/em&gt; much and distracted from the overall composition.
Also, in terms of the internal logic of the scene’s world-building, I thought that the balloon didn’t make a whole lot of sense- the clearing is pretty small, which when combined with all of the surrounding tall trees, makes for a hazardous landing site for a hot air balloon!
I moved on to trying to find something more appropriate to the scene both visually and logically.
I did keep the additional trees though.&lt;/p&gt;

        &lt;p&gt;Since the scene’s original layout principle of “compression and release” comes from the architecture world, I figured it would be fun to turn this scene into a bit of an architectural scene (which tend to be my favorite type of scene to make anyway).
Evermotion &lt;a href="https://evermotion.org/articles/show/11911/15th-anniversary-of-evermotion-"&gt;released a wonderful 15th Anniversary scene&lt;/a&gt; earlier this year that includes two small cabins; I thought that something along the lines of those cabins would fit the bill well for the clearing in my scene.
I was looking for something that would be small and relatively unassuming, but also still be visually interesting; I didn’t really have any preference for what the style of the building would be, but something super modern felt like a nice change of pace after working on the Woodville project.
I didn’t want to just grab one of the Evermotion 15th Anniversary cabins and drop it into the scene as-is though.
To keep things more visually interesting, I wanted to be able to see into the cabin more than is possible in the vanilla Evermotion 15th Anniversary cabins, and I also wanted the cabin to look cozy and inviting on the inside.
To build the cabin for this scene, I kitbashed together parts from the two Evermotion 15th Anniversary cabins and made the front of my cabin one gigantic glass sheet:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/house.004.webp"&gt;&lt;img alt="Figure 23: Cabin for this peice, built by kitbashing together parts from the Evermotion 15th Anniversary scene." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/house.004.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;To give the giant front window a bit more realism, I added a subtle amount of unevenness and wobbliness to the glass sheet, much like how giant glass sheets on skyscrapers often have small amounts of visible unevenness.
In the following test render, note the back window behind the staircase; the wobbliness of the front glass is most noticeable by the effect it has on how the back window’s straight frame looks:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/house.005.webp"&gt;&lt;img alt="Figure 24: Front view of the cabin. Note how the wobbliness of the front window glass slightly distorts some of the cabin interior's appearance." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/house.005.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;To integrate the cabin in the scene,  I expanded the footpath further to reach the cabin and expand out into a small sort of pad surrounding the cabin.
One major mistake I made in putting together this scene though was that I didn’t keep track of the scale of anything, so finding the appropriate scale for the cabin to sit well in the scene took a few tries; for future projects I’ll have to keep track of everything’s scale more closely.&lt;/p&gt;

        &lt;p&gt;Overall I think compared with the hot air balloon idea, the cabin does a much better job of integrating into the scene without overly drawing attention to itself while still being visually interesting:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/progress.139.day.webp"&gt;&lt;img alt="Figure 25: Full scene with cabin integrated in, and also with final camera angle." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/progress.139.day.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Much like in the &lt;a href="https://blog.yiningkarlli.com/2020/07/shipshape-renderman-challenge.html"&gt;Shipshape Art Challenge project&lt;/a&gt;, I used PxrSurface exclusively as the shading model for everything in this project.
However, for the cabin, using PxrSurface became kind of cumbersome because the shader parameterization that Evermotion assets come with doesn’t match up directly with PxrSurface’s parameterization.
Specifically, Evermotion assets typically come with Vray, Corona, or generic “PBR” materials.
Corona and generic “PBR” materials are the easiest to adapt to other renderers because they both follow the roughness/metallic/basecolor workflow that was originally introduced by the Disney BRDF &lt;a href="https://doi.org/10.1145/2343483.2343493"&gt;[Burley 2012]&lt;/a&gt; and has since become the de-facto norm across many popular and widely-used physically based shading systems &lt;a href="https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf"&gt;[Karis 2013&lt;/a&gt;, &lt;a href="https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf"&gt;Kulla and Estevez 2017&lt;/a&gt;, &lt;a href="https://autodesk.github.io/standard-surface/"&gt;Georgiev et al. 2019&lt;/a&gt;, &lt;a href="https://dassaultsystemes-technology.github.io/EnterprisePBRShadingModel/"&gt;Häussler et al. 2020&lt;/a&gt;, &lt;a href="https://substance3d.adobe.com/documentation/s3d/asm-specifications-225969597.html"&gt;Noguer et al. 2021&lt;/a&gt;, &lt;a href="https://conference.blender.org/2022/presentations/1407/"&gt;Stockner 2022&lt;/a&gt;, &lt;a href="https://academysoftwarefoundation.github.io/OpenPBR/"&gt;Andersson et al. 2024]&lt;/a&gt;&lt;sup id="2020-12-28-footnote-1-backlink"&gt;&lt;a href="#2020-12-28-footnote-1"&gt;1&lt;/a&gt;&lt;/sup&gt;.
PxrSurface, however, notably does not follow the roughness/metallic/basecolor parameterization &lt;a href="http://graphics.pixar.com/library/PxrMaterialsCourse2017/index.html"&gt;[Hery et al. 2017]&lt;/a&gt;; roughness is the same in PxrSurface as in pretty much every other modern physical shading model, but instead of metallic, PxrSurface uses a combination of face color, edge color, and fresnel exponent to control how metallic a material looks.
In order to convert metallic/basecolor maps into something PxrSurface could use, the approach I took was:&lt;/p&gt;

        &lt;div&gt;\[diffuseColor_{PxrSurface} = baseColor_{PBR} * (1-metallic_{PBR}) \]&lt;/div&gt;

        &lt;div&gt;\[specFaceColor_{PxrSurface} = baseColor_{PBR} * metallic_{PBR} \]&lt;/div&gt;

        &lt;div&gt;\[specEdgeColor_{PxrSurface} = 1 \]&lt;/div&gt;

        &lt;p&gt;When creating textures from scratch using Substance Painter, as I did for the Shipshape project, PxrSurface’s parameterization isn’t an issue because Substance Painter has built in export templates to save out textures in PxrSurface’s expected parameterization even though Substance Painter uses a standard metallic/basecolor workflow.
When bringing in existing metallic/basecolor textures though, the above conversion has to be done within the material’s node network.
I had to wire up a small node subnetwork to do this for every single Evermotion material that had metallic, which got really old really quickly.
At least as of RenderMan 23 (the current version while I was working on this project), RenderMan doesn’t have any utility node to do this conversion from metallic/basecolor to PxrSurface’s diffuse/specular face/specular edge color paramterization&lt;sup id="2020-12-28-footnote-2-backlink"&gt;&lt;a href="#2020-12-28-footnote-2"&gt;2&lt;/a&gt;&lt;/sup&gt;; such a node would be really helpful!
Alternatively, a full implementation of the Disney BSDF &lt;a href="https://doi.org/10.1145/2776880.2787670"&gt;[Burley 2015]&lt;/a&gt; (as opposed to the reduced-paramter Disney BRDF that is already available) would be useful too since a full implementation of the Disney BSDF would both be able to accept roughness/metallic/basecolor parameterized inputs and provide the full range of abilities that a production-quality shading model needs.&lt;/p&gt;

        &lt;div id="2020-12-28-mist-and-atmospherics"&gt;&lt;/div&gt;
        &lt;h2 id="mist-and-atmospherics"&gt;Mist and Atmospherics&lt;/h2&gt;

        &lt;p&gt;With the surface geometry and shading for the scene complete, the last things to do were atmospherics and final lighting.
Over the last two RenderMan Art Challenges, I’ve evolved my atmospherics and volume rendering workflow a lot.
For the Woodville Art Challenge, I relied on a combination of homogeneous mist and heterogeneous fog made procedurally using Maya’s volume noise nodes plugged into the density field of a PxrVolume.
This workflow was simple, but ultimately challenging to control and slow to iterate on since seeing what anything looked like required doing a full render.
For the Shipshape Art Challenge, I moved to an entirely VDB-based volumes workflow, even for mist and stuff.
Using an entirely VDB-based workflow allowed for more direct control, and because RenderMan for Maya can preview VDBs in Maya’s viewport, I was able to get a good sense of how volumes were placed and how they massed together in the scene without having to wait for full renders.&lt;/p&gt;

        &lt;p&gt;For this project, the volumes workflow was similar to the one on the Shipshape Art Challenge; everything is VDB-based, even the background haze.
In making the mist and atmospherics in this scene, I knew I wanted to break things down into three distinct types of volumes: background haze, foreground godrays and atmospherics, and some mist low down clinging to the ground.
I broke out and rendered these three types of volumes in their own passes/layers to give more control during compositing.&lt;/p&gt;

        &lt;p&gt;Here is the background haze layer, which is mostly uniform but does have a small amount of variation that creates a bit of a cascading effect:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/volumes_backmist.webp"&gt;&lt;img alt="Figure 26: Background haze volumetrics layer." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/volumes_backmist.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;For the main foreground godrays and atmospherics layer, I use similar types of volumes as in the background haze layer, but with a different lighting scheme.
The main lighting setup for the entire scene is basically just a single super high-resolution skydome IBL with a sun baked in.
However, I wanted the godrays to be more prominent than could be achieved by just using the skydome IBL as-is.
For for this layer, I created a separate distant light with an orientation matched to the IBL’s sun position, cranked up the exposure of the distant light, and twiddled with the size (angle) of the distant light until the godrays became more visually prominent:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/volumes_foregroundfog.webp"&gt;&lt;img alt="Figure 27: Foreground godrays and atmospherics layer." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/volumes_foregroundfog.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The low ground-hugging mist is made up of VDBs with higher-frequency detail than the previous two layers. There are only a handful of unique VDBs here, but I instanced them around a bunch using native Maya instancing to cover the entire valley floor.
I really like how the low mist settles down in between the lupine flowers and floods the footpath area:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/volumes_foregroundmist.webp"&gt;&lt;img alt="Figure 28: Low ground-hugging mist layer." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/volumes_foregroundmist.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;Finally, here’s what the three volumetrics layers look like stacked together, with the per-layer adjustments used in the final composite.
One thing that I think is kind of neat about looking at the composited volumes together is that we can actually clearly see the shadow cast by the cabin; this detail isn’t actually necessarily clear in any of the volumes layers in isolation, but becomes apparently obvious once all three are stacked since each layer brings something different into the whole:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/volumes_all.webp"&gt;&lt;img alt="Figure 29: All volumetrics layers stacked together with per-layer adjustments used in the final composite." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/volumes_all.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The clouds in the background in the final render are just part of the skydome IBL; in the future I’m hoping to build background cloudscapes from scratch, but that’ll have to be for a future art exercise.&lt;/p&gt;

        &lt;div id="2020-12-28-final-lighting"&gt;&lt;/div&gt;
        &lt;h2 id="final-lighting"&gt;Final Lighting&lt;/h2&gt;

        &lt;p&gt;The final lighting setup for this scene was super simple; effectively the whole scene is lit by just a simple sun + skydome IBL setup.
My goal was to keep the lighting as naturalistic as possible, so a simple sun + sky setup fit the bill, and even with the simple setup, the complexity of the forest geometry still provided a lot of interesting areas of highlight and shadow.
For final lighting I did split out the sun as a distant light from the skydome IBL, much like what I did for the volumetrics passes, and I painted out the baked-in sun in the skydome IBL. 
The reason for splitting out the sun in this case wasn’t to adjust its brightness independently from the sky though, but instead was to allow for slightly adjusting the color temperature of the sun without affecting the fill provided by the sky.
The sun is just a touch warmer in the final lighting than it was in all of the in-progress renders up to this point.&lt;/p&gt;

        &lt;p&gt;There are a bunch of practical lights in the cabin as well; the interior of the cabin is actually lit only using the practical lights and contains no other stage lighting.
I initially calibrated all of the practical lights against the sun’s brightness, but that wound up making the interior of the cabin a bit too dark to be visible in a bright sunny day, so I cheated and applied a uniform exposure boost to all of the cabin’s practical lights to brighten up the inside of the cabin.&lt;/p&gt;

        &lt;p&gt;Putting everything together with the volumetrics produced the following main daylight version of the scene.
I also did a small amount of color correction in Lightroom, but in this case the color correction was limited to some basic contrast and saturation adjustments.
The color correction for this piece wasn’t nearly as extensive as what I did for the Woodville and Shipshape projects.
Here is the final piece, followed by a 50% grey clay shaded version with the same final lighting, comp, and color correction:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_day.webp"&gt;&lt;img alt="Figure 30: Final piece, main daylight variant. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_day.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_day_clay.webp"&gt;&lt;img alt="Figure 31: Final lighting, comp, and color grading applied to a 50% grey clay shaded version. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_day_clay.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;I had some fun with making some alternate time-of-day versions of the final lighting setup.
These were quick and just for fun, so the sun angle is the same as in the daylight version even though in reality that would make zero sense.
I kept the sun angle the same in the variants since they use the same volumetrics passes, just color corrected differently.
These variants were made quickly on a whim, which is why I didn’t put in the additional effort to redo everything to work with more plausible sun angles.&lt;/p&gt;

        &lt;p&gt;Here’s a late afternoon golden hour variant, followed by a 50% grey clay shaded version.
A lot more of the look of this variant was achieved by extensive color correction in Lightroom.
I think this variant shows off the godray volumetrics better than the main daylight variant, even if the angle of the godrays and by extension the angle of the sun don’t make much sense for golden hour:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_warm.webp"&gt;&lt;img alt="Figure 32: Final piece, alternate afternoon golden hour variant. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_warm.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_warm_clay.webp"&gt;&lt;img alt="Figure 33: Alternate afternoon golden hour lighting, comp, and color grading applied to a 50% grey clay shaded version. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_warm_clay.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;The other variant I played with is a cooler overcast morning.
A lot of the look of this variant also comes from Lightroom, possibly even more so that for the golden hour variant.
I also boosted the contribution of the low ground-hugging mist in this variant to make it more visible, since low mist is typically characterstic of overcast mornings.
I left the godrays in, even though having godrays at all on an overcast morning is fairly implausible; again, these two variants were quick and just for fun.&lt;/p&gt;

        &lt;p&gt;Here’s the overcast morning variant, followed by a 50% grey clay shaded version:&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_cool.webp"&gt;&lt;img alt="Figure 34: Final piece, alternate overcast morning variant. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_cool.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/final_cool_clay.webp"&gt;&lt;img alt="Figure 35: Alternate morning overcast lighting, comp, and color grading applied to a 50% grey clay shaded version. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Dec/lupineforestcabin/preview/final_cool_clay.webp" /&gt;&lt;/a&gt;&lt;/p&gt;

        &lt;div id="2020-12-28-conclusion"&gt;&lt;/div&gt;
        &lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

        &lt;p&gt;I learned a lot from this project; the goal of the project was to figure out how to put together a detailed forest environment that holds up well at relatively close camera distances, and I think the end result accomplishes that well enough.
The final image in this project is decent- it’s not the most narratively interesting image, but it makes for a passable archviz type piece, but to be honest a nice looking image was somewhat secondary to the goal of figuring out how to build a scene like this.
Maya’s version of the XGen toolset makes building this type of scene relatively easy and the XGen toolset is super powerful, even if it doesn’t feel particularly native to the rest of Maya.
XGen certainly feels a lot more scalable for this type of project than MASH, which I’ve run into performance problems with on scenes much smaller than this one.
At the same time though, in my opinion, Maya’s version of XGen isn’t nearly as easy to use and isn’t nearly as featureful as tools like &lt;a href="https://www.itoosoft.com/forestpack"&gt;ForestPack for 3ds Max&lt;/a&gt;, which remains the gold standard for instancing/scatter tools, or the &lt;a href="https://www.geoscatter.com"&gt;Geo-Scatter plugin for Blender&lt;/a&gt;, or Houdini’s native toolset.&lt;/p&gt;

        &lt;p&gt;At the end of the (metaphorical) day, I had a lot of fun making this piece!
The process was much more experimental and aimless compared with working on RenderMan Art Challenge pieces, which was a nice change of pace for an art project.
I learned a bunch of techniques that I’m sure I’ll make use of again in the future, and I got in more practice, which is ultimately the most important part of getting better at anything.
I’m really happy that I’ve more or less figured out a reliable way of making good trees now, given &lt;a href="https://blog.yiningkarlli.com/2011/03/autumn-tree.html"&gt;how much time&lt;/a&gt; &lt;a href="https://blog.yiningkarlli.com/2011/03/vray-tree.html"&gt;I spent a long time ago&lt;/a&gt; &lt;a href="https://blog.yiningkarlli.com/2012/08/more-experiments-with-trees.html"&gt;trying to figure out&lt;/a&gt; &lt;a href="https://blog.yiningkarlli.com/2013/11/throwback-holiday-card-2011.html"&gt;how to make decent trees&lt;/a&gt;.&lt;/p&gt;

        &lt;p&gt;Finally, here is a progression video I put together from all of the test and in-progress renders that I made throughout this entire project:&lt;/p&gt;

        &lt;div class="embed-container"&gt;Lupine Forest Cabin Progression Reel&lt;/div&gt;
        &lt;div class="figcaption"&gt;&lt;span&gt;Figure 36: Progression reel made from test and in-progress renders leading up to my final image.&lt;/span&gt;&lt;/div&gt;

        &lt;div id="2020-12-28-references"&gt;&lt;/div&gt;
        &lt;h2 id="references"&gt;References&lt;/h2&gt;

        &lt;p&gt;Zap Andersson, Paul Edmondson, Julien Guertault, Adrien Herubel, Alan King, Peter Kutz, Andréa Machizaud, Jamie Portsmouth, Frédéric Servant, and Jonathan Stone. 2024. &lt;a href="https://academysoftwarefoundation.github.io/OpenPBR/"&gt;OpenPBR Surface Specification&lt;/a&gt;. &lt;em&gt;Academy Software Foundation white paper&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Autodesk. 2020. &lt;a href="https://help.autodesk.com/view/MAYAUL/2020/ENU/?guid=GUID-C6324505-BD4F-4FD2-B340-CF99158D4819"&gt;XGen Geometry Instancer&lt;/a&gt;. &lt;em&gt;Autodesk Maya 2020 User Documentation&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Autodesk. 2020. &lt;a href="https://help.autodesk.com/view/MAYAUL/2020/ENU/?guid=GUID-496603B0-F929-45CD-B607-1CFCD3283DBE"&gt;XGen Interactive Grooming&lt;/a&gt;. &lt;em&gt;Autodesk Maya 2020 User Documentation&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Brent Burley and Dylan Lacewell. 2008. &lt;a href="https://doi.org/10.1111/j.1467-8659.2008.01253.x"&gt;Ptex: Per-face Texture Mapping for Production Rendering&lt;/a&gt;. &lt;em&gt;Computer Graphics Forum (Proc. of Eurographics Symposium on Rendering)&lt;/em&gt; 27, 4 (Jun. 2008), 1155-1164.&lt;/p&gt;

        &lt;p&gt;Brent Burley. 2012. &lt;a href="https://doi.org/10.1145/2343483.2343493"&gt;Physically Based Shading at Disney&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2012-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2012 Course Notes: Practical Physically-Based Shading in Film and Game Production&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

        &lt;p&gt;Brent Burley. 2015. &lt;a href="https://doi.org/10.1145/2776880.2787670"&gt;Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2015-shading-course"&gt;&lt;em&gt;ACM SIGGRAPH 2015 Course Notes: Physically Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

        &lt;p&gt;Brent Burley. 2019. &lt;a href="https://www.jcgt.org/published/0008/04/02/"&gt;On Histogram-Preserving Blending for Randomized Texture Tiling&lt;/a&gt;. &lt;em&gt;Journal of Computer Graphics Techniques&lt;/em&gt; 8, 4 (Nov. 2019), 31-53.&lt;/p&gt;

        &lt;p&gt;Iliyan Georgiev, Jamie Portsmouth, Zap Andersson, Adrien Herubel, Alan King, Shinji Ogaki, Frederic Servant. 2019. &lt;a href="https://autodesk.github.io/standard-surface/"&gt;Autodesk Standard Surface&lt;/a&gt;. &lt;em&gt;Autodesk white paper&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Tobias Häussler, Holger Dammertz, and Bastian Sdorra. 2020. &lt;a href="https://dassaultsystemes-technology.github.io/EnterprisePBRShadingModel/"&gt;Enterprise PBR Shading Model&lt;/a&gt;. &lt;em&gt;Dassault Systèmes white paper&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Eric Heitz and Fabrice Neyret. 2018. &lt;a href="https://dl.acm.org/doi/10.1145/3233304"&gt;High-Performance By-Example Noise using a Histogram-Preserving Blending Operator&lt;/a&gt;. &lt;em&gt;Proceedings of the ACM on Computer Graphics and Interactive Techniques (Proc. of High Performance Graphics)&lt;/em&gt; 1, 2 (Aug. 2018), Article 31.&lt;/p&gt;

        &lt;p&gt;Christophe Hery, Ryusuke Villemin, and Junyi Ling. 2017. &lt;a href="http://graphics.pixar.com/library/PxrMaterialsCourse2017/index.html"&gt;Pixar’s Foundation for Materials: PxrSurface and PxrMarschnerHair&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2017-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2017 Course Notes: Physically Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

        &lt;p&gt;Brian Karis. 2013. &lt;a href="https://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf"&gt;Real Shading in Unreal Engine 4&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2013-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2013 Course Notes: Physically-Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

        &lt;p&gt;Christopher Kulla and Alejandro Conty Estevez. 2017. &lt;a href="https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf"&gt;Revisiting Physically Based Shading at Imageworks&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2017-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2017 Course Notes: Physically Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

        &lt;p&gt;Jeremie Noguer, Paul Edmondson, Michael Bond, and Peter Kutz. 2021. &lt;a href="https://substance3d.adobe.com/documentation/s3d/asm-specifications-225969597.html"&gt;Adobe Standard Material Specification&lt;/a&gt;. &lt;em&gt;Adobe white paper&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Lukas Stockner. 2022. &lt;a href="https://conference.blender.org/2022/presentations/1407/"&gt;The new Principled BSDF Model in Cycles&lt;/a&gt;. In &lt;a href="https://conference.blender.org/2022/"&gt;&lt;em&gt;BCON 2022: Blender Conference 2022&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

        &lt;p&gt;Thomas V. Thompson, Ernest J. Petti, and Chuck Tappan. 2003. &lt;a href="https://dl.acm.org/doi/10.1145/965400.965411"&gt;XGen: Arbitrary Primitive Generator&lt;/a&gt;. In &lt;em&gt;ACM SIGGRAPH 2003 Sketches &amp;amp; Applications&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Michael Todd. 2013. &lt;a href="https://www.mtodd.work/new-page-1"&gt;Interactive Grooming System: User Friendly Hair &amp;amp; Fur&lt;/a&gt;. &lt;em&gt;Michael Todd Portfolio&lt;/em&gt;.&lt;/p&gt;

        &lt;p&gt;Walt Disney Animation Studios. 2011. &lt;a href="https://wdas.github.io/SeExpr/"&gt;SeExpr&lt;/a&gt;.&lt;/p&gt;

        &lt;hr /&gt;

        &lt;div id="2020-12-28-footnotes"&gt;&lt;/div&gt;
        &lt;h2 id="footnotes"&gt;Footnotes&lt;/h2&gt;

        &lt;p&gt;&lt;sup id="2020-12-28-footnote-1"&gt;1&lt;/sup&gt; Additional post-2020 references added in update to post in May 2025.
&lt;a href="#2020-12-28-footnote-1-backlink"&gt;&lt;span class="material-symbols-outlined"&gt;keyboard_return&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;&lt;sup id="2020-12-28-footnote-2"&gt;2&lt;/sup&gt; As of RenderMan 24, released in 2021, RenderMan does now have a &lt;a href="https://rmanwiki-26.pixar.com/space/REN26/19661673/PxrMetallicWorkflow"&gt;PxrMetallicWorkflow node&lt;/a&gt; that converts metallic/basecolor inputs into the diffuse/specular face/specular edge color inputs that PxrSurface expects. RenderMan 24 also includes a &lt;a href="https://rmanwiki-24.pixar.com/space/REN24/21759038/PxrDisneyBsdf"&gt;new implementation of the full version of the Disney BSDF&lt;/a&gt;.
&lt;a href="#2020-12-28-footnote-2-backlink"&gt;&lt;span class="material-symbols-outlined"&gt;keyboard_return&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;

      &lt;/div&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;</description><author>Code &amp;amp; Visuals</author><pubDate>Mon, 28 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.yiningkarlli.com/2020/12/lupine-forest-cabin-art-project.html</guid></item><item><title>2020 Year in Review</title><link>https://benovermyer.com/blog/2020/12/2020-year-in-review/</link><description>&lt;p&gt;Last year I didn't write a retrospective. This year I felt it was necessary, given all that's happened.&lt;/p&gt;
&lt;p&gt;2020 has been a rough year. Covid-19, George Floyd's murder and the ensuing riots, and Donald Trump's increasingly bizarre behavior are all pretty well known and covered elsewhere. My sister lost three cats this year; two to old age and one small kitten to disease. My wife's grandfather passed away due to Covid.&lt;/p&gt;
&lt;p&gt;Going fully remote was relatively easy for my wife and me, as we both have professions that mesh well with it. In March just after the coronavirus lockdown began in the USA I changed clients. I have never seen anyone at my current client in person; we have only ever interacted in Teams and Zoom. Video chat is definitely preferable to voice-only, but we still need spatially-aware video chat before it can get close to replicating in-person interaction. Side conversations and awareness of eye contact are sorely lacking.&lt;/p&gt;
&lt;p&gt;My wife and I went on our first cruise together in late February and early March. This was right after the first cruise ship off East Asia got quarantined, but right before lockdown began. The ship was filled with hand sanitizer stations and we were required to wash our hands before entering the buffet restaurants, but everything was otherwise no different from normal operation. The daily email updates about the increasing number of ports that were off-limits due to Covid-19 were disconcerting, though. Thankfully, the cruise was in the Caribbean, so it was one of the last regions to be affected by Covid-19 directly, and our ship was never infected.&lt;/p&gt;
&lt;p&gt;Work has been good to me this year. At the end of last year, I won my employer's biggest award, the SDG Award. At the end of this year, I won it again. Throughout the year I got a few smaller awards too. That felt really good, and I've felt very appreciated at Solution Design Group. I joined the Employee Experience Committee and gave a presentation on roguelike development at last year's internal SDG Presents event. The Tabletop Games company community that I lead went quiet for the most part over 2020. I regret that a bit; the events we held for it last year were a lot of fun for everyone. In hindsight, running them virtually would have been a nice change of pace from all the negative events of the year.&lt;/p&gt;
&lt;p&gt;From a learning perspective, I dove deep into Chef this year. It went so well that not only do I no longer hate Chef, I've become an advocate for it in some scenarios. I also began studying Estonian history and the Estonian language. Estonia is a major focus in my personal life right now as we gear up to move there. Their history is fascinating and so much of it is unknown outside the Baltic region itself. I was blown away when I found out that Estonia is effectively the Silicon Valley of Europe, with services like Skype being born there. More on all of this will come in a future blog post.&lt;/p&gt;
&lt;p&gt;With dramatically reduced in-person social events this year, I needed to find new ways to interact with people. The Dungeons &amp;amp; Dragons campaign that I played in went virtual, and I stayed with it for several months, but ultimately it was too big for me to play in virtually. For technical reasons we ended up dropping video chat in favor of voice chat, and that meant it was difficult to get attention without interrupting someone else. I ended up leaving that campaign and joining a smaller one, and that is working out much better. I also have attended a handful of virtual happy hours over the year, and those have been fun, but sporadic. An unexpected social outlet came about in the form of the tilde community that I belong to - &lt;a href="https://tilde.town" rel="external"&gt;Tilde Town&lt;/a&gt;. I interacted with them much more this year than in any of the previous five years I've been a part of it, and started to make some friends. Discord communities have also provided a social environment to a lesser degree, and I've become more involved in the Royal Manticoran Navy, a fan organization dedicated to David Weber's Honorverse novels.&lt;/p&gt;
&lt;p&gt;My personal project Iron Arachne has seen a wealth of development in 2020. Near the beginning of the year I started running into limitations of the Golang ecosystem and rewrote the entire project into a Laravel monolith. This worked much better, even if certain operations became much slower. The site expanded to the point where users had accounts and could save their generated results, and the heraldry generator grew and became more useful and complex. Unfortunately, the infrastructure costs to support the site also grew, and in the last couple months I could no longer justify their expense. So I rewrote the site again, this time as a single-page app in Vue.js that I could host for free on Netlify. The site lost a lot of functionality in the process, but it now costs nothing to maintain. In a happy turn of events, the star system generator actually became much faster in the conversion to JavaScript, going from a 3-5 second generation time to under 60ms. I will talk more about my plans for Iron Arachne in my first blog post of 2021.&lt;/p&gt;
&lt;p&gt;The last big change of 2020 that I'll mention here is my return to the Apple ecosystem. I replaced my Pixel 2 with an iPhone 11 Pro last year, and this year I replaced my custom Windows/Linux PC with a 2019 16" MacBook Pro, and my Fitbit Charge 3 with an Apple Watch. I don't regret this decision at all. While there have been some periods of adjustment, it has been a positive experience overall. Gaming on the MacBook Pro is not as good as it was on my custom rig, but Bootcamp lets me play most of my PC games without issue. I wish the GPU was better but otherwise it works fine.&lt;/p&gt;
&lt;p&gt;All in all, 2020 has been a lot better than it could have been for me personally. I am deeply grateful for being in a position to weather the storm this way. Hopefully 2021 will be better for the world in general. The vaccines and new American leadership give me hope.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Mon, 28 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/12/2020-year-in-review/</guid></item><item><title>How to Concatenate Strings in Lua</title><link>https://www.dannyguo.com/blog/how-to-concatenate-strings-in-lua</link><author>Danny Guo</author><pubDate>Mon, 28 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.dannyguo.com/blog/how-to-concatenate-strings-in-lua</guid></item><item><title>FreeBSD on a Raspberry Pi 4 with 4GB of RAM</title><link>https://lambdaland.org/posts/2020-12-23_freebsd_rpi4/</link><description>&lt;p&gt;+++&lt;/p&gt;
&lt;p&gt;This is the story of how I managed to get FreeBSD running on a Raspberry Pi 4 with 4GB of RAM, though I think the setup story is pretty similar for those with 2GB and 8GB.&lt;/p&gt;
&lt;p&gt;I also managed to get Rust built from source, (kind of) which is nice because the default Rust installer doesn’t seem to work for FreeBSD running on a Raspberry Pi.&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Mon, 28 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-12-23_freebsd_rpi4/</guid></item><item><title>Se connecter à un serveur VPN Wireguard avec NetworkManager</title><link>/post/2020/12/28/se-connecter-%C3%A0-un-serveur-vpn-wireguard-avec-networkmanager/</link><description>&lt;figure&gt;&lt;img src="/images/wireguard.svg" /&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href="https://www.wireguard.com/"&gt;Wireguard&lt;/a&gt; est un protocole de communication permettant de créer des réseaux VPN. Il se veut plus rapide et plus moderne que son concurrent OpenVPN. OpenVPN garde une longueur d&amp;rsquo;avance non négligeable puisque la quasi-totalité des VPNs commerciaux l&amp;rsquo;utilise.&lt;/p&gt;
&lt;p&gt;Même si Wireguard a encore du chemin à parcourir, il commence à prendre une certaine envergure : en effet, Wireguard est intégré dans le noyau Linux depuis la version 5.6, ce qui facilite sa démocratisation.&lt;/p&gt;</description><author>Accueil on dbeley</author><pubDate>Mon, 28 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">/post/2020/12/28/se-connecter-%C3%A0-un-serveur-vpn-wireguard-avec-networkmanager/</guid></item><item><title>Season's Greetings</title><link>https://www.masswerk.at/nowgobang/2020/seasonsgreetings</link><description>Better late than never, an old-school e-card…</description><author>mass:werk – Now Go Bang!</author><pubDate>Sun, 27 Dec 2020 21:15:00 GMT</pubDate><guid isPermaLink="true">https://www.masswerk.at/nowgobang/2020/seasonsgreetings</guid></item><item><title>Advent of Code</title><link>https://explog.in/notes/aoc.html</link><description>&lt;p&gt;
    A quick introduction to Advent of Code for those of you who've never
    tried it out; as well as vignettes of what I learned from
    participating in AoC 2020.
    &lt;/p&gt;</description><author>RSS</author><pubDate>Sun, 27 Dec 2020 17:37:00 GMT</pubDate><guid isPermaLink="true">https://explog.in/notes/aoc.html</guid></item><item><title>How to make digital copies of your old video tapes</title><link>https://ounapuu.ee/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/</link><description>Or 'Wow, I did not know that VLC could do _that_!'</description><author>./techtipsy</author><pubDate>Sun, 27 Dec 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/12/27/how-to-make-digital-copies-of-your-old-video-tapes/</guid></item><item><title>A review of iOS, from an Android user's perspective</title><link>https://bastibe.de/2020-12-27-ios-and-android.html</link><description>&lt;p&gt;My Pixel 2 phone received its final software update the other day, and its battery took the occasion to really show its age. So it was time for a new phone. Which is not a decision to make lightly, considering that I spend multiple hours per day using it. And this time, I was inclined to give the iPhone another go, mostly because of Google's gross lack of human decency in the last few years. So, after years of using various Android devices, I bought a used, red, iPhone SE (2020). I made this choice with some trepidations, as my last experience with iOS was an iPad 3 from 2012. These are my experiences.&lt;/p&gt;
&lt;p&gt;As a seasoned Android user, my first impressions of iOS were a bit of a mess. There are things that swipe up from the bottom, swipe down from the top, to the left of the home screens, to the right of the home screens, and at various permutations of pressing/holding the home button. Everything animates, takes a long time, and moves the viewport around. Particularly annoying is the placement of the back button in the top left corner, i.e. the most-inconvenient place on the entire screen for the arguably most-important gesture of the entire UI&lt;sup class="footnote-ref" id="fnref-1"&gt;&lt;a href="#fn-1"&gt;1&lt;/a&gt;&lt;/sup&gt;. A close second are the context menus that slide out from a long-pressed item, with the menu thus in a different position on the screen every time you long press anything. These things may be less flashy on Android, but are seriously simpler.&lt;/p&gt;
&lt;p&gt;I also immediately missed Android's customizeable home screen, with freely-positionable app icons and a plethora of useful widgets. iOS is very restrictive in this regard, and seemingly for no good reason. Why is the list of all apps (right-of-homescreen) sorted arbitrarily into nonsensical folders instead of a plain list? Why are app widgets allowed, but only on that weird left-of-the-home-screen screen? Why can't I have a currently-playing widget for my podcast player, a weather radar, or my groceries list? Apparently, iOS 14 has a brand new API that does now allow Android-like widgets in iOS, but at the moment they were only available for Apple's own (useless) apps.&lt;/p&gt;
&lt;p&gt;My second big stumbling block was the iOS on-screen keyboard. At first glance, I thought it a terribly clunky thing. Actions as simple as inserting a comma require multiple taps, and positioning the cursor seemed almost comically difficult. But then I discovered that the &amp;quot;123&amp;quot; button in the bottom left can be swiped instead of tapped, which makes commas and periods and hyphens available to a quick swipe. That is seriously cool, if slightly hampered by my accidentally activating Control Center instead of swiping from &amp;quot;123&amp;quot; a bit too often. And precise cursor positioning is hidden behind a long-press of the spacebar. Very cool indeed. With these gestures, the iOS on-screen keyboard is actually not bad at all.&lt;/p&gt;
&lt;p&gt;Autocorrect seems capable as well, and multi-language aware (hear that, Android?). And, mind-blowingly, a triple-swipe on the content area engages undo and redo in the current text area. Albeit a nigh-undiscoverable gesture, this is miles better than Androids undo/redo system (there isn't one). Actually, Android text fields &lt;em&gt;do&lt;/em&gt; support undo and redo if you press Ctrl-Z on the keyboard, it's just that no on-screen keyboard has a Ctrl key. This is my number one grievance with Android at the moment (although there are &lt;a href="https://play.google.com/store/apps/details?id=com.catchingnow.undo&amp;amp;hl=en_US&amp;amp;gl=US"&gt;workarounds&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;As a summary to the keyboard situation, I came to respect the iOS keyboard. I still miss a German &amp;quot;�&amp;quot; key, more control about the autocorrect system, and a more modern design. But it works reasonably well. Better than Android's stock keyboard for sure.&lt;/p&gt;
&lt;p&gt;My second big hurdle with iOS was the camera. Just like my Pixel's camera, the iPhone takes perfectly acceptible photos. But everything else is just plain worse than on Android. It starts with the way you get access to the camera, either by swiping right on the lock screen, or by tapping the camera app on the home screen. On Android, you double-click the lock button to start the camera, then hit the volume button to take a photo. Not only is this significantly faster, it also requires no ungloved finger, and no look onto the screen. And it doesn't make that abominable shutter sound, either, that the iPhone requires (unless the entire phone is silenced or you take video).&lt;/p&gt;
&lt;p&gt;When I take a picture with my phone, it is because I don't have a dedicated camera at hand. Considering the number of cameras I own, this is most likely to happen when I need a camera &lt;em&gt;fast&lt;/em&gt;. Thus the speed from pants to picture is extremely important to me, and this is a clear victory for Android. And additionally, Pixel phones have supported stacked RAWs since the original Pixel&lt;sup class="footnote-ref" id="fnref-2"&gt;&lt;a href="#fn-2"&gt;2&lt;/a&gt;&lt;/sup&gt;, and offer quite a comprehensive image editing suite right in the stock camera app. And I prefer the Pixel's relatively neutral rendering over the iPhone's oversharpened, over-denoised, waxy images. But that might be just me.&lt;/p&gt;
&lt;p&gt;At this point, I had more or less given up on iOS, and bought a Pixel 4a, which is probably Android's closest competitor to the iPhone SE.&lt;/p&gt;
&lt;p&gt;Beyond the camera, there were a number of annoyances with iOS that I found hard to get used to. Like the fingerprint reader on the SE being very unreliable for me (50% miss rate), and awkwardly requiring a distinct push to activate the home button, where the Pixel's is quicker and in a more convenient location. The home button is in fact not a button, but an immovable touch pad that fakes a button-like behavior with a little rumble effect when pressed uncomfortably hard. Pressing a hard surface really hard did not get comfortable to me, especially not when invoking the multi-tasking switcher with a double-press. And it's awkwardly placed at the very bottom of the device, where my thumb does not rest with any kind of force in normal usage. Another real problem is the lack of third-party browsers&lt;sup class="footnote-ref" id="fnref-3"&gt;&lt;a href="#fn-3"&gt;3&lt;/a&gt;&lt;/sup&gt;, which just leaves you in the cold should a website not work in Safari, or should you dislike Safari's rendering or its very limited ad-blockers. I was particularly annoyed by Safari's context menu for links, which slowly slides out from the link's location, often extending far outside of the screen. Thus opening links in new tabs is just awkwardly slow and annoying in Safari, where Android's more utilitarian menu gets the job done much quicker. Although a phone with a bigger screen might mitigate this problem somewhat.&lt;/p&gt;
&lt;p&gt;On the topic of animations in general, one of my favorite features in Android is the animation speed setting in the Developer settings. If you want to feel like you got a new, faster phone, just set the animation speed to 0.5x, and marvel at the newfound snappiness of everything.&lt;/p&gt;
&lt;p&gt;Apps in general feel annoyingly restrictive on iOS. Where is a true Firefox, with addons? Where is a Youtube player that can play a YouTube video in the background while the screen is locked, or block ads (NewPipe is the bee's knees!). Or a file synchronization tool that can actually synchronize useful data outside of its own sandox? In fact, my original hopes for iOS were driven by my memory of the fabled higher quality apps available only on the App Store. Looking at some of my old favorites on the SE however, I was forced to take off those rose-tinted glasses. These apps might have been radical back in the day, but the world has moved on. I don't see a pervasive difference in app quality between iOS and Android any longer. Of course iOS apps do still cost a more money on average, and often can't be test-driven without paying. That two-hour free return policy on the Play Store is seriously genius.&lt;/p&gt;
&lt;p&gt;Additionally, there were a number of odd problems with the iPhone SE that I found hard to make sense of. For example, apps were very frequently getting booted out of memory. So much so in fact, that often my RSS feeds would not refresh in the background, and podcasts would not download. Even though the iPhone SE sure does have a lot less memory than the Pixel 4a, I hadn't expected this to be an actual problem&lt;sup class="footnote-ref" id="fnref-4"&gt;&lt;a href="#fn-4"&gt;4&lt;/a&gt;&lt;/sup&gt;. And the iPhone would frequently misunderstand a vertical swipe for a horizontal one, or initiate an edge swipe when my finger was still clearly on the screen; My bluetooth headphones sounded noticeably worse, with a strange clipping artifact that should not be there; Significantly worse cell reception and voice quality; Low contrast and tiny text on lock screen notifications; And only barely adequate battery life. And let's not even talk about the stupid Lightning cable, the (comparatively) laggy and tiny TFT screen, the lack of a podcast client I like, and my horrible experiences during the setup process.&lt;/p&gt;
&lt;p&gt;So, in summary, the iPhone SE was not for me. Don't get me wrong, it's a nice enough phone, and probably enough of a smartphone for most people. But there were a number of issues with both its hardware and its software, where I found Android and the Pixel 4a plainly more productive. Which is surprising, as my mind still had iOS pegged as the premium alternative, that I would totally buy if I wasn't too cheap for it. But in actual use I was annoyed at its preference of form over function, with many a distracting animation and a number of glaring ergonomic mistakes. Well, another lesson learned. The only truly significant advantage of iOS remains its vastly superior software support story: The SE will probably receive software updates until 2025 or 2027, where the best-in-class Pixel 4a will definitely expire in 2023.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;&lt;p&gt;in some places, a right swipe can be used instead of the back button. But the behavior is too inconsistent to be useful&lt;a class="footnote" href="#fnref-1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn-2"&gt;&lt;p&gt;what Apple calls &amp;quot;ProRAW&amp;quot;, and only makes available in the iPhone 12. iOS does support ordinary RAW, but only in third-party camera apps, and anyway non-stacked RAW files are rather useless from a tiny phone sensor&lt;a class="footnote" href="#fnref-2"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn-3"&gt;&lt;p&gt;there are different browsers, but they are all required to use Safari's web renderer.&lt;a class="footnote" href="#fnref-3"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn-4"&gt;&lt;p&gt;I hear this might have been a bug in iOs 14.3? What this says about the software quality of iOS in general is even more troubling, however.&lt;a class="footnote" href="#fnref-4"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>bastibe.de</author><pubDate>Sun, 27 Dec 2020 16:32:00 GMT</pubDate><guid isPermaLink="true">https://bastibe.de/2020-12-27-ios-and-android.html</guid></item><item><title>Using Dhall to manage my docker-compose.yml</title><link>https://blog.imraniqbal.org/first-time-with-dhall/</link><description>&lt;p&gt;I saw &lt;a href="https://dhall-lang.org/" rel="external"&gt;Dhall&lt;/a&gt; mentioned on a job posting for NoRedInk.
I had never heard of it before but NoRedInk did create &lt;a href="https://elm-lang.org/" rel="external"&gt;Elm&lt;/a&gt; and are fond of functional tooling so it piqued my interest.&lt;/p&gt;
&lt;p&gt;For reference, Dhall is a simple language.
It's not Turing complete, but it's strongly typed.
It's primarily used for managing configuration files.
It has some helpers to output JSON/YML/bash, but you can also output to plain text.&lt;/p&gt;
&lt;p&gt;The website does a good job of showing what it can do and its use cases so I wont dive into those.
Converting my &lt;a href="https://github.com/compose-spec/compose-spec/blob/master/spec.md#compose-file" rel="external"&gt;docker-compose.yaml&lt;/a&gt; that I use to manage my media server was the first usecase I could think of.&lt;/p&gt;
&lt;p&gt;I wont be posting the full source but I hope I convey how much fun I had working with Dhall.&lt;/p&gt;
&lt;h3 id="experiment"&gt;&lt;a class="anchor" href="https://blog.imraniqbal.org/first-time-with-dhall/#experiment"&gt;
    #
&lt;/a&gt;
Experiment&lt;/h3&gt;
&lt;p&gt;I'll just be focusing on a small part of the docker-compose file, namely the ports.&lt;/p&gt;
&lt;p&gt;Let's say this is my compose file&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;services&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  plex&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;    image&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; linuxserver/plex:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;    ports&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; 32400:32400&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; 32400:32400/udp&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;    environment&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;      VERSION&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; &amp;quot;latest&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A quick translate over would get us&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;let plex =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      { image = &amp;quot;linuxserver/plex:latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , ports = [ &amp;quot;32400:32400&amp;quot;, &amp;quot;32400:32400/udp&amp;quot; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , environment.VERSION = &amp;quot;latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;in  { services.plex = plex }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When passed into &lt;code&gt;dhall&lt;/code&gt; gets us this:&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; dhall --file test.dhall&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;{ services.plex&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  { environment.VERSION = &amp;quot;latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  , image = &amp;quot;linuxserver/plex:latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  , ports = [ &amp;quot;32400:32400&amp;quot;, &amp;quot;32400:32400/udp&amp;quot; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;dhall-to-yaml&lt;/code&gt; produces the following:&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; dhall-to-yaml --file test.dhall&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;services:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  plex:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    environment:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      VERSION: latest&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    image: linuxserver/plex:latest&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    ports:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      - &amp;quot;32400:32400&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      - &amp;quot;32400:32400/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is the exact same file (keys are sorted so the output is deterministic).&lt;/p&gt;
&lt;p&gt;I always forget what order the ports should go (host:container) so let's take advantage of Dhall to make it easier on me.
Before I make any changes to the file I'm going to be grabbing the Dhall SHA so I can compare it to my refactored code's SHA, if they are equal then the output has not changed.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; dhall hash --file test.dhall&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;sha256:db23b00a8e79e084306b72ecc788f0b95579080c883cb72045a3ae6ea43999fd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First lets move &lt;code&gt;ports&lt;/code&gt; into it's own variable and verify the hash&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;let ports&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : List Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = [ &amp;quot;32400:32400&amp;quot;, &amp;quot;32400:32400/udp&amp;quot; ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let plex =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      { image = &amp;quot;linuxserver/plex:latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , ports&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , environment.VERSION = &amp;quot;latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;in  { services.plex = plex }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; dhall hash --file test.dhall&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;sha256:db23b00a8e79e084306b72ecc788f0b95579080c883cb72045a3ae6ea43999fd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OK we can be sure we didn't change our output at all. Don't worry about &lt;code&gt;: List Text&lt;/code&gt; that is just a type annotation.&lt;/p&gt;
&lt;p&gt;Lets start by making a type that we can store the port mapping in and a function to convert it to text.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;let PortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Type&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = { host : Natural, container : Natural }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let PortMapping/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : PortMapping -&amp;gt; Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = \(pm : PortMapping) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;        &amp;quot;${Natural/show pm.host}:${Natural/show pm.container}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can supply the ports we want in any order and be confident the output order is correct.
Let's update &lt;code&gt;ports&lt;/code&gt; to use this new functionality.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;let ports&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : List Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = [ PortMapping/show { host = 32400, container = 32400 }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , &amp;quot;${PortMapping/show { host = 32400, container = 32400 }}/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our hash is still &lt;code&gt;sha256:db23b00a8e79e084306b72ecc788f0b95579080c883cb72045a3ae6ea43999fd&lt;/code&gt; so we haven't broken anything yet.&lt;/p&gt;
&lt;p&gt;This is better but we still need to do some string interpolation if we want to create a UDP port mapping.
The &lt;a href="https://docs.docker.com/config/containers/container-networking/" rel="external"&gt;docker documentation&lt;/a&gt; says the notation without &lt;code&gt;/udp&lt;/code&gt; or &lt;code&gt;/tcp&lt;/code&gt; will default to tcp.&lt;/p&gt;
&lt;p&gt;Let's create an enum that will represent these two and update our code to use it.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;let Port&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Type&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = &amp;lt; tcp : PortMapping | udp : PortMapping &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let Port/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Port -&amp;gt; Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = \(p : Port) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;        merge&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;          { tcp = PortMapping/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;          , udp = \(pm : PortMapping) -&amp;gt; &amp;quot;${PortMapping/show pm}/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;          }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;          p&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let ports&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : List Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = [ Port/show (Port.tcp { host = 32400, container = 32400 })&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , Port/show (Port.udp { container = 32400, host = 32400 })&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much nicer! And our hash is still producing &lt;code&gt;sha256:db23b00a8e79e084306b72ecc788f0b95579080c883cb72045a3ae6ea43999fd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now what would be even nicer is we did not have to specify the port twice if they are the same value.
Let's do that by expanding our &lt;code&gt;Port&lt;/code&gt; enum to supply a &lt;code&gt;tcp_mirror&lt;/code&gt; and a &lt;code&gt;udp_mirror&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;let Port&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Type&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = &amp;lt; tcp : PortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      | udp : PortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      | tcp_mirror : Natural&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      | udp_mirror : Natural&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let Port/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Port -&amp;gt; Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = \(p : Port) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;        let udpPortMapping = \(pm : PortMapping) -&amp;gt; &amp;quot;${PortMapping/show pm}/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;        in  merge&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              { tcp = PortMapping/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              , udp = udpPortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              , tcp_mirror =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                  \(port : Natural) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                    PortMapping/show { host = port, container = port }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              , udp_mirror =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                  \(port : Natural) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                    udpPortMapping { host = port, container = port }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              p&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let ports&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : List Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = [ Port/show (Port.tcp_mirror 32400), Port/show (Port.udp_mirror 32400) ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;-- sha256:db23b00a8e79e084306b72ecc788f0b95579080c883cb72045a3ae6ea43999fd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can include the &lt;code&gt;List/map&lt;/code&gt; function from &lt;a href="https://github.com/dhall-lang/dhall-lang/tree/master/Prelude" rel="external"&gt;&lt;code&gt;Prelude&lt;/code&gt;&lt;/a&gt; so we do not have manually transform our port list.&lt;/p&gt;
&lt;h4 id="final-test-dhall"&gt;&lt;a class="anchor" href="https://blog.imraniqbal.org/first-time-with-dhall/#final-test-dhall"&gt;
    #
&lt;/a&gt;
Final &lt;code&gt;test.dhall&lt;/code&gt;&lt;/h4&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;let List/map = https://prelude.dhall-lang.org/List/map&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let PortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Type&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = { host : Natural, container : Natural }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let PortMapping/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : PortMapping -&amp;gt; Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = \(pm : PortMapping) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;        &amp;quot;${Natural/show pm.host}:${Natural/show pm.container}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let Port&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Type&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = &amp;lt; tcp : PortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      | udp : PortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      | tcp_mirror : Natural&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      | udp_mirror : Natural&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      &amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let Port/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : Port -&amp;gt; Text&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = \(p : Port) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;        let udpPortMapping = \(pm : PortMapping) -&amp;gt; &amp;quot;${PortMapping/show pm}/udp&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;        in  merge&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              { tcp = PortMapping/show&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              , udp = udpPortMapping&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              , tcp_mirror =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                  \(port : Natural) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                    PortMapping/show { host = port, container = port }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              , udp_mirror =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                  \(port : Natural) -&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;                    udpPortMapping { host = port, container = port }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;              p&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let portsList&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    : List Port&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    = [ Port.tcp_mirror 32400, Port.udp_mirror 32400 ]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;let plex =&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      { image = &amp;quot;linuxserver/plex:latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , ports = List/map Port Text Port/show portsList&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      , environment.VERSION = &amp;quot;latest&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;in  { services.plex = plex }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;-- sha256:db23b00a8e79e084306b72ecc788f0b95579080c883cb72045a3ae6ea43999fd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="my-conclusion"&gt;&lt;a class="anchor" href="https://blog.imraniqbal.org/first-time-with-dhall/#my-conclusion"&gt;
    #
&lt;/a&gt;
My Conclusion&lt;/h2&gt;
&lt;p&gt;Using Dhall is super fun.
I can totally see the usefulness in a shared team environment for managing configurations.
I think I went a bit overboard as my ~120 line compose file is now ~400 lines of Dhall code 😅.
Except now it's statically typed and it will be super easy to add new services to my server (or in context of the experiment, new ports to the Plex service).&lt;/p&gt;</description><author>Imran's Blog</author><pubDate>Sun, 27 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.imraniqbal.org/first-time-with-dhall/</guid></item><item><title>Stringer Self Hosted RSS Reader</title><link>https://blog.cetinich.net/content/archive/2020-stringer-rss/</link><description>My setup is using the docker compose file and a local build of the docker image
(since docker hub image is years old). Here is a dark theme (solarized) for the
CSS. Just paste this over your stringer/app/assets/stylesheets/application.css
file. I did not spend much time on it but it looks good enough for my taste.</description><author>Brent's Blog</author><pubDate>Sun, 27 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/archive/2020-stringer-rss/</guid></item><item><title>The year in books: 20 to recommend in 2020</title><link>http://notes.eatonphil.com/year-in-books-2020.html</link><description>&lt;p&gt;This year I finished 47 books, up from last year but not a personal
best. The breakdown was 17 non-fiction and 30 fiction. Another 20-30
remain started but unfinished this year.&lt;/p&gt;
&lt;h3 id="non-fiction"&gt;Non-fiction&lt;/h3&gt;&lt;p&gt;The 8 non-fiction books I most recommend are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/51034048-fashionopolis"&gt;Fashionapolis: The Price of Fast Fashion and the Future of Clothes&lt;/a&gt; (Must read)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/48566725-effective-python"&gt;Effective Python: 90 Specific Ways to Write Better Python&lt;/a&gt; (Must read; truly excellent for Python programmers, I recommend this to anyone I work with)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/93904.The_Machine_That_Changed_the_World"&gt;The Machine that Changed the World&lt;/a&gt; (Must read)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/16043511-europe"&gt;Europe: The Struggle for Supremacy from 1453 to the Present&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/19606799-wind-sand-and-stars"&gt;Wind, Sand and Stars&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/11169043-american-colossus"&gt;American Colussus: The Triumph of Capitalism, 1865-1900&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/2360599.Making_Common_Sense_of_Japan"&gt;Making Common Sense of Japan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/8155672-the-german-genius"&gt;The German Genius&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The 3 books I recommend you not to waste time on are: "The Two
Koreas", "The Price of Inequality", and "Ninety Percent of Everything:
Inside Shipping".&lt;/p&gt;
&lt;h4 id="the-whole-list"&gt;The whole list&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/235560.The_Two_Koreas"&gt;The Two Koreas&lt;/a&gt; by Don Oberdorfer&lt;ul&gt;
&lt;li&gt;Interesting but not a huge fan, seemed pretty biased against South Korea somehow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/88546.Forbidden_Nation"&gt;Forbidden Nation: A History of Taiwan&lt;/a&gt; by Jonathan Manthorpe&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/48566725-effective-python"&gt;Effective Python: 90 Specific Ways to Write Better Python&lt;/a&gt; by Brett Slatkin&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/43701534-a-philosophy-of-software-design"&gt;A Philosophy of Software Design&lt;/a&gt; by John Ousterhout&lt;ul&gt;
&lt;li&gt;Came as a recommendation from someone on Twitter, ultimately not a huge fan. Still looking for high quality books on software design&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/16031130-the-price-of-inequality"&gt;The Price of Inequality&lt;/a&gt; by Joseph E. Stiglitz&lt;ul&gt;
&lt;li&gt;Agreed with the premise but the book was incoherent and too self-assuring&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18930203-paris-reborn"&gt;Paris Reborn: Napoléon III, Baron Haussmann, and the Quest to Build a Modern City&lt;/a&gt; by Stephane Kirkland&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/51034048-fashionopolis"&gt;Fashionapolis: The Price of Fast Fashion and the Future of Clothes&lt;/a&gt; by Dana Thomas&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/6603103-a-moveable-feast"&gt;A Moveable Feast&lt;/a&gt; by Ernest Hemingway&lt;ul&gt;
&lt;li&gt;I normally love Hemingway's writing but this particular book was not very coherent&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/16043511-europe"&gt;Europe: The Struggle for Supremacy from 1453 to the Present&lt;/a&gt; by Brendan Simms&lt;ul&gt;
&lt;li&gt;Such an excellent introduction to the continent for Americans who otherwise don't have great background&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/19606799-wind-sand-and-stars"&gt;Wind, Sand and Stars&lt;/a&gt; by Antoine de Saint-Exupéry&lt;ul&gt;
&lt;li&gt;A beautiful memoir of flights by the author of The Little Prince, very similar in style to Hemingway&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/11169043-american-colossus"&gt;American Colussus: The Triumph of Capitalism, 1865-1900&lt;/a&gt; by H.W. Brands&lt;ul&gt;
&lt;li&gt;Baby's first primer on unions, (I need more recommendations on the history of unions)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/2360599.Making_Common_Sense_of_Japan"&gt;Making Common Sense of Japan&lt;/a&gt; by Steven R. Reed&lt;ul&gt;
&lt;li&gt;It can be difficult to find English translations of Korean, Japanese history by Korean and Japanese authors; this is a good one by an American professor&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/93904.The_Machine_That_Changed_the_World"&gt;The Machine that Changed the World&lt;/a&gt; by James P. Womack&lt;ul&gt;
&lt;li&gt;An excellent, well-researched history of automobile manufacturing in the US, Europe and Japan from the 1900s to 1990; how Japan ate everyone's lunch&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/40620.The_United_States_of_Europe"&gt;The United States of Europe&lt;/a&gt; by T.R. Reid&lt;ul&gt;
&lt;li&gt;Very light introduction to the European Union&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/7090.The_Soul_of_a_New_Machine"&gt;The Soul of a New Machine&lt;/a&gt; by Tracy Kidder&lt;ul&gt;
&lt;li&gt;Overhyped by the internets, but not bad&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/8155672-the-german-genius"&gt;The German Genius&lt;/a&gt; by Peter Watson&lt;ul&gt;
&lt;li&gt;Dense but excellent introduction to many famous Germans in many fields throughout time&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18626537-ninety-percent-of-everything"&gt;Ninety Percent of Everything: Inside Shipping&lt;/a&gt; by Rose George&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fiction"&gt;Fiction&lt;/h3&gt;&lt;p&gt;I'm trying to read more from non-English authors. If you see
non-English authors in the vein of these here that you can recommend,
I'd love to hear from you.&lt;/p&gt;
&lt;p&gt;The 12 fiction books I most recommend are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/11607290-planet-of-the-apes"&gt;Planet of the Apes&lt;/a&gt; (Must read, yes even if you've seen the film)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18882869-all-quiet-on-the-western-front"&gt;All Quiet on the Western Front&lt;/a&gt; (Must read)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/26167126-the-mouse-that-roared"&gt;The Mouse That Roared&lt;/a&gt; (Must read)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/25171354-the-dead-mountaineer-s-inn"&gt;The Dead Mountaineer's Inn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/17406654-the-golem-and-the-jinni"&gt;The Golem and the Jinni&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/38886181-neverwhere"&gt;Neverwhere&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/35901747-dubliners"&gt;Dubliners&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/36510196-old-man-s-war"&gt;Old Man's War&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/38453346-the-inspector-barlach-mysteries"&gt;The Inspector Barlach Mysteries: The Judge and His Hangman and Suspicion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18842344-fant-mas"&gt;Fantômas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/40793127-foundation"&gt;Foundation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/13380806-out-of-the-silent-planet"&gt;Out of the Silent Planet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The only book I really didn't like was "Invisible Cities".&lt;/p&gt;
&lt;h4 id="the-whole-list"&gt;The whole list&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18782460-march-violets"&gt;March Violets&lt;/a&gt; by Philip Kerr (Scottish)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/25299696-liberty-bar"&gt;Liberty Bar&lt;/a&gt; by Georges Simenon (Belgian)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/20018218-the-late-monsieur-gallet"&gt;The Late Monsieur Gallet&lt;/a&gt; by Georges Simenon (Belgian)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/35901747-dubliners"&gt;Dubliners&lt;/a&gt; by James Joyce (Irish)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/11580940-tales-of-the-city"&gt;Tales of the City&lt;/a&gt; by Amistead Maupin (American)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/52971537-the-third-policeman"&gt;The Third Policeman&lt;/a&gt; by Flann O'Brien (Irish)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/6522120-44-scotland-street"&gt;44 Scotland Street&lt;/a&gt; by Alexander McCall Smith (British-African)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/23209197-knots-and-crosses"&gt;Knots and Crosses&lt;/a&gt; by Ian Rankin (Scottish)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/35598044-i-hear-your-voice"&gt;I Hear Your Voice&lt;/a&gt; by Kim Young Ha (South Korean)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/17406654-the-golem-and-the-jinni"&gt;The Golem and the Jinni&lt;/a&gt; by Helene Wecker (American)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/25541152-the-tokyo-zodiac-murders"&gt;The Tokyo Zodiac Murders&lt;/a&gt; by Shimada Sōji (Japanese)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/8130077-the-screwtape-letters"&gt;The Screwtape Letters&lt;/a&gt; by C.S. Lewis (English)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/38886181-neverwhere"&gt;Neverwhere&lt;/a&gt; by Neil Gaiman (English)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/36510196-old-man-s-war"&gt;Old Man's War&lt;/a&gt; by John Scalzi (American)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/9285319-tales-from-earthsea"&gt;Tales from Earthsea&lt;/a&gt; by Ursula K. Le Guin (American)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/23632478-solaris"&gt;Solaris&lt;/a&gt; by Stanisław Lem (Polish)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/16029682-a-wizard-of-earthsea"&gt;A Wizard of Earthsea&lt;/a&gt; by Ursula K. Le Guin (American)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/11607290-planet-of-the-apes"&gt;Planet of the Apes&lt;/a&gt; by Pierre Boulle (French)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/25171354-the-dead-mountaineer-s-inn"&gt;The Dead Mountaineer's Inn&lt;/a&gt; by Arkady Strugatsky (Russian)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/49605492-invisible-cities"&gt;Invisible Cities&lt;/a&gt; by Italo Calvino (Cuban-born Italian)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/38453346-the-inspector-barlach-mysteries"&gt;The Inspector Barlach Mysteries: The Judge and His Hangman and Suspicion&lt;/a&gt; by Friedrich Dürrenmatt (Swiss)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18842344-fant-mas"&gt;Fantômas&lt;/a&gt; by Marcel Allain (French)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/18882869-all-quiet-on-the-western-front"&gt;All Quiet on the Western Front&lt;/a&gt; by Erich Maria Remarque (Germany)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/22346782-a-crime-in-holland"&gt;A Crime in Holland&lt;/a&gt; by Georges Simenon (Belgian)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/32076294-the-wonderful-adventure-of-nils-holgersson"&gt;The Wonderful Adventure of Nils Holversson&lt;/a&gt; by Selma Lagerlöf (Swedish)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/40793127-foundation"&gt;Foundation&lt;/a&gt; by Isaac Asimov (Russian-born American)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/13380806-out-of-the-silent-planet"&gt;Out of the Silent Planet&lt;/a&gt; by C.S. Lewis (English)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/19847968-the-spy-who-came-in-from-the-cold"&gt;The Spy Who Came in from the Cold&lt;/a&gt; by John le Carré (English)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/19792871-the-bat"&gt;The Bat&lt;/a&gt; by Jo Nesbø (Norwegian)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/26167126-the-mouse-that-roared"&gt;The Mouse That Roared&lt;/a&gt; by Leonard Wibberley (Irish-born American)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Out of 47 books read this year, here's the 20 I recommend to you (gave them 4/5 stars or better). I'm trying to read more non-English authors so I'd love to hear if there are authors with similar style on this list you'd recommend!&lt;a href="https://t.co/FjHcvHpRSr"&gt;https://t.co/FjHcvHpRSr&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1343242325791805447?ref_src=twsrc%5Etfw"&gt;December 27, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 27 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/year-in-books-2020.html</guid></item><item><title>Migration from FreeNAS to TrueNAS</title><link>https://kevin.deldycke.com/2020/migration-from-freenas-to-truenas</link><description>&lt;p&gt;
 The upgrade itself is quite straightforward by the way of the &lt;span class="caps"&gt;GUI&lt;/span&gt;. But things gets complicated if you’ve got an encrypted&amp;nbsp;pool.
&lt;/p&gt;



&lt;section id="encrypted-pool-migration"&gt;
 &lt;h1&gt;
  Encrypted pool migration
  &lt;a class="headerlink" href="#encrypted-pool-migration" title="Link to this heading"&gt;&amp;nbsp;¶
  &lt;/a&gt;
 &lt;/h1&gt;
 &lt;p&gt;
  Upgrading from FreeNAS to TrueNAS will render your encrypted pool unavailable. FreeNAS relies on
  &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Geli_%28software%29"&gt;
   &lt;code class="docutils literal notranslate"&gt;
    &lt;span class="pre"&gt;
     geli
    &lt;/span&gt;
   &lt;/code&gt;
  &lt;/a&gt;
  ’s block-layer disk encryption and is considered legacy. TrueNAS …&lt;/p&gt;&lt;/section&gt;</description><author>Kevin Deldycke</author><pubDate>Sun, 27 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://kevin.deldycke.com/2020/migration-from-freenas-to-truenas</guid></item><item><title>You're Allowed To Make Your Own Tools</title><link>https://www.swyx.io/make-your-own-tools</link><description>Making personal side projects for fun and profit.</description><author>swyx's site RSS Feed</author><pubDate>Sat, 26 Dec 2020 20:04:11 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/make-your-own-tools</guid></item><item><title>Beaver Lake Preserve</title><link>https://sam.hooke.me/trip/2020/12/beaver-lake-preserve/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;p&gt;No trip report yet.&lt;/p&gt;



 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/beaver-lake-preserve/hazel-wolf-wetlands.jpg"&gt;
 
 &lt;img alt="Some very wet wetlands surrounded by trees." src="https://sam.hooke.me/images/trip/2020/beaver-lake-preserve/hazel-wolf-wetlands_hu6519253756225380560.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Hazel Wolf Wetlands.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/beaver-lake-preserve/beaver-lake-preserve-map.jpg"&gt;
 
 &lt;img alt="A map." src="https://sam.hooke.me/images/trip/2020/beaver-lake-preserve/beaver-lake-preserve-map_hu11704162225670785706.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 A map of the woods.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;</description><author>Sam Hooke</author><pubDate>Sat, 26 Dec 2020 09:00:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/12/beaver-lake-preserve/</guid></item><item><title>What went wrong with software for prisons</title><link>https://stop.zona-m.net/2020/12/what-went-wrong-with-software-for-prisons/</link><description>&lt;p&gt;It became just another business, in one more market.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 26 Dec 2020 09:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/what-went-wrong-with-software-for-prisons/</guid></item><item><title>Chess bookmarks</title><link>https://xenodium.com/chess-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dwheeler.com/chess-openings/"&gt;A Beginner's Garden of Chess Openings&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=25446399"&gt;A Beginner's Garden of Chess Openings (2002) (Hacker News)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sat, 26 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/chess-bookmarks</guid></item><item><title>On the UX of Microwave Ovens</title><link>https://one.mikro2nd.net/pages/ux-of-microwave-ovens/</link><description>Who the hell decided on four? Why four beeps? That tinny, high-pitched electronic squeak that grates on the nerves like the gravel tearing at your knee that time you came off your bike. Two beeps would have been plenty. Hell, one would be enough. What does it take for the microwave to say, &amp;ldquo;I&amp;rsquo;m done. Your food is hot&amp;rdquo;. Hottish anyway. Hot around the edges but never in the middle. Actually you don&amp;rsquo;t really need any beeping noises at all — the machinery inside the thing, the fan, the motor that drives the turntable, the synchrotron&amp;rsquo;s whirl, all those come to a stop.</description><author>one mikro2nd</author><pubDate>Fri, 25 Dec 2020 12:23:39 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/ux-of-microwave-ovens/</guid></item><item><title>Our need for rituals, and one thing that really upsets it</title><link>https://stop.zona-m.net/2020/12/our-need-for-rituals-and-one-thing-that-really-upsets-it/</link><description>&lt;p&gt;Guess what that thing is?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 25 Dec 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/our-need-for-rituals-and-one-thing-that-really-upsets-it/</guid></item><item><title>My 2020 reads</title><link>https://www.alexanderlolis.com/my-2020-reads</link><description>Flow</description><author>Alexander's Blog Blog</author><pubDate>Fri, 25 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.alexanderlolis.com/my-2020-reads</guid></item><item><title>2020 - Year in Review</title><link>https://www.mootoday.com/blog/2020-year-in-review</link><description>A look back at what was 2020. Highlights, what worked and what didn't.</description><author>www.mootoday.com - RSS Feed</author><pubDate>Thu, 24 Dec 2020 19:57:09 GMT</pubDate><guid isPermaLink="true">https://www.mootoday.com/blog/2020-year-in-review</guid></item><item><title>Nanoscale is where chipmaking must go</title><link>https://stop.zona-m.net/2020/12/nanoscale-is-where-chipmaking-must-go/</link><description>&lt;p&gt;This is important. Really.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 24 Dec 2020 15:54:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/nanoscale-is-where-chipmaking-must-go/</guid></item><item><title>Advent of Haskell 2020: Santa Wrap</title><link>https://dicioccio.fr/santa-wrap.html</link><description>We help Santa Elves optimize cutting wrapping paper to accomodate various shapes.  The difficult optimization requires a dedicated solver in MiniZinc. Haskell allows to integrate with MiniZinc, reads JSON and outputs a PNG image with the footprint of the positionned shapes to cut. This article shows that a one-day-of-work project can reach pretty far.</description><author>Lucas DiCioccio's Blog</author><pubDate>Thu, 24 Dec 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://dicioccio.fr/santa-wrap.html</guid></item><item><title>Big Tech = Feudalism + Animal Farm, digitized. Via tax havens</title><link>https://stop.zona-m.net/2020/12/big-tech-feudalism-animal-farm-digitized.-via-tax-havens/</link><description>&lt;p&gt;Because, INNOVATION!!!!, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 23 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/big-tech-feudalism-animal-farm-digitized.-via-tax-havens/</guid></item><item><title>2020</title><link>http://evantravers.com/articles/2020/12/23/2020/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/12/canyon.jpg" /&gt;&lt;/p&gt;&lt;p&gt;Hindsight is 2020… but I'm glad to see 2020 in hindsight. 🥁 Truthfully, my family has been very blessed and protected in so many ways through this wild year.&lt;/p&gt;
&lt;p&gt;We welcomed another little one safely, God continues to provide for us through my job (which I enjoy!), and our little family has had lots of time together... sometimes socially distanced but otherwise wonderful.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/12/baby.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This has also been a challenging year... mostly the external factors of The Unknown&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-unknown" id="fnref-unknown"&gt;1&lt;/a&gt;&lt;/sup&gt; preying on my mind and creating the usual symptoms of stress on my body and mind. Running to the Lord first, and wisely limiting some of the sources of stress has really helped.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#creating" id="creating"&gt;&lt;/a&gt;Creating&lt;/h2&gt;
&lt;p&gt;This year I wrote &lt;a href="http://evantravers.com/articles/2020/"&gt;&lt;strong&gt;60 blog posts&lt;/strong&gt;&lt;/a&gt; including this one.&lt;/p&gt;
&lt;p&gt;While writing has been creatively satisfying in and of itself (and useful!&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;2&lt;/a&gt;&lt;/sup&gt;) even more wonderful has been likes, comments, reblogs and the occasional email from a new internet friend. I got to &lt;a href="https://brettterpstra.com/2020/01/13/the-indieweb-and-webmentions/"&gt;help a blogging hero of mine set up webmentions&lt;/a&gt;, got a lot of folks talking about &lt;a href="http://evantravers.com/articles/series/simple-markdown-zettelkasten/"&gt;zettelkasten&lt;/a&gt;, and a few crazy souls &lt;em&gt;actually tried&lt;/em&gt; my hammerspoon setup. This year I've &lt;strong&gt;received about 12 emails from y'all…&lt;/strong&gt; and each made my day and inspired me to keep going. I have removed analytics from the site… getting emails from y'all is much nicer than tracking top keywords.&lt;/p&gt;
&lt;p&gt;It's really hard to tell how much I added to my zettelkasten… the modified time has been clobbered by running the transition script too many times. Looking forward to investing in that more this year.&lt;/p&gt;
&lt;p&gt;While I don't presently code for a living, GitHub counts &lt;strong&gt;872 contributions&lt;/strong&gt;… probably mostly me dinking around on my blog, hammerspoon, or QMK. :-P&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#reading" id="reading"&gt;&lt;/a&gt;Reading&lt;/h2&gt;
&lt;p&gt;I only read &lt;strong&gt;13 books&lt;/strong&gt; this year. :( I'll blame a variety of factors, including discovering long-form podcasts and getting overly absorbed that I can borrow graphic novels on Hoopla that I can borrow comic books from the library (which don't count for me… although I definitely maxed out my 10 per month every single month this year. I suppose if I did count comic books, it'd be closer to 120?)&lt;/p&gt;
&lt;p&gt;I've responded by deleting Hoopla off my phone, which seems to be helping. 😜&lt;/p&gt;
&lt;p&gt;While I don't know how many articles I read this year, I apparently saved &lt;strong&gt;1,360 articles and videos&lt;/strong&gt; in my instapaper… so something less than that. I saved 67 annotated links into my zettelkasten… although many more went into blog posts and newsletters.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#health" id="health"&gt;&lt;/a&gt;Health&lt;/h2&gt;
&lt;figure class="right"&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/12/strava.jpeg" /&gt;
&lt;/figure&gt;
&lt;p&gt;According to strava I &lt;strong&gt;worked out 214 days&lt;/strong&gt; in 2020. I doubled up on running, and set another sub-25m 5k just last week.&lt;/p&gt;
&lt;p&gt;While (God be praised!) we've been well and haven't really gained any weight, I'm still wrestling with my diet, although a combination of macro tracking and looking at the graph every morning seems to be helping me in the last two months. Turns out sugar is the single most correlated stat for me and weight. I'll write more about that automation later I'm sure.&lt;/p&gt;
&lt;p&gt;In all, I think this year I finally started to add sleep, water intake, and diet moderation to the mix. Now to make it an easy part of my life.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#work" id="work"&gt;&lt;/a&gt;Work&lt;/h2&gt;
&lt;p&gt;In February, my wife and I got away to talk about the next four years and what we wanted to accomplish personally and in our family life. One of those things was that we wanted me to work from home by the end of those four years... and we got our wish the next week. 🤷&lt;/p&gt;
&lt;p&gt;COVID remote has been a challenge, but a welcome one. I work well from home, and I've been glad that I could be home for the first six months of our newest. While I certainly pray for the pandemic to end, I kinda want to stay home.&lt;/p&gt;
&lt;p&gt;Our team has grown both in size and capability. I don't think I've &lt;em&gt;ever&lt;/em&gt; been this excited to get back into work for the next year, I know great things are ahead.&lt;/p&gt;
&lt;p&gt;I've been tracking my time this year, although it really didn't become a habit till June (&lt;a href="http://evantravers.com/articles/series/hammerspoon-headspace/"&gt;Headspace&lt;/a&gt; was born in May.)&lt;/p&gt;
&lt;figure&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/12/toggl.png" /&gt;
  &lt;figcaption&gt;
    These are mostly since June:&lt;br /&gt;
    Dark Blue is High Value. (298h, some of it hidden in the gray.)&lt;br /&gt;
    Light Blue is shallow work (238h) and meetings (266h).&lt;br /&gt;
    Green (47h) is "play" which includes blogging and working on dotfiles.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Looking at my stats... I'm kind of appalled of where the time was invested. I'm happy with the results, and so I guess this is an encouragement that I can do &lt;em&gt;even&lt;/em&gt; better.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#spiritual-life" id="spiritual-life"&gt;&lt;/a&gt;Spiritual Life&lt;/h2&gt;
&lt;p&gt;I'm still not where I want to be here. Half way through the year I realized my commitment to working out was choking my quiet times, so I've started turning that around: trading my workout time for prayer and the word. I still haven't gotten back to my study habit I had five years ago, I may need to find another time in the day because mornings are difficult with two little ones.&lt;/p&gt;
&lt;p&gt;I think the next step is to reconnect with my wife and really prioritize shared time in the word and prayer. With the two smidgens it's easy to have a split schedule.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#relationships" id="relationships"&gt;&lt;/a&gt;Relationships&lt;/h2&gt;
&lt;p&gt;Mid-COVID, I started realizing that while my introverted self was happy, there would be others that would be struggling, so I started reaching out to my friends for virtual lunches. I wound up doing &lt;em&gt;quite&lt;/em&gt; a few... too many actually, I think that kind of undercut my family time. Going to find a sustainable pattern going forward, but definitely going to continue something intentional and personal over likes and comments on social media.&lt;/p&gt;
&lt;p&gt;Unsurprisingly, I cut off personal social media. I'm still pretty active on twitter and linkedin for semi-professional reasons, but instagram... well I only posted twice this year. I think I'll probably close it down eventually. I'm already collecting an email list for those who want more personal family updates, but don't feel like feeding FB's giant algorithm monster.&lt;/p&gt;
&lt;p&gt;While the wife and I got a lot of time together, it wasn't very restful for her... when I work from home I can leave my office, but if you work &lt;strong&gt;on&lt;/strong&gt; the home it is &lt;em&gt;hard&lt;/em&gt; to find that life-giving distance in COVID-land, especially with a newborn. We went on our first date &lt;em&gt;in six months&lt;/em&gt; this past month, and we are prioritizing more dating time in 2021.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#2021" id="2021"&gt;&lt;/a&gt;2021&lt;/h2&gt;
&lt;p&gt;In 2020 chose the theme of &amp;quot;Clarity.&amp;quot; I often asked myself when stressed if I had clarity on what was most important, and that really helped. If I knew what was most important (often my family) then I prioritized that. If I didn't know what was most important, then discovering my priorities was the next thing.&lt;/p&gt;
&lt;p&gt;I look forward to revealing my 2021 theme... at another time. 😉&lt;/p&gt;
&lt;p&gt;I still haven't finished my full yearly personal review and planning... that usually comes in the days before New Years, but I am excited to see what the Lord will do in my heart in 2021. He has been faithful through a very strange and stressful year, and I fully expect to see His hand clearly in 2021.&lt;/p&gt;
&lt;p&gt;He is good. I trust him. Let's do this!&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-unknown"&gt;
&lt;p&gt;Politics. Pandemics. Other P words. &lt;a class="footnote-backref" href="#fnref-unknown"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;I have been secretly pleased &lt;em&gt;every&lt;/em&gt; time I send someone a previously written link to answer a question! &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Wed, 23 Dec 2020 19:10:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/12/23/2020/</guid></item><item><title>Books and Links: December</title><link>http://evantravers.com/articles/2020/12/23/books-and-links-december/</link><description>&lt;p&gt;This year is almost done! I'm working on a year in review thingy... how many years have I done that now?&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;p&gt;I haven't finished any books this month... I've been burning down the remaining 15+ hours of a podcast entitled &lt;a href="http://www.martyrmade.com/fear-loathing-in-the-new-jerusalem/"&gt;Fear and Loathing in the New Jerusalem&lt;/a&gt;, a podcast series by Darryl Cooper. It examines the birth and growth of Zionism, starting in the late 19th century all the way up to the birth of the modern Israeli state.&lt;/p&gt;
&lt;p&gt;I went into this idly interested, but wound up being enthralled… and horrified. I appreciated how he confronts the listener with the experience of people in that time and context, honestly asking the hard question: &amp;quot;what would you have done?&amp;quot;&lt;/p&gt;
&lt;p&gt;On deck: The 12 Week Year, House of Leaves.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#whats-a-linkable-app-and-why-does-linkability-matter--hook" id="whats-a-linkable-app-and-why-does-linkability-matter--hook"&gt;&lt;/a&gt;What’s a Linkable App and Why Does Linkability Matter? – Hook&lt;/h3&gt;
&lt;p&gt;I'm obsessed with this weird app at the moment.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;People have become so accustomed to the weird fact that, without Hook, information resources are not easily addressable on the Mac that they tend not to realize that its just as important to be able to address local (or cloud synced) resources as it is to address remote resources.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://hookproductivity.com/help/integration/data-linkability-and-why-it-matters/"&gt;What’s a Linkable App and Why Does Linkability Matter? – Hook&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#walmart-and-autonomous-trucks---marginal-revolution" id="walmart-and-autonomous-trucks---marginal-revolution"&gt;&lt;/a&gt;Walmart and autonomous trucks - Marginal REVOLUTION&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Since last year, those trucks have been operating on a two-mile route between a “dark store” (a store that stocks items for fulfillment but isn’t open to the public) and a nearby Neighborhood Market in Bentonville, Arkansas. Since then, the vehicles have racked up 70,000 miles in autonomous mode with a safety driver.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I guess that future is here.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://marginalrevolution.com/marginalrevolution/2020/12/walmart-and-autonomous-trucks.html?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+marginalrevolution%2Ffeed+%28Marginal+Revolution%29"&gt;Walmart and autonomous trucks - Marginal REVOLUTION&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#by-the-numbers-a-year-and-half-with-atomic-css" id="by-the-numbers-a-year-and-half-with-atomic-css"&gt;&lt;/a&gt;By The Numbers: A Year and Half with Atomic CSS&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The results speak for themselves. Refactoring our CSS to the functional approach led to a 30% decrease in size. It could have been even smaller, but we left some legacy styles in place to refactor at a later time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://medium.com/@johnpolacek/by-the-numbers-a-year-and-half-with-atomic-css-39d75b1263b4"&gt;By The Numbers: A Year and Half with Atomic CSS&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#revised-blooms-taxonomy--center-for-excellence-in-learning-and-teaching--iowa-state-university" id="revised-blooms-taxonomy--center-for-excellence-in-learning-and-teaching--iowa-state-university"&gt;&lt;/a&gt;Revised Bloom’s Taxonomy • Center for Excellence in Learning and Teaching • Iowa State University&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The authors of the revised taxonomy underscore this dynamism, using verbs and gerunds to label their categories and subcategories (rather than the nouns of the original taxonomy). These “action words” describe the cognitive processes by which thinkers encounter and work with knowledge.&lt;/p&gt;
&lt;p&gt;A statement of a learning objective contains a verb (an action) and an object (usually a noun).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While this is generally fascinating, this has direct application for us productivity nerds: how we write project and to-do titles. I heard CGPGrey say on Cortex that it's good to phrase projects or to-dos in the past tense… some taxonomy like this could be helpful.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.celt.iastate.edu/teaching/effective-teaching-practices/revised-blooms-taxonomy/"&gt;Revised Bloom’s Taxonomy • Center for Excellence in Learning and Teaching • Iowa State University&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Wed, 23 Dec 2020 17:33:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/12/23/books-and-links-december/</guid></item><item><title>Lanham Lake Snowshoe</title><link>https://sam.hooke.me/trip/2020/12/lanham-lake-snowshoe/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;table class="stats-table"&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;th&gt;Distance&lt;/th&gt;
 &lt;th&gt;8.22 km / 5.11 miles&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Elevation gain&lt;/th&gt;
 &lt;th&gt;365 m / 1198 ft&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Duration&lt;/th&gt;
 &lt;th&gt;4h45m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Moving&lt;/th&gt;
 &lt;th&gt;2h20m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;No trip report yet.&lt;/p&gt;



 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/lanham-lake/pylons-1.jpg"&gt;
 
 &lt;img alt="A long clearing in the trees from the pylons." src="https://sam.hooke.me/images/trip/2020/lanham-lake/pylons-1_hu3089878376020231329.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Looking along the line of pylons.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/lanham-lake/pylons-2.jpg"&gt;
 
 &lt;img alt="The pylon base." src="https://sam.hooke.me/images/trip/2020/lanham-lake/pylons-2_hu10737508824006435058.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 A close look at the pylon base.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/lanham-lake/glare.jpg"&gt;
 
 &lt;img alt="A farewall glare from the sun over the frozen lake." src="https://sam.hooke.me/images/trip/2020/lanham-lake/glare_hu3482785290356470773.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Lanhm Lake with the sun just about to vanish.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/lanham-lake/trees.jpg"&gt;
 
 &lt;img alt="Lumps of snow in the forest." src="https://sam.hooke.me/images/trip/2020/lanham-lake/trees_hu16989686175309784953.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Snowy lumps amidst the trees.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/lanham-lake/logs.jpg"&gt;
 
 &lt;img alt="Lumps of snow in the forest." src="https://sam.hooke.me/images/trip/2020/lanham-lake/logs_hu4992234391054839697.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Snow logs amidst the trees.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;</description><author>Sam Hooke</author><pubDate>Wed, 23 Dec 2020 05:00:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/12/lanham-lake-snowshoe/</guid></item><item><title>An Annotated Guide to React Server Components</title><link>https://www.swyx.io/react-server-components-demo</link><description>React Server Components are a nuanced, sweeping addition to React's existing capabilities. This is my guide.</description><author>swyx's site RSS Feed</author><pubDate>Wed, 23 Dec 2020 03:18:46 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/react-server-components-demo</guid></item><item><title>2020 Recap</title><link>https://james.brooks.page/blog/2020-recap</link><description>I recap on what happened over the year of 2020.</description><author>James Brooks</author><pubDate>Wed, 23 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://james.brooks.page/blog/2020-recap</guid></item><item><title>2020 in review</title><link>https://jasoneckert.github.io/myblog/2020-in-review/</link><description>&lt;p&gt;&lt;img alt="Tech workers" src="techworkers.jpg#right" title="Tech workers" /&gt;&lt;/p&gt;
&lt;p&gt;I know what you&amp;rsquo;re thinking - 2020 sucked! Worst year ever! The COVID-19 pandemic, no social gatherings, no dine-in restaurants, no gyms, the US Trumpster fire, and most importantly to those of us in the tech world: Red Hat terminating CentOS development.&lt;/p&gt;
&lt;p&gt;Of course, most people will remember 2020 for the pandemic, and that&amp;rsquo;s completely understandable. None of us have experienced a pandemic in our lifetime, and both our society and economy were not prepared to deal with it gracefully. Many businesses folded or downsized, and the lack of social contact caused mental health issues for many people of all ages.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Wed, 23 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/2020-in-review/</guid></item><item><title>Hotwiring the Web: What does Basecamp's New Magic bring to the table?</title><link>https://davi.sh/blog/Hotwiring%20the%20Web/</link><description>&lt;p&gt;&lt;a href="https://hotwire.dev"&gt;Hotwire&lt;/a&gt;, which seems to be short for (H)tml
(O)ver (T)he (Wire), is a collection of frameworks just announced by
Basecamp that work together to help build “traditional”
server-rendered web applications that look and feel to users like
modern, Single-Page Applications (SPAs) built in React, Angular, Vue or
other frontend frameworks. &lt;a href="https://m.signalvnoise.com/html-over-the-wire/"&gt;Basecamp’s CTO put out a blog
post&lt;/a&gt; on why he believes
in Hotwire, but most of the justification seems to be handwavy claims
that JavaScript is inherently “complex,” never mind that Ruby’s
syntax and dynamic type system can be just as head-scratching to a
newcomer. I think that Basecamp’s built a really interesting tool, and
a better argument for Hotwire can be made by fully engaging with the
benefits that SPA “&lt;a href="https://www.computerhope.com/jargon/t/thickcli.htm"&gt;thick
clients&lt;/a&gt;” bring to
the table, their specific shortcomings, and all the different ways
framework developers are trying to address those shortcomings today.&lt;/p&gt;
&lt;h1 id="problems-with-web-application-development-today"&gt;Problems with Web Application Development Today&lt;/h1&gt;
&lt;p&gt;I want to separate “web app” development from general “web”
development, simply because most websites aren’t single-page
applications, or web apps in the sense we think of gmail, or
&lt;a href="https://hey.com"&gt;hey.com&lt;/a&gt;. It’s put most concisely in “&lt;a href="https://css-tricks.com/how-the-web-is-really-built/"&gt;How the Web
is Really Built&lt;/a&gt;”.
Here, though, I’ll be talking about that subset of the web which &lt;em&gt;can&lt;/em&gt;
be categorized more as an application than simply a web site.&lt;/p&gt;
&lt;p&gt;Building a web app is always going to be a complex endeavour. SPA view
libraries like React have emerged in the past five or so years as an
awesome way to handle that complexity on the client side, allowing
developers to build interactive user-interfaces in a composable way,
re-using components easily in different parts of the site.&lt;/p&gt;
&lt;h2 id="duplication-of-concerns"&gt;Duplication of Concerns&lt;/h2&gt;
&lt;p&gt;Generally, when building a React app, you get any dynamic data through a
loosely coupled JSON API (in my personal preference, probably written
with &lt;a href="https://www.django-rest-framework.org"&gt;Django REST Framework&lt;/a&gt;). If
you’re using a web framework like Django or Ruby on Rails, then you’re
going to have a lot of complexity and business logic on both the
frontend and backend. Whenever you add a feature, you need to ask
yourself where it should be added. The loose coupling between parts that
may very well be written in different languages means that it’s really
difficult to share code, and even if you’re doing something as simple
as validating a form, you’ll probably end up with a decent amount of
duplicated business logic, a big no-no if you follow the &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY
principle&lt;/a&gt;!&lt;/p&gt;
&lt;h2 id="data-fetching-boilerplate"&gt;Data Fetching Boilerplate&lt;/h2&gt;
&lt;p&gt;Loosely-coupled APIs present another challenge when building web apps:
the boilerplate that comes along with getting the data out of your
database and displayed in a browser. The general process for an SPA
follows this outline:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;[User] Navigates to a page, submits a form, or clicks on a
resource.&lt;/li&gt;
&lt;li&gt;[Browser] Send a request, along with any route parameters and
arguments, to a backend API endpoint.&lt;/li&gt;
&lt;li&gt;[Server] API endpoint is called, fetches data from the database
using the parameters in the request.&lt;/li&gt;
&lt;li&gt;[Server] After retrieving data from the database, marshal that
data into JSON to be sent back to the client.&lt;/li&gt;
&lt;li&gt;[Browser] Receive JSON from request, un-marshal the JSON into data
structures that the web app can understand. For a React app, this
would include passing the data as props to each component that uses
the data to for render itself.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that’s only the happy path! In the case of a validation error, for
example, the server would return a 400 response with some JSON details,
and the client again would need to catch that error, and render it
properly. It really is a lot of boilerplate for any given request.&lt;/p&gt;
&lt;p&gt;There are frontend libraries like &lt;a href="https://swr.vercel.app"&gt;SWR&lt;/a&gt; which
factor out as much boilerplate as possible and encourage declarative
patterns for your own data fetching, but “thick client” web apps will
always need to marshal data to JSON on the server, and un-marshal to
some view-able format on the client.&lt;/p&gt;
&lt;h1 id="managing-spa-complexity-in-2020"&gt;Managing SPA Complexity in 2020&lt;/h1&gt;
&lt;p&gt;There’s a bunch of different solutions to these problems for those who
still want to provide an SPA experience, and they fall broadly into two
separate categories.&lt;/p&gt;
&lt;h2 id="frontend-first-the-jamstack"&gt;Frontend-First: The JAMStack&lt;/h2&gt;
&lt;p&gt;In recent years, there’s been a big push towards the
&lt;a href="https://jamstack.org/what-is-jamstack/"&gt;JAMStack&lt;/a&gt;: pushing all your
complexity and business logic onto your frontend, and relying mostly on
commodified API services for your backend work. JSON is still the lingua
franca here, but reliance on pre-built backends as a service for
different functionalities, along with query languages like GraphQL,
means that there isn’t any backend boilerplate handled by developers.
All the complexity and business logic is pushed to the client-side,
which alleviates worries about duplication of concerns.&lt;/p&gt;
&lt;p&gt;JAMStack and associated “micro-backends” like
&lt;a href="https://auth0.com"&gt;Auth0&lt;/a&gt;, or “backends-as-a-service” like
&lt;a href="https://supabase.io"&gt;Supabase&lt;/a&gt; and &lt;a href="https://firebase.google.com"&gt;Google
Firebase&lt;/a&gt; allow people who haven’t done
too much backend work in the past to build truly full-stack apps on
their own. &lt;a href="https://m3o.com"&gt;m3o&lt;/a&gt; is even building a constellation of
JAMStack-oriented “micro-services” to provide the batteries to power
most web apps. Hmm… “batteries included”? Where
&lt;a href="https://www.phoenixframework.org"&gt;have&lt;/a&gt; we
&lt;a href="https://www.djangoproject.com"&gt;heard&lt;/a&gt; &lt;a href="https://laravel.com"&gt;that&lt;/a&gt;
&lt;a href="https://rubyonrails.org"&gt;before&lt;/a&gt;…&lt;/p&gt;
&lt;h2 id="backend-first-re-discovering-the-batteries"&gt;Backend-First: Re-discovering the batteries&lt;/h2&gt;
&lt;p&gt;MVC Frameworks like Django and Rails came about during the heyday of Web
2.0 to abstract away a lot of the boilerplate associated with building
CRUD web applications, the exact issues that we spoke about above. Back
in 2006, all those interactions were through normal browser HTTP
requests. SPAs, built with anything from
&lt;a href="https://backbonejs.org"&gt;Backbone&lt;/a&gt; or &lt;a href="https://emberjs.com"&gt;Ember&lt;/a&gt; to
React and Vue, were more responsive. These web frameworks became
frameworks for JSON API servers, and for many web app developers,
functionality like Django’s
&lt;a href="https://docs.djangoproject.com/en/3.1/ref/templates/"&gt;templates&lt;/a&gt; and
&lt;a href="https://docs.djangoproject.com/en/3.1/topics/forms/#more-about-django-form-classes"&gt;forms&lt;/a&gt;
and the battle-tested
&lt;a href="https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/"&gt;abstractions&lt;/a&gt;
for linking them together became vestiges of an earlier age. Django’s
&lt;code&gt;Form&lt;/code&gt;{.verbatim} classes can render validation errors in templates with
virtually no boilerplate written by developers. As soon as you want to
put that form action over a JSON API, any responses from your server,
which were previously just the HTML that the browser displayed, now have
to be un-marshalled from JSON on the client and handled specifically.
How much was Django really a “batteries included” framework if you
needed to pull in &lt;a href="https://www.django-rest-framework.org"&gt;REST
Framework&lt;/a&gt; and &lt;a href="https://github.com/jazzband/django-oauth-toolkit"&gt;OAuth
Toolkit&lt;/a&gt; whenever you
wanted to work with a “modern” frontend?&lt;/p&gt;
&lt;p&gt;Many people, myself included, enjoy modeling business logic in the ways
Django and its ilk allow for. Backend-first fullstack frameworks have
begun to proliferate built on top of these existing frameworks. &lt;a href="https://www.phoenixframework.org/blog/build-a-real-time-twitter-clone-in-15-minutes-with-live-view-and-phoenix-1-5"&gt;Phoenix
LiveView&lt;/a&gt;
and &lt;a href="https://laravel-livewire.com"&gt;Laravel Livewire&lt;/a&gt; are two that come
to mind immediately, and have been around for a year or more.&lt;/p&gt;
&lt;p&gt;On Monday, even the React Core team at Facebook threw their hat in the
ring, with their &lt;a href="https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html"&gt;Server
Components&lt;/a&gt;
that have the opportunity to allow for React components to be rendered
much like PHP templates, interspersing database calls and server-side
JavaScript with the layout description inside a server component’s
&lt;code&gt;render&lt;/code&gt;{.verbatim} function.&lt;/p&gt;
&lt;p&gt;These fullstack frameworks go a long way towards solving both of the
concerns with traditional SPAs listed above. Separation of concerns is
no longer an issue, since there is no separate, loosely coupled frontend
codebase. Data fetching is drastically simpler in this paradigm. No
longer does all your data need to be serialized to JSON before being
converted into HTML; your data-fetching flow looks a lot more like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;[User] Navigates to a page, submits a form, etc.&lt;/li&gt;
&lt;li&gt;[Server] Backend route is called, fetches/stores appropriate data
from the database based on the request.&lt;/li&gt;
&lt;li&gt;[Server] Data is used to populate an HTML template, which is sent
to the client and rendered with the help of the framework.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your backend business logic renders HTML directly, completely replacing
steps 3, 4 and 5 above with a single step: map your data into its visual
representation in HTML. The two server steps remaining &lt;em&gt;are&lt;/em&gt; the actual
business logic in your application: the full-stack framework handles the
smooth transitions, without the developer having to worry about
serializing and de-serializing their own data. The logical flow of your
application becomes a lot simpler for a single developer to follow and
to handle.&lt;/p&gt;
&lt;p&gt;Even React’s Server Components fit this new paradigm: Data fetching no
longer happens in AJAX requests, but by declaring a child server
component which fetches the data and displays it in its own DOM tree
without the developer having to serialize to/from JSON themselves. After
the component renders on the backend, its virtual DOM gets sent to the
frontend &lt;em&gt;by React itself&lt;/em&gt; for display. The developer’s interface into
this whole process remains high-level and declarative.&lt;/p&gt;
&lt;h2 id="as-the-pendulum-swings"&gt;As the Pendulum Swings&lt;/h2&gt;
&lt;p&gt;We started the decade with frameworks like
&lt;a href="https://www.meteor.com"&gt;Meteor.js&lt;/a&gt; with extremely tight couplings
between the client and server, and after a long time wandering in the
wilderness of duplicated compelxity across loosely-coupled frontend and
backend, it seems like we’re entering the twenties with a renewed push
towards a &lt;a href="https://m.signalvnoise.com/the-majestic-monolith/"&gt;more
monolithic&lt;/a&gt; approach
to web development. When even a frontend framework like React is
beginning to bridge the gap with the backend, you know it’s an
interesting idea to explore right now.&lt;/p&gt;
&lt;h1 id="so-what-is-hotwire"&gt;So what is Hotwire?&lt;/h1&gt;
&lt;p&gt;The folks at Basecamp, the company behind Hotwire, have always been
skeptical of thick clients with loads of JavaScript. Hotwire is
Basecamp’s latest answer to the challenge of building modern,
responsive, “snappy” single-page applications where the domain logic
lives entirely on the server. They used it to build out their new email
service, Hey.com.&lt;/p&gt;
&lt;p&gt;At Hotwire’s core is &lt;a href="https://turbo.hotwire.dev"&gt;Turbo&lt;/a&gt;, a new library
that takes HTML from AJAX requests and dynamically modifies the currrent
page. It comes out of an existing library called Turbolinks, now called
“&lt;a href="https://turbo.hotwire.dev/handbook/drive"&gt;Turbo Drive&lt;/a&gt;” as of today,
which is a utility that intercepts all click events on anchor tags,
loads the resources over AJAX, and swaps out the &lt;code&gt;&amp;#x3c;body&gt;&lt;/code&gt;{.verbatim}
tags, all while handling browser history.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://turbo.hotwire.dev/handbook/frames"&gt;Turbo Frames&lt;/a&gt;, one of the
new components, is pretty intriguing. Turbo Drive will still AJAX-ify
form submissions and link clicks behind the scenes, but instead of
swapping out the entire webpage each time, Turbo will look for matching
&lt;code&gt;&amp;#x3c;turbo-frame&gt;&lt;/code&gt;{.verbatim} tags on the current page and in the new
page’s content. If there’s a match, it’ll &lt;em&gt;dynamically replace that
section of the page&lt;/em&gt;. Basically, you can compose webpages together,
using &lt;code&gt;&amp;#x3c;turbo-frame&gt;&lt;/code&gt;{.verbatim} to delineate template partials as
scoped components, similarly to how you’d think of components in a
React app. The benefit here being that all the logic is handled on the
server-side rather than split between two code-bases.&lt;/p&gt;
&lt;h1 id="trying-out-hotwire-with-django"&gt;Trying out Hotwire with Django&lt;/h1&gt;
&lt;p&gt;What’s special about Turbo when compared to Phoenix LiveView and
Laravel Livewire is that Turbo is completely backend-agnostic: Drop the
JS bundle into a &lt;code&gt;&amp;#x3c;script&gt;&lt;/code&gt;{.verbatim} tag in your page’s
&lt;code&gt;&amp;#x3c;head&gt;&lt;/code&gt;{.verbatim}, and Turbo Drive works its magic without any
co-operation from the server. Turbo Frames can be adapted by wrapping
&lt;code&gt;&amp;#x3c;turbo-frame&gt;&lt;/code&gt;{.verbatim} tags around template partials in any backend
framework. &lt;a href="https://turbo.hotwire.dev/handbook/streams"&gt;Turbo Streams&lt;/a&gt;,
the solution for incremental data updates, can also be used in the
context of HTTP requests without any co-operation from the server beyond
modifying your template partials. It’s only if you want to use Turbo
Streams over WebSockets where you’ll need some custom code for your
specific backend framework.&lt;/p&gt;
&lt;p&gt;Since the push behind Hotwire came from DHH and Basecamp, it makes sense
that their examples are with Ruby on Rails, and that’s where they’ve
made their supporting libraries. I decided to take a shot at building a
demo app similar to what’s shown in Hotwire’s demo video using Django
rather than Rails. &lt;a href="https://github.com/davish/hotwire-django-demo-chat"&gt;It really didn’t take
long!&lt;/a&gt; I got my
start in Web Development with a JQuery app with a REST API, and even
after moving on to Django, I always used Django REST Framework. I never
really took advantage of the templating functionality, or the
super-useful built-in CRUD operations with Django forms. It was an
interesting experience working with &lt;code&gt;CreateView&lt;/code&gt;{.verbatim} and
&lt;code&gt;DetailView&lt;/code&gt;{.verbatim} rather than &lt;code&gt;ModelViewSet&lt;/code&gt;{.verbatim}, and I’ll
be excited to keep exploring this going forward.&lt;/p&gt;
&lt;p&gt;After an hour or so more of experimentation and digging into the
turbo-rails codebase, I got a working prototype of a Turbo Streams
&lt;code&gt;Broadcastable&lt;/code&gt;{.verbatim} mixin for Django! I’m working on &lt;a href="https://github.com/pennlabs/django-rest-live"&gt;something
similar for Django REST
Framework&lt;/a&gt; right now,
which definitely helped in hitting the ground running. I’ll probably
look to clean up the code and make sure it works for the other actions,
and split it out into its own pypi package.&lt;/p&gt;
&lt;p&gt;I’ll have to look at how the Rails integration handles authorization —
right now, anyone would be able to subscribe to any stream for a given
model, which is obviously not ideal for actual production applications.&lt;/p&gt;
&lt;p&gt;I was really surprised at how easy it was to set up Turbo to work
effectively with a Django backend. The chat app that I built was really
simple, but it also was just not many lines of code: not having to worry
about moving data around from the frontend to the backend really
decreased the amount of time spent on the implementation. Turbo though
is in a pretty early beta, and the one main thing I’d like to see be
addressed would be a good fallback mechanism for Turbo Streams over
websockets. Right now, if you want to broadcast updates over websockets,
then you can’t also send Turbo Streams in HTTP responses to form
actions without getting duplicate data appended. The solution in the
Hotwire demo video is simply to not send updates over HTTP, and only
stream over websockets. This doesn’t seem particularly robust, however,
in the case that a websocket connection fails or a client simply
doesn’t support it. In addition to the five actions, there should
probably be an &lt;code&gt;append-or-replace&lt;/code&gt;{.verbatim} action that looks for an
element with a matching &lt;code&gt;id&lt;/code&gt;{.verbatim}, performs a &lt;code&gt;replace&lt;/code&gt;{.verbatim}
action if one is found, and otherwise performs an &lt;code&gt;append&lt;/code&gt;{.verbatim}
action. The duplicate updates from the HTTP response and the websocket
stream wouldn’t conflict in that case, since one will append, and the
other will replace with identical data.&lt;/p&gt;
&lt;h2 id="closing-thoughts"&gt;Closing Thoughts&lt;/h2&gt;
&lt;p&gt;This is definitely an exciting time for frontend development! I’m
hoping to do some more experimentation in the coming weeks, and I’m
glad that framework authors accross the board are putting effort into
thinking about how to move the web app developer experience to the next
level.&lt;/p&gt;</description><author>Davis Haupt's Blog</author><pubDate>Wed, 23 Dec 2020 01:38:55 GMT</pubDate><guid isPermaLink="true">https://davi.sh/blog/Hotwiring%20the%20Web/</guid></item><item><title>Software will eat Hollywood, bringing two risks with it</title><link>https://stop.zona-m.net/2020/12/software-will-eat-hollywood-bringing-two-risks-with-it/</link><description>&lt;p&gt;Not everybody&amp;rsquo;s software, by the way. Not if things remain as today.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 22 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/software-will-eat-hollywood-bringing-two-risks-with-it/</guid></item><item><title>Indiehacking: a review of my 3rd year</title><link>https://maxrozen.com/indiehacking-3-year-review</link><description>A review of my third year of trying to start an internet business.</description><author>Max Rozen</author><pubDate>Tue, 22 Dec 2020 11:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/indiehacking-3-year-review</guid></item><item><title>Gold Creek Pond Snowshoe</title><link>https://sam.hooke.me/trip/2020/12/gold-creek-pond-snowshoe/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;table class="stats-table"&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;th&gt;Distance&lt;/th&gt;
 &lt;th&gt;5.87 km / 3.65 miles&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Elevation gain&lt;/th&gt;
 &lt;th&gt;34 m / 112 ft&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Duration&lt;/th&gt;
 &lt;th&gt;4h&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Moving&lt;/th&gt;
 &lt;th&gt;1h40m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;No trip report yet.&lt;/p&gt;



 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/gold-creek-pond/december/trail.jpg"&gt;
 
 &lt;img alt="A flat, snow covered trail lined with snowy pine trees." src="https://sam.hooke.me/images/trip/2020/gold-creek-pond/december/trail_hu1852191468952829238.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Following the trail from the trailhead to the lake.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/gold-creek-pond/december/bridge.jpg"&gt;
 
 &lt;img alt="A small wooden bridge deep in snow." src="https://sam.hooke.me/images/trip/2020/gold-creek-pond/december/bridge_hu1100405224742578549.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 The snow covered bridge at the north side of the lake.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/gold-creek-pond/december/lake.jpg"&gt;
 
 &lt;img alt="A frozen lake with an open flat area of snow in front with several groups of people, and snow covered mountains in the distance." src="https://sam.hooke.me/images/trip/2020/gold-creek-pond/december/lake_hu11783103834209037205.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 View of Gold Creek Pond from the south shore.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;</description><author>Sam Hooke</author><pubDate>Tue, 22 Dec 2020 04:30:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/12/gold-creek-pond-snowshoe/</guid></item><item><title>ADHD 🧠</title><link>https://klinger.io/posts/adhd-%F0%9F%A7%A0</link><description>I want to preface this by saying that I have only a mild case of ADHD, eg I don’t take any medication. I get regularly asked about...</description><author>Blog posts of Andreas Klinger</author><pubDate>Tue, 22 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://klinger.io/posts/adhd-%F0%9F%A7%A0</guid></item><item><title>Why broot switched to Hjson for its configuration files</title><link>https://dystroy.org/blog/hjson-in-broot/</link><description>&lt;p&gt;TOML was originally the only format for configuring broot.&lt;/p&gt;
&lt;p&gt;Here I explain why Hjson is now the preferred one.&lt;/p&gt;</description><author>dystroy|Canop / blog</author><pubDate>Tue, 22 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://dystroy.org/blog/hjson-in-broot/</guid></item><item><title>Tech salaries probably aren't dropping from remote work</title><link>https://ntietz.com/blog/salaries-probably-not-dropping-with-remote-work/?utm_source=atom&amp;utm_medium=feed</link><description>&lt;p&gt;Not even a year ago, most software companies and software engineers were some form of remote work skeptical. Remote work existed (I've been working remote for most of my admittedly short career!) but it was not widespread. When I talked to recruiters at big tech companies they would all insist that remote work was not feasible for them, and even at the companies I worked for, there was pushback that this definitely wouldn't work for us because &lt;em&gt;reasons&lt;/em&gt;. But now, I think we're seeing one of the real reasons people were skeptical:&lt;/p&gt;
&lt;p&gt;Money.&lt;/p&gt;
&lt;p&gt;There are lots of very real reasons to like colocation, and there is a lot that's hard about remote work. But I haven't seen a lot of discussion around the role of salaries in affecting whether or not people prefer remote work. Imagine this (and for some of you, this might be &lt;em&gt;really&lt;/em&gt; easy): you're working in New York or San Francisco, pulling down an absurdly high salary. You know that in the Midwest, salaries are much lower, not even comparing to other countries where salaries might be &lt;em&gt;much&lt;/em&gt; lower. In this situation, it seems pretty rational to oppose remote work. If you only allow colocation, then you're competing against other workers who all have the same cost of living as you and all have the same sky-high salary demands as you. But if you allow remote work, that great dev from Akron, Ohio might be willing to do the same job for less money. Right?&lt;/p&gt;
&lt;p&gt;Well... it isn't quite that simple. Right now, tech salaries have been going up consistently for a while (anecdotally, I've seen this as long as I've been here, so at least since 2013). This is consistent with demand for software engineers outpacing supply of them. Companies like Basecamp and Stripe are employing software engineers &lt;em&gt;anywhere&lt;/em&gt; at California rates. These companies aren't charities: they are doing it because they understand that, in the market conditions we have right now, to get the employees they need for their business to be successful, they have to pay those rates.&lt;/p&gt;
&lt;p&gt;Now the pool of software engineers who are available for remote work has expanded dramatically. So has the competition, as many companies are leaning into this advantage in hiring (including my employer) by looking for the &lt;em&gt;best&lt;/em&gt; talent, regardless of where it is. When you do that, you have to pay what the competition is willing to pay, and right now that's going to be... *checks watch*... a pretty high salary and good equity compensation.&lt;/p&gt;
&lt;p&gt;The gut check on this is to consider outsourcing to other countries. This has been a trope and fear as long as I've been aware of computers. For most of my life, people have been talking about how software development is all going to go overseas to whatever the current country of interest is: India, Russia, Ukraine, China... you hear people saying these countries with cheaper labor are going to eat our industry and we'll be out of jobs. Well, it hasn't happened. So why not? There are a few advantages to hiring an engineer in the US: you get someone who is on a compatible timezone (you could also get this in South America), who shares the same language, who has shared cultural touchpoints. And you're working within the local legal framework, which is easy: hiring across US state lines is harder than hiring in the same state, and hiring out of the country is harder than hiring within the same country. So it's just far more convenient to work with people who are in the same market, usually. But we &lt;em&gt;are&lt;/em&gt; hiring people globally, and many teams are distributed around the globe. The effect of that? It's buoying salaries everywhere. The countries which once had the cheapest labor have been getting wealthier and salaries have been rising, and before you know it, the labor arbitrare will be hardly worth it (if it even is now).&lt;/p&gt;
&lt;p&gt;So you can rest easy, probably: your tech salary is safe with remote work.&lt;/p&gt;
&lt;p&gt;But of course I'd say that, because I work remote and like my salary 😉. So make your own judgments, and take your and others' biases into account. From where I sit, it looks like remote work doesn't dramatically change the market forces that are keeping salaries up. I'd be more afraid of bootcamps (and maybe when those threaten our salaries, you'll see a sudden push for licensing to keep salaries up and add barriers to entry).&lt;/p&gt;</description><author>ntietz.com blog - technically a blog</author><pubDate>Tue, 22 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://ntietz.com/blog/salaries-probably-not-dropping-with-remote-work/?utm_source=atom&amp;utm_medium=feed</guid></item><item><title>ByteBuffer and the Dreaded NoSuchMethodError</title><link>https://www.morling.dev/blog/bytebuffer-and-the-dreaded-nosuchmethoderror/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_how_to_prevent_this_situation"&gt;How to Prevent This Situation?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The other day, a user in the &lt;a href="https://debezium.io/"&gt;Debezium&lt;/a&gt; community reported an interesting issue;
They were using Debezium with Java 1.8 and got an odd &lt;code&gt;NoSuchMethodError&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Mon, 21 Dec 2020 18:45:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/bytebuffer-and-the-dreaded-nosuchmethoderror/</guid></item><item><title>NO proprietary formats in Italy, please!</title><link>https://stop.zona-m.net/2020/12/no-proprietary-formats-in-italy-please/</link><description>&lt;p&gt;It&amp;rsquo;s so sad that this is still necessary&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 21 Dec 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/no-proprietary-formats-in-italy-please/</guid></item><item><title>Focus</title><link>https://one.mikro2nd.net/pages/focus/</link><description>Our days on this Earth are limited. Death is coming for us all. (Except maybe Bezos who is planning to upload his mind to AWS.) It behooves us, therefore, to spend what time we have on the things that:
matter interest us we are able to affect we have (or can attain) competence in Importance. Significance. Influence. Competence.
Needless to say there is a large dollop of subjectivity in judging these things, not to mention a high dose of personal preference, aptitude, inclination and Dunning-Kruger effect.</description><author>one mikro2nd</author><pubDate>Mon, 21 Dec 2020 15:54:58 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/focus/</guid></item><item><title>My Engineering Axioms</title><link>https://martinrue.com/my-engineering-axioms/</link><description>A few months back I gave a talk in which I shared a list of my personal engineering axioms – things that, over the years, I've come to think of as generally true and useful to have in mind when writing code, building things, and working with others.</description><author>Martin Rue</author><pubDate>Mon, 21 Dec 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://martinrue.com/my-engineering-axioms/</guid></item><item><title>Stop showing me ads on my TV player</title><link>https://blog.imraniqbal.org/ads-fire-tv/</link><description>&lt;p&gt;I am a huge fan of dumb TV's made smart via a TV player, something along the likes of an apple TV or a Roku.&lt;/p&gt;
&lt;p&gt;The first device that I owned was the first generation of a google chromecast.
It worked decently enough, but it would struggle when trying to play back some of the more higher definition media that I had.&lt;/p&gt;
&lt;p&gt;I upgraded from the chromecast to a Roku 3.
It worked splendidly for a while, up until they decided to take up half the home screen with a giant ad.
This pissed me off. I already paid around $100-ish dollars for the damn thing.
And now they want to shove ads down my throat.&lt;/p&gt;
&lt;p&gt;I then upgraded to an amazon fire TV. These things were not available in Canada so I had to order it from the states.
It came out to about $150 and also worked fine for a short period of time.
That is until, you guessed it, they started showing &lt;a href="https://advertising.amazon.com/en-ca/resources/ad-specs/fire-tv" rel="external"&gt;ads on the home screen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I am not against advertising and I understand why it exists and its use in free products.
The issue is that these things are not free (or cheap).
It sucks to pay for something and to have ads shown on top of that.
The shittier part is that ads are sometimes for amazon's own products like prime video or prime music.
I already have amazon prime. Why are you advertising these things to me?
I paid for the hardware and have a subscription on top of that. Why am I getting ads?
How much money is enough money?&lt;/p&gt;
&lt;p&gt;This pissed me off enough that I spent my evening trying to get rid of them.
&lt;a href="https://github.com/codefaktor/FTVLaunchX" rel="external"&gt;FTVLaunchX&lt;/a&gt; is an project that will let you set your launcher to anything else.
There's also &lt;a href="https://tv.aptoide.com/" rel="external"&gt;aptoide&lt;/a&gt; that's worth mentioning (install untrusted apps at your own risk).&lt;/p&gt;
&lt;p&gt;When I feel like spending some more money (yet again) for an ad free experience I will go for a vera from &lt;a href="https://osmc.tv/" rel="external"&gt;https://osmc.tv/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please for goodness sake, stop showing me ads on my TV streamer!
All I need you to do is stream content from my local network to my TV!
If you want to show me ads, at least let me get the hardware without paying, otherwise bugger off.&lt;/p&gt;</description><author>Imran's Blog</author><pubDate>Mon, 21 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.imraniqbal.org/ads-fire-tv/</guid></item><item><title>How to React to the Ledger Data Breach: 5 Recommendations</title><link>https://serhack.me/articles/how-to-react-data-breach-ledger/</link><description>If you think you are amongst the users affected by the latest &lt;a href="https://ledger.com"&gt;Ledger&lt;/a&gt; data breach, it is important &lt;strong&gt;not to panic!&lt;/strong&gt; Follow a few simple steps and you can check the extent of the damage and keep an eye on the security of your account. -&lt;a href="https://serhack.me/articles/how-to-react-data-breach-ledger/"&gt;Continue to read the article on SerHack.me&lt;/a&gt;</description><author>SerHack - Security Researcher</author><pubDate>Mon, 21 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://serhack.me/articles/how-to-react-data-breach-ledger/</guid></item><item><title>Blog Post Index</title><link>https://rob.sh/postindex/</link><description/><author>rob.sh</author><pubDate>Sun, 20 Dec 2020 21:47:06 GMT</pubDate><guid isPermaLink="true">https://rob.sh/postindex/</guid></item><item><title>40 Coolest neighbourhoods in the world</title><link>https://xenodium.com/40-coolest-neighborhoods-in-the-world</link><description>&lt;p&gt;Via TimeOut's &lt;a href="https://www.timeout.com/coolest-neighbourhoods-in-the-world"&gt;40 Coolest Neighbourhoods in the World Right Now&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Esquerra de l’Eixample, Barcelona&lt;/li&gt;
&lt;li&gt;Downtown, Los Angeles&lt;/li&gt;
&lt;li&gt;Sham Shui Po, Hong Kong&lt;/li&gt;
&lt;li&gt;Bedford-Stuyvesant, New York&lt;/li&gt;
&lt;li&gt;Yarraville, Melbourne&lt;/li&gt;
&lt;li&gt;Wedding, Berlin&lt;/li&gt;
&lt;li&gt;Shaanxi Bei Lu/Kangding Lu, Shanghai&lt;/li&gt;
&lt;li&gt;Dennistoun, Glasgow&lt;/li&gt;
&lt;li&gt;Haut-Marais, Paris&lt;/li&gt;
&lt;li&gt;Marrickville, Sydney&lt;/li&gt;
&lt;li&gt;Verdun, Montreal&lt;/li&gt;
&lt;li&gt;Kalamaja, Tallinn&lt;/li&gt;
&lt;li&gt;Hannam-dong, Seoul&lt;/li&gt;
&lt;li&gt;Bonfim, Porto&lt;/li&gt;
&lt;li&gt;Ghosttown, Oakland&lt;/li&gt;
&lt;li&gt;Chula-Samyan, Bangkok&lt;/li&gt;
&lt;li&gt;Alvalade, Lisbon&lt;/li&gt;
&lt;li&gt;Noord, Amsterdam&lt;/li&gt;
&lt;li&gt;Centro, São Paulo&lt;/li&gt;
&lt;li&gt;Holešovice, Prague&lt;/li&gt;
&lt;li&gt;Lavapiés, Madrid&lt;/li&gt;
&lt;li&gt;Opebi, Lagos&lt;/li&gt;
&lt;li&gt;Narvarte, Mexico City&lt;/li&gt;
&lt;li&gt;Uptown, Chicago&lt;/li&gt;
&lt;li&gt;Little Five Points, Atlanta&lt;/li&gt;
&lt;li&gt;Wynwood, Miami&lt;/li&gt;
&lt;li&gt;Phibsboro, Dublin&lt;/li&gt;
&lt;li&gt;Nørrebro, Copenhagen&lt;/li&gt;
&lt;li&gt;Bugis, Singapore&lt;/li&gt;
&lt;li&gt;Gongguan, Taipei&lt;/li&gt;
&lt;li&gt;Soho, London&lt;/li&gt;
&lt;li&gt;Binh Thanh, Ho Chi Minh City&lt;/li&gt;
&lt;li&gt;Melville, Johannesburg&lt;/li&gt;
&lt;li&gt;Kabutocho, Tokyo&lt;/li&gt;
&lt;li&gt;Porta Venezia, Milan&lt;/li&gt;
&lt;li&gt;Taman Paramount, Kuala Lumpur&lt;/li&gt;
&lt;li&gt;Allston, Boston&lt;/li&gt;
&lt;li&gt;Bandra West, Mumbai&lt;/li&gt;
&lt;li&gt;Arnavutköy, Istanbul&lt;/li&gt;
&lt;li&gt;Banjar Nagi, Ubud&lt;/li&gt;
&lt;/ol&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 20 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/40-coolest-neighborhoods-in-the-world</guid></item><item><title>Static analysis with semgrep: practical examples using Docker</title><link>http://notes.eatonphil.com/static-analysis-with-semgrep.html</link><description>&lt;p&gt;In this post we'll get a basic semgrep environment set up in Docker
running some custom rules against our code.&lt;/p&gt;
&lt;h3 id="existing-linters"&gt;Existing linters&lt;/h3&gt;&lt;p&gt;Linters like &lt;a href="https://www.pylint.org/"&gt;pylint&lt;/a&gt; for Python or
&lt;a href="https://eslint.org/"&gt;eslint&lt;/a&gt; for JavaScript are great for general,
broad language standards. But what about common nits in code review
like using print statements instead of a logger, or using a defer
statement inside a for loop (Go specific), or the existence of
multiple nested loops.&lt;/p&gt;
&lt;p&gt;Most developers don't have experience working with language
parsing. So it's fairly uncommon in small- and medium-sized teams to
see custom linting rules. And while no single linter or language is
that much more complex than the other (it's all just AST operations),
there is a small penalty to learning the AST and framework for each
language linter.&lt;/p&gt;
&lt;h3 id="semgrep"&gt;Semgrep&lt;/h3&gt;&lt;p&gt;&lt;a href="https://semgrep.dev/"&gt;Semgrep&lt;/a&gt; is a generic tool for finding patterns
in source code. Unlike traditional regex (and traditional grep) it can
find recursive patterns. This makes it especially useful as a tool to
learn for finding patterns in any language.&lt;/p&gt;
&lt;p&gt;An advantage of semgrep rules is that you can learn the semgrep
pattern matching syntax (which is surprisingly easy) and then you can
write rules for any language you'd like to write rules for.&lt;/p&gt;
&lt;p&gt;And while the &lt;a href="https://semgrep.dev/editor"&gt;online rule tester&lt;/a&gt; is
awesome, I had a hard time going from that to a working sample on my
own laptop with Docker. We'll do just that.&lt;/p&gt;
&lt;h3 id="catching-print-statements-in-python"&gt;Catching print statements in Python&lt;/h3&gt;&lt;p&gt;Let's say we want a script to fail on any use of print statements in
Python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;cat&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;simple&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DEBUG: here&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DEBUG: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;now here&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The current &lt;a href="https://semgrep.dev/editor"&gt;default example&lt;/a&gt; shown in the
online editor happens to be for just this. Click the Advanced tab and
you'll see the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fail-on-print&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;print(&amp;quot;...&amp;quot;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;Semgrep found a match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;WARNING&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Copy this into &lt;code&gt;config.yml&lt;/code&gt;. Let's modify the pattern to
warn on all print calls, not just print calls with a single string
argument:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fail-on-print&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;print(...)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;Semgrep found a match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;WARNING&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The editor doesn't mention it (nor do any docs I can find) but we also
need to include two keys in the individual rule
object: &lt;code&gt;mode&lt;/code&gt; and &lt;code&gt;languages&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fail-on-print&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;print(...)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;Semgrep found a match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;WARNING&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;generic&amp;quot;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Semgrep fails really weirdly if you set &lt;code&gt;mode&lt;/code&gt; to
anything other than &lt;code&gt;search&lt;/code&gt;, but it won't warn you that
what you set is garbage. The &lt;code&gt;languages&lt;/code&gt; setting is
similarly fickle and doesn't give you much feedback if you set it
incorrectly.&lt;/p&gt;
&lt;p class="note"&gt;
  Also, I'm using the "generic" language here because I don't
  understand the difference between languages and as far as I'm
  concerned the syntax I'm using here is already pretty generic.
&lt;/p&gt;&lt;p&gt;We run the semgrep Docker image:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:/src&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;returntocorp/semgrep&lt;span class="w"&gt; &lt;/span&gt;--config&lt;span class="o"&gt;=&lt;/span&gt;config.yml&lt;span class="w"&gt; &lt;/span&gt;test/python
A&lt;span class="w"&gt; &lt;/span&gt;new&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;Semgrep&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;available.&lt;span class="w"&gt; &lt;/span&gt;Please&lt;span class="w"&gt; &lt;/span&gt;see&lt;span class="w"&gt; &lt;/span&gt;https://github.com/returntocorp/semgrep#upgrading&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;more&lt;span class="w"&gt; &lt;/span&gt;information.
running&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules...
test/python/simple-print.py
severity:warning&lt;span class="w"&gt; &lt;/span&gt;rule:fail-on-print:&lt;span class="w"&gt; &lt;/span&gt;Semgrep&lt;span class="w"&gt; &lt;/span&gt;found&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;match

&lt;span class="m"&gt;2&lt;/span&gt;:print&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;DEBUG: here&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
ran&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;files:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;findings&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And there we've got our warning!&lt;/p&gt;
&lt;p class="note"&gt;
  Not completely clear to me why we're getting warned about a new
  version when we've pulled &lt;code&gt;latest&lt;/code&gt; as the linked docs
  suggest. Maybe there's a newer version that hasn't made it into a
  Docker image yet.
&lt;/p&gt;&lt;h3 id="catching-fmt.print*-statements-in-go"&gt;Catching fmt.Print* statements in Go&lt;/h3&gt;&lt;p&gt;Let's say we also want to fail on print statements in Go (because we
should use a logger instead):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;simple&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;here&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;My crazy error&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We could try to look for any &lt;code&gt;import "fmt"&lt;/code&gt; code in a file
but that would fail on uses of &lt;code&gt;fmt.Sprintf&lt;/code&gt;
or &lt;code&gt;fmt.Errorf&lt;/code&gt; which are fine. Instead we'll just focus on
uses of &lt;code&gt;fmt.Printf&lt;/code&gt; or &lt;code&gt;fmt.Println&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;$ cat go-config.yml&lt;/span&gt;
&lt;span class="l l-Scalar l-Scalar-Plain"&gt;rules&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fail-on-print&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;pattern-either&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fmt.Printf(...)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fmt.Println(...)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;Semgrep found a match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;WARNING&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;generic&amp;quot;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Run the Go config against the Go files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:/src&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;returntocorp/semgrep&lt;span class="w"&gt; &lt;/span&gt;--config&lt;span class="o"&gt;=&lt;/span&gt;go-config.yml&lt;span class="w"&gt; &lt;/span&gt;test/golang
A&lt;span class="w"&gt; &lt;/span&gt;new&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;Semgrep&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;available.&lt;span class="w"&gt; &lt;/span&gt;Please&lt;span class="w"&gt; &lt;/span&gt;see&lt;span class="w"&gt; &lt;/span&gt;https://github.com/returntocorp/semgrep#upgrading&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;more&lt;span class="w"&gt; &lt;/span&gt;information.
running&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules...
test/golang/simple-print.go
severity:warning&lt;span class="w"&gt; &lt;/span&gt;rule:fail-on-print:&lt;span class="w"&gt; &lt;/span&gt;Semgrep&lt;span class="w"&gt; &lt;/span&gt;found&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;match

&lt;span class="m"&gt;8&lt;/span&gt;:fmt.Printf&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%s\n&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="o"&gt;)&lt;/span&gt;
--------------------------------------------------------------------------------
&lt;span class="m"&gt;7&lt;/span&gt;:fmt.Println&lt;span class="o"&gt;(&lt;/span&gt;a&lt;span class="o"&gt;)&lt;/span&gt;
ran&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;files:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;findings
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool! Making some sense. Now let's try a harder pattern.&lt;/p&gt;
&lt;h3 id="catching-triple-nested-for-loops"&gt;Catching triple-nested for loops&lt;/h3&gt;&lt;p&gt;Let's try to warn on the triple-nested loop in this code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;loopy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;doneFirst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;going&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;going&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;doneFirst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we want to catch the use of nested for loops here then we'll need
to search for the loops surrounded by arbitrary
syntax. Semgrep's &lt;code&gt;...&lt;/code&gt; syntax makes this easy.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;$ cat go-config2.yml&lt;/span&gt;
&lt;span class="l l-Scalar l-Scalar-Plain"&gt;rules&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fail-on-3-loop&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;for ... {&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;for ... {&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;for ... {&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="no"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="no"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="no"&gt;Semgrep found a match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;WARNING&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;search&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;generic&amp;quot;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And run semgrep:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:/src&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;returntocorp/semgrep&lt;span class="w"&gt; &lt;/span&gt;--config&lt;span class="o"&gt;=&lt;/span&gt;go-config2.yml&lt;span class="w"&gt; &lt;/span&gt;test/golang
A&lt;span class="w"&gt; &lt;/span&gt;new&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;Semgrep&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;available.&lt;span class="w"&gt; &lt;/span&gt;Please&lt;span class="w"&gt; &lt;/span&gt;see&lt;span class="w"&gt; &lt;/span&gt;https://github.com/returntocorp/semgrep#upgrading&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;more&lt;span class="w"&gt; &lt;/span&gt;information.
running&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules...
test/golang/loopy.go
severity:warning&lt;span class="w"&gt; &lt;/span&gt;rule:fail-on-3-loop:&lt;span class="w"&gt; &lt;/span&gt;Semgrep&lt;span class="w"&gt; &lt;/span&gt;found&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;match

&lt;span class="m"&gt;7&lt;/span&gt;:for&lt;span class="w"&gt; &lt;/span&gt;i&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;i&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;i++&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="m"&gt;8&lt;/span&gt;:&lt;span class="w"&gt;              &lt;/span&gt;log.Print&lt;span class="o"&gt;(&lt;/span&gt;i&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="m"&gt;9&lt;/span&gt;:
&lt;span class="m"&gt;10&lt;/span&gt;:&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;j&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;j&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;j++&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="m"&gt;11&lt;/span&gt;:&lt;span class="w"&gt;                     &lt;/span&gt;c&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;i&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;j
&lt;span class="m"&gt;12&lt;/span&gt;:
&lt;span class="m"&gt;13&lt;/span&gt;:&lt;span class="w"&gt;                     &lt;/span&gt;going&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="m"&gt;14&lt;/span&gt;:&lt;span class="w"&gt;                     &lt;/span&gt;k&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="m"&gt;15&lt;/span&gt;:&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;going&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="m"&gt;16&lt;/span&gt;:&lt;span class="w"&gt;                             &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
--------&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;hid&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;additional&lt;span class="w"&gt; &lt;/span&gt;lines,&lt;span class="w"&gt; &lt;/span&gt;adjust&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;--max-lines-per-finding&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--------
ran&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;files:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;findings
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's just swell.&lt;/p&gt;
&lt;h3 id="limits-of-static-analysis"&gt;Limits of static analysis&lt;/h3&gt;&lt;p&gt;Now let's say we refactor one of the inner loops into its own
function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;loopy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;going&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;going&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;doneFirst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;doneFirst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And run semgrep again:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:/src&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;returntocorp/semgrep&lt;span class="w"&gt; &lt;/span&gt;--config&lt;span class="o"&gt;=&lt;/span&gt;go-config2.yml&lt;span class="w"&gt; &lt;/span&gt;test/golang
&lt;span class="w"&gt; &lt;/span&gt;A&lt;span class="w"&gt; &lt;/span&gt;new&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;Semgrep&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;available.&lt;span class="w"&gt; &lt;/span&gt;Please&lt;span class="w"&gt; &lt;/span&gt;see&lt;span class="w"&gt; &lt;/span&gt;https://github.com/returntocorp/semgrep#upgrading&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;more&lt;span class="w"&gt; &lt;/span&gt;information.
&lt;span class="w"&gt; &lt;/span&gt;running&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules...
&lt;span class="w"&gt; &lt;/span&gt;ran&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rules&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;files:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;findings
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well great. The 3-nested loop still exists but we can't find it
anymore because it's not syntactically obvious anymore.&lt;/p&gt;
&lt;p&gt;At this point we'd need to start getting into linting based on runtime
analysis. If you know of a tool that does this and lets you write
rules like semgrep for it, please tell me!&lt;/p&gt;
&lt;h3 id="in-summary"&gt;In summary&lt;/h3&gt;&lt;p&gt;In the end though, it's still very useful to be able to learn a single
language for writing syntax rules at a high level to enforce behavior
in code. Furthermore, a generic syntax matcher helps you write easily
write rules for things that don't already have linters like YAML
or JSON configuration or Vagrantfiles.&lt;/p&gt;
&lt;p&gt;It can be annoying to work around some missing docs in semgrep but
overall it's a great tool for the kit.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;&lt;a href="https://twitter.com/hashtag/semgrep?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#semgrep&lt;/a&gt; is a really neat tool for syntactic analysis. Here are a few simple examples (catch print statements, triple nested loops, etc.) using Docker. Includes some necessary info the docs don't get into&lt;a href="https://t.co/UDHEH5JmOa"&gt;https://t.co/UDHEH5JmOa&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1340785372364738562?ref_src=twsrc%5Etfw"&gt;December 20, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 20 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/static-analysis-with-semgrep.html</guid></item><item><title>Sad follow-up on that small problem with e-voting in Italy</title><link>https://stop.zona-m.net/2020/12/sad-follow-up-on-that-small-problem-with-e-voting-in-italy/</link><description>&lt;p&gt;Sad news, indeed.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sun, 20 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/sad-follow-up-on-that-small-problem-with-e-voting-in-italy/</guid></item><item><title>2010 Prius Microphone</title><link>https://andrewferguson.net/2020/12/19/2010-prius-microphone/</link><description>This is an update to Notes on Installing Sony XAV-AX100 in a 2010 Prius, specifically trying to integrate the factory microphone. Unfortunately, the microphone is pre-amplified with what I believe to be a New Japan Radio Co. 2140 Op-Amp (the black IC in the middle on front side, pin 1 is upper left corner). When&amp;#8230;&amp;#160;&lt;a class="" href="https://andrewferguson.net/2020/12/19/2010-prius-microphone/" rel="bookmark"&gt;Read More &amp;#187;&lt;span class="screen-reader-text"&gt;2010 Prius Microphone&lt;/span&gt;&lt;/a&gt;</description><author>Andrew Ferguson dot NET</author><pubDate>Sat, 19 Dec 2020 22:12:14 GMT</pubDate><guid isPermaLink="true">https://andrewferguson.net/2020/12/19/2010-prius-microphone/</guid></item><item><title>How to find a missing Sonos</title><link>https://ilearnt.com/blog/findingamissingsonos/</link><description>&lt;p&gt;We recently purchased a Sonos Beam and hooked it up to 2 Sonos Play Ones we already had. It works really well and we are really pleased with it. We expected to mostly use it with the TV but have found ourselves using it more and more to play music. However every few days the Sonos app seems to lose the setup. The TV still works with it but the application does not show the system - this is very frustrating.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sat, 19 Dec 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/findingamissingsonos/</guid></item><item><title>Changes - Ending 2020</title><link>https://blog.herlein.com/post/ending-2020/</link><description>&lt;p&gt;As 2020 thankfully winds down, I leave Cisco and join AWS.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 19 Dec 2020 10:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/ending-2020/</guid></item><item><title>Programming Serial in C</title><link>https://blog.herlein.com/post/serial/</link><description>&lt;p&gt;It&amp;rsquo;s back to the future again.  Fidding with node.js a lot, but you know, C is still my favorite language.  Dug up some old code to read/write from a serial port.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 19 Dec 2020 10:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/serial/</guid></item><item><title>JavaScript Objects Cachification</title><link>https://www.alexanderlolis.com/javascript-objects-cachification</link><description>Wrapping your JavaScript Objects with caching capabilities</description><author>Alexander's Blog Blog</author><pubDate>Sat, 19 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.alexanderlolis.com/javascript-objects-cachification</guid></item><item><title>13 random reasons why i still use atom</title><link>https://thatxliner.github.io/posts/13-random-reasons-why-i-still-use-atom/</link><description>Just a little rant/vent.</description><author>ThatXliner's Blog</author><pubDate>Sat, 19 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://thatxliner.github.io/posts/13-random-reasons-why-i-still-use-atom/</guid></item><item><title>2020–12–19: Away from keyboard for the rest of the month</title><link>https://xnux.eu/log/#030</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 19 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#030</guid></item><item><title>How to Design Almost Any Backend and Deploy It to AWS with No Code</title><link>https://www.swyx.io/design-and-deploy-backend-with-amplify-sandbox</link><description>With the Amplify Sandbox, it is really easy to model and think through any app backend scenario</description><author>swyx's site RSS Feed</author><pubDate>Fri, 18 Dec 2020 21:42:48 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/design-and-deploy-backend-with-amplify-sandbox</guid></item><item><title>The Big Tech Model</title><link>https://stop.zona-m.net/2020/12/the-big-tech-model/</link><description>&lt;p&gt;Knowing exactly how they harm you is the first step of liberation.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 18 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/the-big-tech-model/</guid></item><item><title>Sheffield Is The New Derby; Also Arsenal</title><link>https://rjp.is/blogging/posts/2020/12/sheffield-the-new-derby/</link><description>In which we make dire predictions.</description><author>infrequent oscillations</author><pubDate>Fri, 18 Dec 2020 12:20:42 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/12/sheffield-the-new-derby/</guid></item><item><title>Visiting the United Kingdom</title><link>https://ben.bolte.cc/posts/2020-12-18-united-kingdom</link><description>Reflections on our time in the United Kingdom during the Covid-19 pandemic.</description><author>Ben Bolte</author><pubDate>Fri, 18 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://ben.bolte.cc/posts/2020-12-18-united-kingdom</guid></item><item><title>Convos: A Persistent Self-Hosted Web Client for IRC</title><link>https://serhack.me/articles/convos-web-client-persistent-irc/</link><description>Throughout 2020, in large part due to the lockdown, many people have started to become familiar with internal communication tools. Microsoft Teams, Slack, Telegram, Mattermost, and a few others are the most widely used and recognizable of these tools, but there still seems to be some people using Internet Relay Chat (IRC) ― one of the first online messaging services. -&lt;a href="https://serhack.me/articles/convos-web-client-persistent-irc/"&gt;Continue to read the article on SerHack.me&lt;/a&gt;</description><author>SerHack - Security Researcher</author><pubDate>Fri, 18 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://serhack.me/articles/convos-web-client-persistent-irc/</guid></item><item><title>The Mom Test: How to talk to customers &amp;amp; learn if your business is a good idea when everyone is lying to you</title><link>https://olshansky.info/book/the_mom_test/</link><description>Olshansky's review of The Mom Test: How to talk to customers &amp;amp; learn if your business is a good idea when everyone is lying to you by Rob Fitzpatrick</description><author>🦉 olshansky 🦁</author><pubDate>Fri, 18 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/the_mom_test/</guid></item><item><title>Perceived age velocity. Or: Why every year is getting shorter</title><link>https://nutcroft.mataroa.blog/blog/perceived-age-velocity-or-why-every-year-is-getting-shorter/</link><description>&lt;p&gt;Time is scary.&lt;/p&gt;
&lt;p&gt;Everybody is afraid they will grow old. Even if death was not on the menu, being non-young is not fun. Fatigue, fragility, lack of agility.&lt;/p&gt;
&lt;p&gt;In this quest of fear facing one could turn to stoicism. One of the arcane techniques of this resurgent philosophy is negative visualization. One could imagine they are old and wary and experience it in their imagination, which will then—presumably—cause them to make peace with it. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every year is getting shorter, never seem to find the time.&lt;br /&gt;
– &lt;cite&gt;&lt;a href="http://www.pink-floyd-lyrics.com/html/time-dark-lyrics.html"&gt;Pink Floyd&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But spooky time has another trick. Getting older feels faster &lt;em&gt;as&lt;/em&gt; one grows older. As if the older one gets, the faster time passes. &lt;/p&gt;
&lt;p&gt;This is completely expected, a time scientist would say a posteriori. When one is 10 years old, a new year would include 1/10th of their memories. When they would be 11 years old, the last year would comprise 10%&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; of their lives. However, when one is 50 years old, a new year would comprise 1/50th, which is 2% of new memories when measured in time&lt;sup id="fnref2:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Of course, then, it feels that time speeds up. Every new year will always be smaller as the already lived memories will only keep growing. &lt;/p&gt;
&lt;p&gt;Which brings a second negativity to visualise for the stoic response: one should also assume that the next year will go by even faster than the previous one.&lt;/p&gt;
&lt;p&gt;Wicked.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Assuming they remember everything since birth.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>nutcroft</author><pubDate>Fri, 18 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/perceived-age-velocity-or-why-every-year-is-getting-shorter/</guid></item><item><title>Quote 94</title><link>https://www.wints.org/quotes/94/</link><description>&lt;p&gt;Yesterday I was clever, so I wanted to change the world. Today I am wise, so I am changing myself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Rumi&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Fri, 18 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/94/</guid></item><item><title>Setting up Matomo in such a way to bypass adblockers</title><link>https://jonlu.ca/posts/matomo-bypass</link><description>Configuring self-hosted Matomo analytics behind custom routes and POST tracking.</description><author>JonLuca's Blog</author><pubDate>Thu, 17 Dec 2020 21:10:04 GMT</pubDate><guid isPermaLink="true">https://jonlu.ca/posts/matomo-bypass</guid></item><item><title>Product-Market Fit is Lindy</title><link>https://whoisnnamdi.com/product-market-fit-is-lindy/</link><description>The longer you search for product-market fit, the less likely you will find it.</description><author>Who is Nnamdi?</author><pubDate>Thu, 17 Dec 2020 20:20:27 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/product-market-fit-is-lindy/</guid></item><item><title>What THIS "Google Down" put in full view</title><link>https://stop.zona-m.net/2020/12/what-this-google-down-put-in-full-view/</link><description>&lt;p&gt;Google is like the One Ring of Sauron.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 17 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/what-this-google-down-put-in-full-view/</guid></item><item><title>Siamese Neural Networks (Video)</title><link>https://blog.lukesalamone.com/posts/siamese-nn-video/</link><description>&lt;div style="text-align: center;"&gt;
  
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;The following is a transcript of the above video&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In this paper, the authors present a novel neural network architecture to enable audio search via sounds humans are able to make, for example humming and whistling. This is an important capability when searching through audio for a specific sound.&lt;/p&gt;
&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Imagine you have hundreds of unlabeled sound effects on your computer, and you are looking for a specific one. It could be very tedious to listen to every single one until you can find the right sound. Even if the sounds do have some kind of word labels, it could be hard to pinpoint exactly which words to search for. A lot of sounds don’t exactly lend themselves to text descriptors, so finding the right sound can be difficult with a text search.&lt;/p&gt;</description><author>Luke Salamone's Blog</author><pubDate>Thu, 17 Dec 2020 19:22:43 GMT</pubDate><guid isPermaLink="true">https://blog.lukesalamone.com/posts/siamese-nn-video/</guid></item><item><title>Joshua Tree, 2020</title><link>https://faingezicht.com/photos/2020/12/17/jt20/</link><description>In November, we rented a house in Indio with our friends, and drove down to Southern California. Oddly, I didn't take any photos at the house, but I took a bunch on the couple of trips we did into Joshua Tree National Park that week.</description><author>Avy Faingezicht</author><pubDate>Thu, 17 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/photos/2020/12/17/jt20/</guid></item><item><title>How Changing One Sentence led to 2.5x more Reviews</title><link>https://www.wints.org/blog/2020.12.17/</link><description>&lt;p&gt;&lt;strong&gt;&lt;u&gt;June 2019&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;
Fifteen years in business and we had a measly three reviews on Google.&lt;/p&gt;
&lt;p&gt;Sigh.&lt;/p&gt;
&lt;p&gt;I reminded myself that this is &lt;em&gt;exactly&lt;/em&gt; why I moved back from the Bay area to work on the family business &amp;ndash; to use technology to expand. Let&amp;rsquo;s fix this!&lt;/p&gt;
&lt;div class="text-center my-3"&gt;
&lt;img alt="Stoneland Reviews December 2019" class="img-fluid" src="https://www.wints.org/img/articles/2020.12.17/2.stoneland-reviews-dec-2019.jpg" /&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;rsquo;d read somewhere that people are most willing to review right after their experience &amp;ndash; good or bad.
I&amp;rsquo;d been itching to use Twilio, and this was the perfect use case!
Our inside sales person saves a visitor&amp;rsquo;s contact information right after a visitor leaves. Their phone number is included in this.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Thu, 17 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/blog/2020.12.17/</guid></item><item><title>This election and the insanity of betting markets</title><link>https://www.attejuvonen.fi/trump-biden-betting-markets/</link><description>If you were following the 2020 U.S. presidential election, you might remember the barrage of ”experts” offering predictions on the outcome…</description><author>TODO</author><pubDate>Thu, 17 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.attejuvonen.fi/trump-biden-betting-markets/</guid></item><item><title>Making statistics lie for the 2020 Presidential election</title><link>https://bytepawn.com/making-statistics-lie-for-the-2020-presidential-election.html</link><description>&lt;p&gt;After the 2020 US presidential election, the Trump campaign filed over 50 lawsuits and attacked the integrity of the elections by claiming there was voter fraud. One of the last lawsuits was filed in the Supreme Court of the United States by the state of Texas. Here I look at the statistical claims made in this lawsuit that were supposed to show irregularities in the Georgia vote.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Trump vs Biden" src="/images/trump-biden.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Thu, 17 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/making-statistics-lie-for-the-2020-presidential-election.html</guid></item><item><title>A key finding from OSOR's report on Open Source</title><link>https://stop.zona-m.net/2020/12/a-key-finding-from-osors-report-on-open-source/</link><description>&lt;p&gt;Here is a curve that must not flatten!&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 16 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/a-key-finding-from-osors-report-on-open-source/</guid></item><item><title>Towards Continuous Performance Regression Testing</title><link>https://www.morling.dev/blog/towards-continuous-performance-regression-testing/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_getting_started_with_jfrunit"&gt;Getting Started With JfrUnit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_case_study_1_spotting_increased_memory_allocation"&gt;Case Study 1: Spotting Increased Memory Allocation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_case_study_2_identifying_increased_io_with_the_database"&gt;Case Study 2: Identifying Increased I/O With the Database&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_discussion"&gt;Discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_summary_and_outlook"&gt;Summary and Outlook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Functional unit and integration tests are a standard tool of any software development organization,
helping not only to ensure correctness of newly implemented code,
but also to identify regressions — bugs in existing functionality introduced by a code change.
The situation looks different though when it comes to regressions related to non-functional requirements, in particular performance-related ones:
How to detect increased response times in a web application?
How to identify decreased throughput?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;These aspects are typically hard to test in an automated and reliable way in the development workflow,
as they are dependent on the underlying hardware and the workload of an application.
For instance assertions on the duration of specific requests of a web application typically cannot be run in a meaningful way on a developer laptop,
which differs from the actual production hardware
(ironically, nowadays both is an option, the developer laptop being less or more powerful than the actual production environment).
When run in a virtualized or containerized CI environment, such tests are prone to severe measurement distortions due to concurrent load of other applications and jobs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This post introduces the &lt;a href="https://github.com/gunnarmorling/jfrunit"&gt;JfrUnit&lt;/a&gt; open-source project, which offers a fresh angle to this topic by supporting assertions not on metrics like latency/throughput themselves, but on &lt;em&gt;indirect metrics&lt;/em&gt; which may impact those.
JfrUnit allows you define expected values for metrics such as memory allocation, database I/O, or number of executed SQL statements, for a given workload and asserts the actual metrics values — which are obtained from &lt;a href="https://openjdk.java.net/jeps/328"&gt;JDK Flight Recorder&lt;/a&gt; events — against these expected values.
Starting off from a defined base line, future failures of such assertions are an indicator for potential performance regressions in an application, as a code change may have introduced higher GC pressure,
the retrieval of unneccessary data from the database, or SQL problems commonly induced by ORM tools, like N+1 SELECT statements.&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Wed, 16 Dec 2020 18:45:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/towards-continuous-performance-regression-testing/</guid></item><item><title>Personal news, 2020 edition</title><link>https://blog.separateconcerns.com/2020-12-16-personal-news.html</link><description>&lt;p&gt;I haven’t posted anything here for 6 months so I thought it would be a good idea to post a personal news update before the end of 2020.&lt;/p&gt;
&lt;section id="Shutting-down-Chilli"&gt;
&lt;h2&gt;Shutting down Chilli&lt;/h2&gt;
&lt;p&gt;I haven’t posted about it here yet, but my co-founder Julien and me decided to shut down &lt;a href="https://blog.separateconcerns.com/2019-04-23-spicing-things-up.html"&gt;Chilli&lt;/a&gt; at the end of last year, in agreement with eFounders. Basically, some of our initial hypotheses about the state of the market we were in (french SMBs) were wrong and the business couldn’t be profitable enough.&lt;/p&gt;
&lt;p&gt;In retrospect, it was an interesting experience. I really appreciated being part of &lt;a href="https://www.efounders.com"&gt;eFounders&lt;/a&gt;, I do recommend it for people who want to start a B2B SaaS company.&lt;/p&gt;
&lt;p&gt;However, I wanted to get out of my comfort bubble too much with this one, by tackling a problem in a market I didn’t know. Because of that, I had to rely on others regarding core business choices, and while that was fine with me initially it ended up being frustrating in the end when things didn’t work well and I couldn’t help much. So if I start another company someday, it will be one where I know the problem domain better.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="Joining-Inch"&gt;
&lt;h2&gt;Joining Inch&lt;/h2&gt;
&lt;p&gt;After we shut down Chilli, I decided to join a small startup editing a SaaS CRM and ticketing solution for property managers called &lt;a href="https://inch.fr"&gt;Inch&lt;/a&gt;, only available in the French market for now.&lt;/p&gt;
&lt;p&gt;I didn’t pick Inch randomly, I have known one of the founders for years since he was a &lt;a href="https://blog.separateconcerns.com/2013-06-20-three-years-proprietary-projects.html"&gt;Moodstocks&lt;/a&gt; user! Fun fact: at the time, I had met him and he was looking for a technical co-founder for &lt;a href="https://fr-fr.facebook.com/Qrators/"&gt;his project&lt;/a&gt;. I told him he should learn to code instead and gave him Ruby sample code… and this is why I am back to Rails today. Karma? :)&lt;/p&gt;
&lt;p&gt;Anyway, I had been following Inch with interest since its creation, because it is the company I like: solving a real need in a market where tools were either terrible or non-existent. Now they have a unique place in the market and some interesting technical challenges to solve, so I decided to join and help.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="Starting-a-family"&gt;
&lt;h2&gt;Starting a family&lt;/h2&gt;
&lt;p&gt;And here comes the last piece of news: despite all the madness that happened this year, the biggest change for me is that I am now a father! My son was born last week, and I took a holiday until the end of the year to spend time with him and his mother. I don’t intend to post too much personal news here, but this one deserved it. =)&lt;/p&gt;
&lt;/section&gt;</description><author>Separate Concerns</author><pubDate>Wed, 16 Dec 2020 14:50:00 GMT</pubDate><guid isPermaLink="true">https://blog.separateconcerns.com/2020-12-16-personal-news.html</guid></item><item><title>Fix bin/magento taking all the RAM</title><link>https://bfontaine.net/2020/12/16/fix-bin-magento-all-the-ram/</link><description>&lt;p&gt;While working with Magento 2.3.6 on &lt;a href="https://bixoto.com/"&gt;Bixoto&lt;/a&gt; I hit a weird issue: the
&lt;code class="language-plaintext highlighter-rouge"&gt;bin/magento&lt;/code&gt; command-line tool was always eating all the RAM, even with a simple command:&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ ./bin/magento --help
PHP Fatal error:  Allowed memory size of 2147483648 bytes exhausted (tried to allocate 262144 bytes) in /home/baptiste/.../vendor/magento/module-store/Model/Config/Placeholder.php on line 146
Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The issue, as weird as it sounds, is an empty configuration value that causes Magento to end up in
an infinite loop.&lt;/p&gt;

&lt;p&gt;When I installed Magento on my local machine, I deactivated HTTPS by setting &lt;code class="language-plaintext highlighter-rouge"&gt;web/secure/base_url&lt;/code&gt;
to &lt;code class="language-plaintext highlighter-rouge"&gt;NULL&lt;/code&gt; in the table &lt;code class="language-plaintext highlighter-rouge"&gt;core_config_data&lt;/code&gt;. This alone is the cause of the issue.&lt;/p&gt;

&lt;p&gt;Check in MySQL:&lt;/p&gt;

&lt;div class="language-sql highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;core_config_data&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'web/secure/base_url'&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If this shows a line with a &lt;code class="language-plaintext highlighter-rouge"&gt;NULL&lt;/code&gt; value, either delete it or replace it with some non-null value:&lt;/p&gt;

&lt;div class="language-sql highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;core_config_data&lt;/span&gt; &lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'http://...'&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'web/secure/base_url'&lt;/span&gt; &lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This has been &lt;a href="https://github.com/magento/magento2/issues/12835"&gt;reported to Magento&lt;/a&gt; but was closed because “it’s not a bug”. I don’t think
falling in an infinite loop on &lt;code class="language-plaintext highlighter-rouge"&gt;--help&lt;/code&gt; because some config value is &lt;code class="language-plaintext highlighter-rouge"&gt;NULL&lt;/code&gt; should really be a
normal behavior, but at least now you know how to solve it.&lt;/p&gt;</description><author>Baptiste Fontaine’s Blog</author><pubDate>Wed, 16 Dec 2020 13:08:00 GMT</pubDate><guid isPermaLink="true">https://bfontaine.net/2020/12/16/fix-bin-magento-all-the-ram/</guid></item><item><title>ImageMagick on Azure Functions for Linux with Node.js</title><link>https://blog.kaetemi.be/2020/12/15/imagemagick-on-azure-functions-for-linux-with-nodejs/</link><description>Since you cannot install any additional dependencies on function instances, you have to include any missing tools, that you need, as static binaries in your deployment. To prepare a static...</description><author>Kaetemi</author><pubDate>Tue, 15 Dec 2020 23:46:37 GMT</pubDate><guid isPermaLink="true">https://blog.kaetemi.be/2020/12/15/imagemagick-on-azure-functions-for-linux-with-nodejs/</guid></item><item><title>Why You Should Pre-Sell</title><link>https://www.swyx.io/pre-sell</link><description>My thoughts on preselling, from having done it successfully exactly one time.</description><author>swyx's site RSS Feed</author><pubDate>Tue, 15 Dec 2020 20:00:25 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/pre-sell</guid></item><item><title>VM Port Forwarding</title><link>https://geo.rocks/post/vm-port-forwarding/</link><description>&lt;p&gt;&lt;img alt="Port Forwarding" src="https://geo.rocks/img/port-forwarding-vm.jpg" title="Port Forwarding" /&gt;
Port Forwarding in Virtual Box - Postgres example&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Tue, 15 Dec 2020 17:55:03 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/vm-port-forwarding/</guid></item><item><title>The Stop! 2020-2021 fundraiser</title><link>https://stop.zona-m.net/christmas-2020-fundraising/</link><description>&lt;p&gt;Important request/Public Service Announcement:&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 15 Dec 2020 12:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/christmas-2020-fundraising/</guid></item><item><title>Guidelines for developing Custom Hooks in React</title><link>https://maxrozen.com/guidelines-for-developing-custom-hooks-react</link><description>You've just gotten over the fact we call them 'Hooks', but how do you stop repeating the same code everywhere? Let's learn about Custom Hooks.</description><author>Max Rozen</author><pubDate>Tue, 15 Dec 2020 11:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/guidelines-for-developing-custom-hooks-react</guid></item><item><title>Automatic Newsletter Using Drafts</title><link>http://evantravers.com/articles/2020/12/15/automatic-newsletter-using-drafts/</link><description>&lt;p&gt;In my &lt;a href="http://evantravers.com/articles/2020/11/07/day-of-automation/"&gt;day of automation&lt;/a&gt; post I mentioned a simple newsletter automation. It's grown since then. Some background:&lt;/p&gt;
&lt;p&gt;A year ago, we were using Monday.com to post status updates on hard-to-see work streams for executives. Monday.com didn't catch on, but I thought there was value in having a historical log that stakeholders could check to stay current.&lt;/p&gt;
&lt;p&gt;In addition, I spammed links to &amp;quot;good to read&amp;quot; blog posts in Slack… at all hours of the day. This was an excusable habit when I was just a colleague, once I became a manager I realized that it was &lt;em&gt;very&lt;/em&gt; disruptive. 🤦&lt;/p&gt;
&lt;p&gt;I started using the blog system in Confluence for both the stakeholder statuses and collect all my links and commentary for the week. At first I manually typed up each &amp;quot;issue,&amp;quot; occasionally copy/pasting the format of the previous week's entry, and finding links out of Instapaper's archive and making commentary by hand. Like an &lt;em&gt;animal&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Until now.&lt;/p&gt;
&lt;p&gt;As I read throughout my week, I save little snippets using &lt;a href="http://evantravers.com/articles/2020/06/11/hammerspoon-automating-airpods-and-brave-browser/"&gt;my snip tool in Hammerspoon&lt;/a&gt; or the Share API on iOS, and tag them &lt;code&gt;link&lt;/code&gt; and &lt;code&gt;dayjob&lt;/code&gt;. This forms the a queue of the links to share.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/12/things-nag.png" /&gt;&lt;/p&gt;
&lt;p&gt;On Monday I'm greeted by a prompt in my Task Manager with a URLscheme link to Drafts that runs the following action:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-javascript" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;let&lt;/span&gt; &lt;span&gt;template&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;Draft&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;uuid-of-my-template-draft&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;let&lt;/span&gt; &lt;span&gt;today&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; &lt;span&gt;Date&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;let&lt;/span&gt; &lt;span&gt;week_ago&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;today&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;getDate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;-&lt;/span&gt; &lt;span&gt;7&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;let&lt;/span&gt; &lt;span&gt;workspace&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;Workspace&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Day Job&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;let&lt;/span&gt; &lt;span&gt;drafts&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;workspace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;   &lt;span&gt;.&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;inbox&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;   &lt;span&gt;.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;d&lt;/span&gt; &lt;span&gt;=&amp;gt;&lt;/span&gt; &lt;span&gt;d&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;includes&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;link&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span&gt;d&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;createdAt&lt;/span&gt; &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;week_ago&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;let&lt;/span&gt; &lt;span&gt;links&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;drafts&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;let&lt;/span&gt; &lt;span&gt;content&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;d&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;.&lt;/span&gt;&lt;span&gt;trim&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;.&lt;/span&gt;&lt;span&gt;split&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;content&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;### &amp;quot;&lt;/span&gt; &lt;span&gt;+&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;return&lt;/span&gt; &lt;span&gt;content&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;drafts&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;forEach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt; &lt;span&gt;d&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;isArchived&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt; &lt;span&gt;d&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;let&lt;/span&gt; &lt;span&gt;newsletter&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;Draft&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;create&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;newsletter&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;`$&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;template&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;\n&lt;/span&gt;&lt;span&gt;$&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;links&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;newsletter&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setClipboard&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;newsletter&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Short and sweet! After I've clicked the link from my Task Manager, I open Confluence, type &lt;code&gt;c&lt;/code&gt; to create a page, choose the Blog template in the sidebar&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;, type &lt;code&gt;,,weekly&lt;/code&gt; in the title field that Alfred.app text expands to &amp;quot;UXWEEKLY (2020.51)&amp;quot;, and then I paste the newsletter since the last line of my Drafts action copied the draft to the system clipboard. Voila!&lt;/p&gt;
&lt;p&gt;Just what is in my clipboard? The contents of my template Draft! Let's take a (redacted) peek.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-markdown" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;# ProctorU Weekly Template
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;## 👷‍♂️ In Progress
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;[UX Kanban Board](link to our kanban board)
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;### Project #1: Fictional Title
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;📁: http://linktoprojectpageonconfluence.com/project-1
&lt;/div&gt;&lt;div class="line"&gt;💬: [#proj-1-ux](https://dayjob.slack.com/archives/L337)
&lt;/div&gt;&lt;div class="line"&gt;📈: [Link to dashboard or metrics associated with UX outcomes](http://fakelink.com/)
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;### Project #2: Fictional Boogaloo
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;📁: http://linktoprojectpageonconfluence.com/project-2
&lt;/div&gt;&lt;div class="line"&gt;💬: [#proj-2-ux](https://dayjob.slack.com/archives/nicetry)
&lt;/div&gt;&lt;div class="line"&gt;📈: [Link to dashboard or metrics associated with UX outcomes](http://fakelink.com/)
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;## 🔗 Links
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's it! I'll write my tweet-length update in-between the header and the links of the projects, @mention anyone who needs to see it, and the links magically appear below the &lt;code&gt;## 🔗 Links&lt;/code&gt; section of the newsletter.&lt;/p&gt;
&lt;p&gt;Projects don't change &lt;em&gt;that&lt;/em&gt; much, so as they come and go I'll add them and their pertinent information to the Draft Template.&lt;/p&gt;
&lt;p&gt;This simple automation has cut down the time it takes to provide this &amp;quot;hub&amp;quot; for our work from 45 minutes per week to around 3 minutes… and that makes me happy. I'm sure there's a bunch of ways to automate this, but keeping it all in Drafts makes it cross platform and easy to change the template on the fly if I get new information.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;Honestly, this is the step I mess up &lt;em&gt;every&lt;/em&gt; week and I should automate. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Tue, 15 Dec 2020 09:39:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/12/15/automatic-newsletter-using-drafts/</guid></item><item><title>Adding ambient light support to Linux and GNOME</title><link>https://maxleiter.com/blog/MSHW0184</link><description>&lt;p&gt;A couple of a weeks ago I picked up a Surface Pro 7 (i3 1.2 mhz) at a Black Friday sale. I love making devices run software they shouldn't, so I got to work dual-booting Linux on it. To my surprise, almost everything worked with the default Fedora 33 kernel, not including the touchscreen, the ambient light sensor, and the camera. After compiling and loading the great &lt;a href="https://github.com/linux-surface/linux-surface" rel="noopener noreferrer" target="_blank"&gt;linux-surface&lt;/a&gt; kernel the touchscreen started to work but I found a &lt;a href="https://github.com/linux-surface/linux-surface/issues/121" rel="noopener noreferrer" target="_blank"&gt;GitHub issue&lt;/a&gt; someone had made detailing that the ambient light sensor (a MSHW0184) isn't detected. This normally wouldn't matter a lot, but I'd discovered that GNOME supported adjusting the screen brightness based on the ambient light through &lt;a href="https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/" rel="noopener noreferrer" target="_blank"&gt;iio-sensor-proxy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I knew nothing (and still know very little) about the Linux kernel or drivers, but this seemed like a great place to start. Luckily, GitHub user archseer discovered that the MSHW0184 registers align with the APDS9960 device, which already has an upstream kernel driver, and he mentioned all that should be needed is a small change to allow the driver to detect the new device.&lt;/p&gt;
&lt;p&gt;Here I realized I had to do some research into how the kernel loads drivers. I knew that drivers could either be statically built into the kernel, or built as kernel modules so they can be dynamically loaded when they're needed. But how does the kernel know when to load specific drivers for certain hardware? You register the ID with a matching table.&lt;/p&gt;
&lt;p&gt;Initially, I tried adding the MSHW0184 device ID to the existing match table in the APDS9960 driver for the i2c protocol. This consisted of the following one-line change:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;static const struct i2c_device_id apds9960_id[] = {
                    { &amp;quot;apds9960&amp;quot;, 0 },
+                   { &amp;quot;MSHW0184, 0 }
                    {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this didn't work and I realized the conventions seemed a little odd: no other i2c device ids in other drivers contained capitals or were ambient light sensing devices. Thankfully, someone on IRC helped me out:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;00:53 &amp;#60;djrscally&amp;#62; That's an acpi ID &lt;br /&gt;&lt;br /&gt;00:53 &amp;#60;djrscally&amp;#62; You probably need to add an ACPI match table&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A few minutes later (well, probably closer to 30 minutes after compiling and testing the kernel on-device) I had the following, largely copied from other ACPI drivers:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;
+ static const struct acpi_device_id apds9960_acpi_match[] = {
    +	{ &amp;quot;MSHW0184&amp;quot; },
    +	{ }
    +};
+ MODULE_DEVICE_TABLE(acpi, apds9960_acpi_match);

  static struct i2c_driver apds9960_driver = {
    .driver = {
        .name	= APDS9960_DRV_NAME,
        .of_match_table = apds9960_of_match,
        .pm	= &amp;amp;apds9960_pm_ops,
+       .acpi_match_table = apds9960_acpi_match,
    },
    .probe		= apds9960_probe,
    .remove		= apds9960_remove
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I recompiled the kernel module, rebooted, and verified the driver was matched with lsmod and ensured the driver paired with the device by navigating to the IIO device (finding the path to the device took a lot more work than I'd like to admit) and reading in the `in_intensity_clear_raw` file:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt; max@surface ~&amp;gt; cat sys/bus/iio/devices/iio:device0/in_intensity_clear_raw
    33
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The joy I felt seeing that file exist and the output was monumental. I had something to work with!&lt;/p&gt;
&lt;p&gt;I wasn't done yet though — GNOME still didn't show me an option to automatically adjust the screen brightness. After someone else verified they also had the device loaded with the modified driver but not in GNOME I determined the problem was somewhere in iio-sensor-proxy. I cloned the iio-sensor-proxy repository and started digging.&lt;/p&gt;
&lt;p&gt;The first thing I always do when I clone a new repo is expand and quickly look over every folder (assuming the repo is a reasonable size) and that served me well here. I found the following file `80-iio-sensor-proxy.rules`:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yml"&gt;# iio-sensor-proxy
# IIO sensor to D-Bus proxy

ACTION==&amp;quot;remove&amp;quot;, GOTO=&amp;quot;iio_sensor_proxy_end&amp;quot;

# Set the sensor type for all the types we recognise
SUBSYSTEM==&amp;quot;hwmon&amp;quot;, TEST==&amp;quot;light&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;hwmon-als&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;in_accel_x_raw&amp;quot;, TEST==&amp;quot;in_accel_y_raw&amp;quot;, TEST==&amp;quot;in_accel_z_raw&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-poll-accel&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;scan_elements/in_accel_x_en&amp;quot;, TEST==&amp;quot;scan_elements/in_accel_y_en&amp;quot;, TEST==&amp;quot;scan_elements/in_accel_z_en&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-buffer-accel&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;scan_elements/in_rot_from_north_magnetic_tilt_comp_en&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-buffer-compass&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;in_illuminance_input&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-poll-als&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;in_illuminance0_input&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-poll-als&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;in_illuminance_raw&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-poll-als&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;scan_elements/in_intensity_both_en&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-buffer-als&amp;quot;
SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;in_proximity_raw&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-poll-proximity&amp;quot;
SUBSYSTEM==&amp;quot;input&amp;quot;, ENV{ID_INPUT_ACCELEROMETER}==&amp;quot;1&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;input-accel&amp;quot;

ENV{IIO_SENSOR_PROXY_TYPE}==&amp;quot;&amp;quot;, GOTO=&amp;quot;iio_sensor_proxy_end&amp;quot;

# We got here because we have a sensor type, which means we need the service
TAG+=&amp;quot;systemd&amp;quot;, ENV{SYSTEMD_WANTS}+=&amp;quot;iio-sensor-proxy.service&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you might be able to figure out, each TEST file is checked for existence and is used to determine whether or not the device should be used by iio-sensor-proxy.&lt;/p&gt;
&lt;p&gt;I hadn't seen any of the seemingly relevant files, in&lt;em&gt;illuminance&lt;/em&gt;*, so I added my own line:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yml"&gt;SUBSYSTEM==&amp;quot;iio&amp;quot;, TEST==&amp;quot;in_intensity_clear_raw&amp;quot;, ENV{IIO_SENSOR_PROXY_TYPE}+=&amp;quot;iio-poll-als&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After another small iio-sensor-proxy change and running again the device was now discovered by iio-sensor-proxy! The full merge request can be seen &lt;a href="https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/-/merge_requests/319" rel="noopener noreferrer" target="_blank"&gt;here&lt;/a&gt;. The option appeared in GNOME and I now have automatic adjusting brightness!&lt;/p&gt;
&lt;p&gt;It kind of sucks though and isn't very consistent. As it turns out, intensity_clear != illuminance, which is what most programs expect from ambient light sensors, so I need to figure out and perform some math in iio-sensor-proxy to translate the RGBC values to lux.&lt;/p&gt;
&lt;p&gt;If you've made it this far (or are here to get the code yourself), the modified driver (with basic proximity sensing support too) can be found here: &lt;a href="https://github.com/maxleiter/MSHW0184" rel="noopener noreferrer" target="_blank"&gt;https://github.com/maxleiter/MSHW0184&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Major thanks to everyone that helped me in the ##linux-surface IRC channel. It was great to finally get a little low-level with Linux.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;*This post was originally written on the old maxleiter.com, and formatting has slightly adjusted&lt;/p&gt;</description><author>Max Leiter</author><pubDate>Tue, 15 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://maxleiter.com/blog/MSHW0184</guid></item><item><title>2020–12–15: Battery thermistor measurements</title><link>https://xnux.eu/log/#029</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 15 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#029</guid></item><item><title>Five critical things for our oceans</title><link>https://stop.zona-m.net/2020/12/five-critical-things-for-our-oceans/</link><description>&lt;p&gt;and their &amp;ldquo;digital&amp;rdquo; implications.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 14 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/five-critical-things-for-our-oceans/</guid></item><item><title>Disable Google Autoupdater on macOS</title><link>https://caiustheory.com/disable-google-autoupdater-on-macos/</link><description>&lt;p&gt;From reading &lt;a href="https://chromeisbad.com"&gt;Chrome is Bad&lt;/a&gt;, it seems in some situations the updater (also known as keystone) can chew up CPU cycles. Whilst I&amp;rsquo;m not 100% convinced keystone continuously chews CPU, its launchctl configuration suggests it runs at least once an hour. Given I don&amp;rsquo;t use Chrome as my main browser, this is undesirable behaviour for me.&lt;/p&gt;
&lt;p&gt;With that in mind, I&amp;rsquo;ve decided to disable the background services rather than delete Chrome entirely. (I need it occasionally.) Stopping/unloading the services and fettling the config files to do nothing achieves this aim (and stops Chrome re-enabling them next launch), whilst leaving Chrome fully functional when needed.&lt;/p&gt;
&lt;ol start="0"&gt;
&lt;li&gt;
&lt;p&gt;Unload the currently loaded services&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl unload -w ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;launchctl unload -w ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Empty the config files, so if launchd ever tries to launch them they&amp;rsquo;ll just error out&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &amp;gt; ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &amp;gt; ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change ownership and permissions of these files so only root can write to the files&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;644&lt;/span&gt; ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;644&lt;/span&gt; ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown root ~/Library/LaunchAgents/com.google.keystone.xpcservice.plist
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo chown root ~/Library/LaunchAgents/com.google.keystone.agent.plist
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now when I want to update Chrome once in a blue moon when I need it, I can navigate to &lt;a href=""&gt;chrome://settings/help&lt;/a&gt; to update (or from the UI, Chrome -&amp;gt; About Chrome.)&lt;/p&gt;</description><author>Caius Theory</author><pubDate>Mon, 14 Dec 2020 18:14:53 GMT</pubDate><guid isPermaLink="true">https://caiustheory.com/disable-google-autoupdater-on-macos/</guid></item><item><title>Benchmarking Rustpython With Criterion</title><link>https://tomforb.es/blog/benchmarking-rustpython-with-criterion/</link><description>I’ve been very excited about RustPython since I saw the project being presented at FOSDEM 2019. Last week I finally got to contributing something to the project ! For context, RustPython benchmarks specific Python files against CPython, the “reference implementation” for Python (read: the only real ...</description><author>Tom Forbes</author><pubDate>Mon, 14 Dec 2020 15:27:30 GMT</pubDate><guid isPermaLink="true">https://tomforb.es/blog/benchmarking-rustpython-with-criterion/</guid></item><item><title>Ethan Magnass' sermons from Grace Anglican Church in Grove City, PA</title><link>https://josh.works/sermons</link><description>&lt;p&gt;&lt;em&gt;update from a few years later: I tried a bunch of stuff to keep myself within evangelicalism. failed, so iterated through another option, sorta in the style of &lt;a href="https://www.goodreads.com/book/show/149033.Exit_Voice_and_Loyalty"&gt;exit, voice, and loyalty: responses in decline of quality of firms&lt;/a&gt;. I’ve firmly left the club, and warmly invite anyone else finding themselves within it to do the same: &lt;a href="/on-leaving-evangelicalism"&gt;On Leaving Evangelicalism and Opposing It&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’ve been recommending a collection of sermons to many people recently.&lt;/p&gt;

&lt;p&gt;I’ve listened to each of these sermons quite a few times. They’re worth your time.&lt;/p&gt;

&lt;p&gt;Ethan Magness is the rector at &lt;a href="http://graceanglicanonline.com/"&gt;Grace Anglican Church&lt;/a&gt; in Grove City, PA.&lt;/p&gt;

&lt;h2 id="sermon-series-on-joseph"&gt;Sermon Series on Joseph&lt;/h2&gt;

&lt;p&gt;Grace Anglican Church podcast feed (&lt;a href="https://play.pocketcasts.com/podcasts/6de56a60-e04e-0134-ebdd-4114446340cb"&gt;PocketCasts&lt;/a&gt;, &lt;a href="https://podcasts.apple.com/us/podcast/grace-anglican-church/id1209329002"&gt;Apple Podcasts&lt;/a&gt;)&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-i-privilege/"&gt;St Joe (Part I) – Privilege – Genesis 37&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-ii-desecration-genesis-37/"&gt;St Joe (Part II) – Desecration – Genesis 37&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-iii-companion-genesis-39/"&gt;St Joe (Part III) – Companion – Genesis 39&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-iv-dreams-genesis-40/"&gt;St Joe (Part IV) – Dreams – Genesis 40&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-v-engagement-genesis-41/"&gt;St Joe (Part V) – Engagement – Genesis 41&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-vi-rise-genesis-41/"&gt;St Joe (Part VI) – Rise – Genesis 41&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-vii-sun-genesis-45/"&gt;St Joe (Part VII) – Sun – Genesis 45&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-viii-dad-genesis-46/"&gt;St Joe (Part VIII) – Dad – Genesis 46&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-ix-bless-genesis-48/"&gt;St Joe (Part IX) – Bless – Genesis 48&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-x-mix-genesis-49/"&gt;St Joe (Part X) – Mix – Genesis 49&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://graceanglicanonline.com/podcast/st-joe-part-xi-mummies-genesis-50/"&gt;St Joe (Part XI) – Mummies – Genesis 50&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="sermon-on-matthew-543-48"&gt;Sermon on Matthew 5:43-48&lt;/h2&gt;

&lt;p&gt;From November 4, 2018: &lt;a href="http://graceanglicanonline.com/podcast/gollum-the-outstretched-hand-matthew-5/"&gt;Gollum &amp;amp; the Outstretched Hand - Matthew 5&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Relevant scripture:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“You have heard that it was said, ‘Love your neighbor and hate your enemy.’&lt;/p&gt;

  &lt;p&gt;But I tell you, love your enemies and pray for those who persecute you, that you may be children of your Father in heaven. He causes his sun to rise on the evil and the good, and sends rain on the righteous and the unrighteous.&lt;/p&gt;

  &lt;p&gt;If you love those who love you, what reward will you get? Are not even the tax collectors doing that?&lt;/p&gt;

  &lt;p&gt;And if you greet only your own people, what are you doing more than others? Do not even pagans do that?&lt;/p&gt;

  &lt;p&gt;Be perfect, therefore, as your heavenly Father is perfect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I have far more thoughts on the topic, but for now, this should help you, the reader, find these excellent sermons.&lt;/p&gt;

&lt;h2 id="todo"&gt;Todo&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;I’d like to get high-quality transcripts of these sermons. There are services that do this (Like &lt;a href="https://www.rev.com/"&gt;Rev&lt;/a&gt;), I’ll pay for it sometime soon. I want &lt;em&gt;good&lt;/em&gt; transcripts, not just AI-generated transcripts. It took me like two hours to clean up a few minutes of AI-generated text for &lt;a href="/my-thoughts-on-erics-thoughts-on-pias-thoughts"&gt;My Thoughts on Eric Weinstein’s Thoughts on Pia Kalani’s Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point I’ll weave together other threads I’ve got sketched out, but are not ready for public consumption.&lt;/p&gt;

&lt;h2 id="additional-reading"&gt;Additional Reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="/whats-up-with-anabaptists"&gt;What’s up with the Anabaptists? (josh.works)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/was-jesus-ethics-normative"&gt;Was Jesus’ behavior normative? (josh.works)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/on-leaving-evangelicalism"&gt;On Leaving Evangelicalism and Opposing It&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Josh Thompson</author><pubDate>Mon, 14 Dec 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/sermons</guid></item><item><title>Sketchnotes: UX Vision Intensive</title><link>http://evantravers.com/articles/2020/12/14/sketchnotes-ux-vision-intensive/</link><description>&lt;p&gt;This past week our team attended the &lt;a href="https://leaders.centercentre.com"&gt;Leaders of Awesomeness&lt;/a&gt; &lt;em&gt;UX Vision Intensive&lt;/em&gt;. &lt;a href="https://twitter.com/jmspool"&gt;Jared Spool&lt;/a&gt; led the sessions, and I was very impressed and grateful to the time he gave us for &lt;em&gt;free&lt;/em&gt;.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="sketchnote" src="https://images.evantravers.com/articles/2020/12/experience-vision.jpeg" /&gt;
  &lt;figcaption&gt;If you want a higher-resolution copy, you can &lt;a href="https://images.evantravers.com/articles/2020/12/experience-vision.pdf"&gt;download the pdf&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I struggled with the difference between a vision an an envisionment. If I understand correctly, a UX vision is a depiction of a user's timeless experience, with major friction alleviated by a nearly magic product you are imagining. An envisionment is a near future implementation of a UX vision with possible technology. I have been keeping it straight by saying that Star Trek TOS is a UX Vision, where Star Trek TNG is an envisionment. 🤷‍♂️&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;We are &lt;strong&gt;super&lt;/strong&gt; excited to take the lessons to heart and bring a UX Vision to life… talking about that this week. I'm especially looking forward to some of the workshop exercises… &amp;quot;despicable design&amp;quot;&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;2&lt;/a&gt;&lt;/sup&gt; sounds like fun!&lt;/p&gt;
&lt;p&gt;I've been playing around with taking notes in the sketchnotes style for a year or so…&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-3" id="fnref-3"&gt;3&lt;/a&gt;&lt;/sup&gt; this digital sketchnote I made in &lt;a href="https://apps.apple.com/us/app/goodnotes-5/id1444383602"&gt;GoodNotes&lt;/a&gt;, and am very happy with the tool. It has a good mix of power and simplicity that works really well for me… and even my handwriting is searchable! Highly recommended.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;If I'm misrepresenting these, please &lt;a href="/contact"&gt;let me know&lt;/a&gt;… I'm a TNG guy myself. &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;In Despicable Design, you ask your team the question: &amp;quot;how could we make the users experience &lt;strong&gt;worse&lt;/strong&gt;?&amp;quot; Sort of an ice breaker, and it quickly highlights which elements upon which the user's experience hinges. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-3"&gt;
&lt;p&gt;I may go back and find my first couple of sketchnotes. The first 10 were not nearly this good… and the ability of a digital note to zoom and undo makes it a &lt;em&gt;lot&lt;/em&gt; easier to make something neat and clean. Just keep at it! &lt;a class="footnote-backref" href="#fnref-3"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Mon, 14 Dec 2020 08:37:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/12/14/sketchnotes-ux-vision-intensive/</guid></item><item><title>Announcing the AutoEPM Patch Tracker</title><link>http://blog.pythonaro.com/2020/02/announcing-autoepm-patch-tracker.html</link><description>&lt;p&gt;UPDATE: This service has been discontinued; this post is left as historical reference. If you need this sort of thing, &lt;a href="https://linkedin.com/in/glacava" target="_blank"&gt;contact me on LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the recent release of EPM 11.2, I thought it would be a good time to make public a tool I've built and used "behind the scenes" for quite some time, &lt;a href="https://tracker.autoepm.co"&gt;the AutoEPM Patch Tracker&lt;/a&gt;.&lt;/p&gt; 

&lt;p&gt;It's a patch tracker focused on EPM products, automatically aggregating updates and pointing to readmes, hopefully a bit faster to peruse than My Oracle Support. It also recommends Critical Product Updates that can be applied to the EPM stack, and the most common "standard" updates (only for 11.1.2.4 at the moment). With a free account via LinkedIn sign-on, all lists can be downloaded in CSV, JSON, and XML (Atom).&lt;/p&gt;

&lt;p&gt;It's only a small showcase of what we can do at &lt;a&gt;AutoEPM&lt;/a&gt; by Targlet. If you'd like to find out how to integrate this level of automation and intelligence to your EPM enviroments, feel free to &lt;a href="mailto:info@autoepm.com"&gt;reach out&lt;/a&gt;! I'll be at OpenWorld London next week as well, always happy to have a chat.&lt;/p&gt;</description><author>Subclassed</author><pubDate>Mon, 14 Dec 2020 03:05:16 GMT</pubDate><guid isPermaLink="true">http://blog.pythonaro.com/2020/02/announcing-autoepm-patch-tracker.html</guid></item><item><title>Mimicry vs Reflexivity</title><link>https://www.swyx.io/mimicry-reflexivity</link><description>Two opposing forces that describe how perception and reality do battle.</description><author>swyx's site RSS Feed</author><pubDate>Mon, 14 Dec 2020 00:35:02 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/mimicry-reflexivity</guid></item><item><title>Smaller, Faster-starting Container Images With jlink and AppCDS</title><link>https://www.morling.dev/blog/smaller-faster-starting-container-images-with-jlink-and-appcds/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_creating_a_modular_runtime_image_for_a_quarkus_application"&gt;Creating a Modular Runtime Image for a Quarkus Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_adding_an_appcds_archive_to_a_custom_runtime_image"&gt;Adding an AppCDS Archive to a Custom Runtime Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_creating_a_linux_container_image"&gt;Creating a Linux Container Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_lets_see_some_numbers"&gt;Let’s See Some Numbers!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;A few months ago I &lt;a href="https://www.morling.dev/blog/building-class-data-sharing-archives-with-apache-maven/"&gt;wrote about&lt;/a&gt; how you could speed up your Java application’s start-up times using application class data sharing (&lt;a href="http://openjdk.java.net/jeps/350"&gt;AppCDS&lt;/a&gt;),
based on the example of a simple &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt; application.
Since then, quite some progress has been made in this area:
Quarkus 1.6 brought &lt;a href="https://quarkus.io/guides/maven-tooling#quarkus-package-pkg-package-config_quarkus.package.create-appcds"&gt;built-in support for AppCDS&lt;/a&gt;,
so that now you just need to provide the &lt;em&gt;-Dquarkus.package.create-appcds=true&lt;/em&gt; option when building your project,
and you’ll find an AppCDS file in the &lt;em&gt;target&lt;/em&gt; folder.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Things get more challenging though when combining AppCDS with custom Java runtime images,
as produced using the &lt;a href="https://docs.oracle.com/en/java/javase/15/docs/specs/man/jlink.html"&gt;jlink&lt;/a&gt; tool added in Java 9.
Combining custom runtime images with AppCDS is very attractive,
in particular when looking at the deployment of Java applications via Linux containers.
Instead of putting the full Java runtime into the container image, you only add those JDK modules which your application actually requires.
(Parts of) what you save in image size by doing so,
can be used for adding an AppCDS archive to your container image.
The result will be a container image which still is smaller than before — and thus is faster to push to a container registry, distribute to worker nodes in a Kubernetes cluster, etc. — and which starts up significantly faster.&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Sun, 13 Dec 2020 21:30:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/smaller-faster-starting-container-images-with-jlink-and-appcds/</guid></item><item><title>SSH in Virtual Machine Ubuntu Server 20.04</title><link>https://geo.rocks/post/ssh-in-vm/</link><description>&lt;p&gt;&lt;img alt="Ubuntu SSH" src="https://geo.rocks/img/ubuntu-ssh.jpg" title="Ubuntu SSH" /&gt;&lt;/p&gt;
&lt;p&gt;A quick guide to setup a SSH-conncection to Virtual Machine Ubuntu Server 20.04&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Sun, 13 Dec 2020 18:58:46 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/ssh-in-vm/</guid></item><item><title>Secrets of Sand Hill Road: Venture Capital and How to Get It</title><link>https://olshansky.info/book/secrets_of_sand_hill_road/</link><description>Olshansky's review of Secrets of Sand Hill Road: Venture Capital and How to Get It by Scott Kupor</description><author>🦉 olshansky 🦁</author><pubDate>Sun, 13 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/secrets_of_sand_hill_road/</guid></item><item><title>Beep, beep, I'm a sheep</title><link>https://zserge.com/posts/beep/</link><description>Audio I/O is a complex topic, which scares away many inspired musicians who are into programming (or programmers who are into music). Let&amp;rsquo;s try making it look less complex and see how audio works on each modern desktop platform.
Our show case today will be a simple beeper. Remeber that annoying thing inside your PC boxes producing the irritating buzzing sound? It&amp;rsquo;s long time gone, but I suggest to sumon its soul and make a library that plays beeps across all the platforms.</description><author>zserge's blog</author><pubDate>Sun, 13 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/beep/</guid></item><item><title>The Perfect Neapolitan Pizza</title><link>https://blog.cetinich.net/content/food/2020-naples-pizza/</link><description>In Italy a society; Associazione Verace Pizza Napoletana makes the rules
when it comes to every aspect of the Naples pizza and they describe the
rules of a Naples pizza in extreme technical detail
here
this is a great read if you are a pizza nerd and it details the exact
procedure to cook a perfect Napoletana pizza.</description><author>Brent's Blog</author><pubDate>Sun, 13 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/food/2020-naples-pizza/</guid></item><item><title>Peri Peri Chicken</title><link>https://blog.cetinich.net/content/food/2020-peri-peri-chicken/</link><description>Chicken Thigh (With or without skin / bone - to taste)</description><author>Brent's Blog</author><pubDate>Sun, 13 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/food/2020-peri-peri-chicken/</guid></item><item><title>The immensely stupid fragility of our "high-tech" way of living</title><link>https://stop.zona-m.net/2020/12/the-immensely-stupid-fragility-of-our-high-tech-way-of-living/</link><description>&lt;p&gt;It&amp;rsquo;s embarrassing. It really is.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 12 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/the-immensely-stupid-fragility-of-our-high-tech-way-of-living/</guid></item><item><title>Talapus Lake</title><link>https://sam.hooke.me/trip/2020/12/talapus-lake/</link><description>&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/talapus-lake/talapus-lake.jpg"&gt;
 
 &lt;img alt="A frozen lake with snowy valley on the other side." src="https://sam.hooke.me/images/trip/2020/talapus-lake/talapus-lake_hu16117309800859985362.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Talapus Lake. The best photo I have, because for some unknown reason I barely took any photos on this hike.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;

&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;table class="stats-table"&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;th&gt;Distance&lt;/th&gt;
 &lt;th&gt;7.6 km / 4.72 miles&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Elevation gain&lt;/th&gt;
 &lt;th&gt;233 m / 765 ft&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Duration&lt;/th&gt;
 &lt;th&gt;3h10m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;th&gt;Moving&lt;/th&gt;
 &lt;th&gt;2h10m&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Normally we like to start hiking bright and early, but today we went on an afternoon hike with friends.&lt;/p&gt;
&lt;p&gt;After turning off the I-90, the drive up FR 9030 was pretty hairy. It&amp;rsquo;s a gravel road, with sharp blind bends, and at some points it&amp;rsquo;s rather narrow with a steep drop to the side through dense forest. By itself this wouldn&amp;rsquo;t have been an issue, but we weren&amp;rsquo;t the only people driving here. We were caught in a perfect storm between the morning hikers, who had got those precious spaces at the trailhead but were now trying to drive home; the midday hikers, who had found the trailhead car park full and opted to park in various places on the side of the narrow road; and the hopeful afternoon hikers (us included) who were playing slow motion dodgems on the side of a mountain.&lt;/p&gt;</description><author>Sam Hooke</author><pubDate>Sat, 12 Dec 2020 07:30:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/12/talapus-lake/</guid></item><item><title>Something to monitor about e-voting in Europe</title><link>https://stop.zona-m.net/2020/12/something-to-monitor-about-e-voting-in-europe/</link><description>&lt;p&gt;A compendium of inherently wrong things&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 11 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/something-to-monitor-about-e-voting-in-europe/</guid></item><item><title>You Can Run Containers on AWS Amplify Now</title><link>https://www.swyx.io/amplify-serverless-containers</link><description>AWS just added the easiest way to deploy long running serverful code alongside a serverless architecture.</description><author>swyx's site RSS Feed</author><pubDate>Fri, 11 Dec 2020 16:24:37 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/amplify-serverless-containers</guid></item><item><title>Preventing auto-locking and sleeping by simulating user activity</title><link>https://cmetcalfe.ca/blog/prevent-auto-lock-by-simulating-activity.html</link><description>&lt;p&gt;This post will detail how to simulate activity on your computer in order to prevent it from
auto-locking or going into sleep mode. Note that this will usually also prevent the "auto-away"
functionality of various chat programs from ever marking you as "away".&lt;/p&gt;
&lt;p&gt;Generally you should change your operating system's settings to disable sleeping and auto-locking if
possible instead. These methods are for when you don't have the access or permission to change those
settings (ie. locked-down devices).&lt;/p&gt;
&lt;h2&gt;Windows&lt;/h2&gt;
&lt;p&gt;This method runs a &lt;a href="https://en.wikipedia.org/wiki/Powershell"&gt;Powershell&lt;/a&gt; script on login that toggles &lt;a href="https://en.wikipedia.org/wiki/Scroll_lock"&gt;scroll lock&lt;/a&gt; on/off every minute.
Since scroll lock mostly doesn't do anything on modern systems and the script will press it twice to
immediately unlock/relock it, this is basically unnoticeable to the user. However, if you have
issues simply swap the two &lt;code&gt;{SCROLLLOCK}&lt;/code&gt;s in the below command to something else. A full list of
special keys can be found &lt;a href="https://social.technet.microsoft.com/wiki/contents/articles/5169.vbscript-sendkeys-method.aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Explorer (shortcut: &lt;code&gt;Win+E&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Paste &lt;code&gt;%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup&lt;/code&gt; into the location bar and hit
   enter to navigate there.&lt;/li&gt;
&lt;li&gt;Right click in the folder and click &lt;code&gt;New &amp;gt; Shortcut&lt;/code&gt; to open the shortcut creation wizard.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paste the following as the shortcut's location:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;powershell.exe -windowstyle hidden -command &amp;quot;$myshell=New-Object -com \&amp;quot;Wscript.Shell\&amp;quot;;while(1){$myshell.SendKeys(\&amp;quot;{SCROLLLOCK}{SCROLLLOCK}\&amp;quot;);Start-Sleep -Seconds 60}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Give it any name you like and hit &lt;code&gt;Finish&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;macOS&lt;/h2&gt;
&lt;p&gt;This method runs a shell script on login that uses a tool called &lt;a href="https://www.bluem.net/en/projects/cliclick/"&gt;&lt;code&gt;cliclick&lt;/code&gt;&lt;/a&gt; to move the
mouse one pixel left and right every minute. This is such a small and fast movement that it's
usually not noticeable unless you're really looking for it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;code&gt;cliclick&lt;/code&gt; from &lt;a href="https://www.bluem.net/en/projects/cliclick/"&gt;the project website&lt;/a&gt; or via &lt;a href="https://brew.sh/"&gt;brew&lt;/a&gt; (&lt;code&gt;brew install cliclick&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Create a script called &lt;code&gt;jiggle&lt;/code&gt; with the following contents:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;#!/bin/sh
while true; do
    cliclick 'm:-1,+0' 'm:+1,+0'
    sleep 60
done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Make the script executable (&lt;code&gt;chmod +x jiggle&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Open System Preferences, search for "login items" and hit enter.&lt;/li&gt;
&lt;li&gt;Click the &lt;code&gt;+&lt;/code&gt; button, select the &lt;code&gt;jiggle&lt;/code&gt; script and hit "Add". You should see it appear in the
   list of programs as a "Unix executable". Check the "Hide" checkbox beside it and exit.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Xorg-based Linux&lt;/h2&gt;
&lt;p&gt;Much like the macOS version above, this moves the mouse one pixel left and right every minute. If
you would prefer to instead use a keyboard-based method like the above Windows version, use &lt;code&gt;xdotool
key Scroll_Lock&lt;/code&gt; twice instead of the &lt;code&gt;xdotool mousemove_relative *&lt;/code&gt; commands in the following
script. More special key names for &lt;code&gt;xdotool&lt;/code&gt; can be found &lt;a href="https://gitlab.com/cunidev/gestures/-/wikis/xdotool-list-of-key-codes"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install &lt;a href="https://www.semicomplete.com/projects/xdotool/"&gt;&lt;code&gt;xdotool&lt;/code&gt;&lt;/a&gt; (usually available via your package manager)&lt;/li&gt;
&lt;li&gt;Create a script called &lt;code&gt;jiggle&lt;/code&gt; with the following contents:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;#!/bin/sh
while true; do
    xdotool mousemove_relative --sync -- -1 0
    xdotool mousemove_relative 1 0
    sleep 60
done
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Make the script executable (&lt;code&gt;chmod +x jiggle&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Configure your OS to run the script at login. Usually this would be done through the desktop
   environment's settings or via something like &lt;a href="https://www.freedesktop.org/wiki/Software/systemd/"&gt;&lt;code&gt;systemd&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Wayland-based Linux&lt;/h2&gt;
&lt;p&gt;Some preliminary research suggests that this is possible on Wayland using &lt;a href="https://github.com/ReimuNotMoe/ydotool"&gt;&lt;code&gt;ydotool&lt;/code&gt;&lt;/a&gt; as a
replacement for &lt;code&gt;xdotool&lt;/code&gt;. I don't currently run a Wayland-based setup so I can't test it. If you
manage to find a solution for Wayland feel free to send it to me and I'll update the post.&lt;/p&gt;</description><author>Carey Metcalfe</author><pubDate>Fri, 11 Dec 2020 06:12:00 GMT</pubDate><guid isPermaLink="true">https://cmetcalfe.ca/blog/prevent-auto-lock-by-simulating-activity.html</guid></item><item><title>Educational Logic Gate Board</title><link>https://blog.kaetemi.be/2020/12/11/educational-logic-gate-board/</link><description>This is a board I based roughly on a setup we had in high school, that I was taught logic gates with, once upon a time. I designed the layout...</description><author>Kaetemi</author><pubDate>Fri, 11 Dec 2020 03:41:41 GMT</pubDate><guid isPermaLink="true">https://blog.kaetemi.be/2020/12/11/educational-logic-gate-board/</guid></item><item><title>I received first-ever donation on my open-source side project and it felt great!</title><link>https://gourav.io/blog/first-donation-on-open-source-side-project</link><description>I decided to build an extension for VSCode. That would add handy buttons for many common commands like save file, format file, show opened files etc.</description><author>Gourav Goyal</author><pubDate>Fri, 11 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://gourav.io/blog/first-donation-on-open-source-side-project</guid></item><item><title>Capitalism and the Jews</title><link>https://olshansky.info/book/capitalism_and_the_jews/</link><description>Olshansky's review of Capitalism and the Jews by Jerry Z. Muller</description><author>🦉 olshansky 🦁</author><pubDate>Fri, 11 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/capitalism_and_the_jews/</guid></item><item><title>Dr. Loopback, Or: How I Learned to Stop DOSing Myself and Love the Pi-Hole</title><link>https://lambdaland.org/posts/2020-12-11-raspberry-pi-dos/</link><description>&lt;p&gt;I noticed that my Internet was acting strangely: whenever I visited a web page, my browser would hang for a good second or two before it started loading anything. Zoom calls worked without a problem for school, so this tipped me off that something was wrong with the DNS lookup or the handshake.&lt;/p&gt;
&lt;p&gt;Sure enough, I popped open my &lt;a class="link-external" href="https://pi-hole.net/" rel="external"&gt;Pi-Hole&lt;/a&gt; admin console, and was greeted with this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Pi-Hole Admin Console" src="https://lambdaland.org/img/pi_hole_before.png" /&gt;&lt;/p&gt;
&lt;p&gt;The green number in the &lt;code&gt;Total Queries&lt;/code&gt; box would jump by 10, 20, or sometimes even 100 every second.&lt;/p&gt;
&lt;p&gt;I tried turning off, disconnecting, and rebooting my various computers and devices to see if it was just some rogue process messing everything up. No change. I rebooted my router. No change. I updated and restarted the Pi-Hole. Still no change.&lt;/p&gt;
&lt;p&gt;I noticed that a &lt;em&gt;lot&lt;/em&gt; of requests to the domain &lt;code&gt;lb._dns-sd._udp.0.0.0.10.in-addr.arpa&lt;/code&gt;. I did a web search and found &lt;a class="link-external" href="https://discourse.pi-hole.net/t/many-requests-to-lb-dns-sd-udp-0-1-168-192-in-addr-arpa/18241" rel="external"&gt;a single post on a forum&lt;/a&gt; that suggested turning off conditional forwarding on the Pi-Hole.&lt;/p&gt;
&lt;p&gt;I went into admin settings, turned off conditional forwarding, and was rewarded with this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Pi-Hole Admin Console" src="https://lambdaland.org/img/pi_hole_after.png" /&gt;&lt;/p&gt;
&lt;p&gt;Now my pi isn’t overloaded with DNS requests, and my Internet is as snappy as it used to be.&lt;/p&gt;
&lt;p&gt;What happened, I think, was that a device on my network would try and lookup some name. The router would forward this request to the pi, which would then forward it back to the router, which would then send it back to the pi, etc. Boom. Infinite loop, and all my DNS requests got bogged down.&lt;/p&gt;
&lt;p&gt;I’m not very good with networking; that’s probably my biggest weakness. I learned a thing today, though!&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Fri, 11 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-12-11-raspberry-pi-dos/</guid></item><item><title>When algorithms meet debt...</title><link>https://stop.zona-m.net/2020/12/when-algorithms-meet-debt.../</link><description>&lt;p&gt;Everyone must be aware of four (no, five) problems. Especially lawyers.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 10 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/when-algorithms-meet-debt.../</guid></item><item><title>Email whitelisting</title><link>https://rjp.is/blogging/posts/2020/12/email-whitelisting/</link><description>Settings -&amp;gt; Mail -&amp;gt; Accounts -&amp;gt; [appropriate account] -&amp;gt; turn on Notes Go to iOS Notes. Go to the Folders view and find the same account as step 1. Create a note with the first line &amp;ldquo;Whitelist&amp;rdquo;, then a blank line, then each domain you want to whitelist on its own line. Wait for the automatic processing to pick up the changes (a few times a day.)
Note this isn&amp;rsquo;t a pure whitelist - instead it adds a base score of -12.</description><author>infrequent oscillations</author><pubDate>Thu, 10 Dec 2020 19:17:53 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/12/email-whitelisting/</guid></item><item><title>Sounds from Silence: Graeme Clark and the Bionic Ear story</title><link>https://macleodsawyer.com/books/sounds-from-silence/</link><description>&lt;p&gt;This story has a very deep place in my heart, my mother was born deaf and after countless surgeries in her early youth she was able to regain (or to have the start of) the hearing in her left ear. She is still entirely deaf in her right, but I am very happy that she can hear at all - if she hadn’t, both her and my own life would be far different (and I wouldn’t likely have existed at all!).&lt;/p&gt;
&lt;p&gt;Growing up I always had to subtitles on, driven to speak loudly and clearly, and learn just enough sign language (not much, but being italian grants you the starting ability to hand wave at all hours of the day). This story catalogues all the attempts to create and invent a medical device that could restore or grant the power of hearing. The story is excellently written, and written by the very man who has changed millions of lives over the past few decades, Professor Graeme Clark.&lt;/p&gt;
&lt;p&gt;This story goes into the thought process of the device, the manufacturing, the attempt to raise funding (many times! many failures!), the stress of integration within the deaf community, and many more. If you have an interest in technology and how it is a net-benefit of humanity, or are worried about the use of technology, this should be your first choice to see how great the world can be.&lt;/p&gt;</description><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Thu, 10 Dec 2020 14:06:36 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/books/sounds-from-silence/</guid></item><item><title>Link to https://amberwilson.co.uk/blog/grow-the-indieweb-with-webmentions/</title><link>https://qubyte.codes/links/1607597111642</link><description>&lt;p&gt;I really like webmentions, so it makes me happy when folk blog about them! &lt;a href="https://qubyte.codes/links/1607597111642"&gt;Grow the IndieWeb with Webmentions - Amber Wilson&lt;/a&gt;&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Thu, 10 Dec 2020 12:45:11 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/links/1607597111642</guid></item><item><title>Haskell coreutils - tee</title><link>https://www.anardil.net/2020/haskell-coreutils-tee.html</link><description>&lt;p&gt;Implementing tee in Haskell&lt;/p&gt;</description><author>Anardil</author><pubDate>Thu, 10 Dec 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://www.anardil.net/2020/haskell-coreutils-tee.html</guid></item><item><title>Downloading your Favorite YouTube Playlist Automatically</title><link>/youtube-playlist-downloader/</link><description>&lt;p&gt;In light of Youtube-DL being taken down from GitHub, I decided to give it a go with a use case I happened to have.&lt;/p&gt;
&lt;p&gt;Lately, I've been listening to lots of concerts/festival sets that are not available for traditional purchase. Although I have listened to them on youtube, I didn't want to have the web page open and the auto-play/queuing features are not as fledged out as a proper music player.&lt;/p&gt;
&lt;p&gt;I decided to write a quick script that I could run in a cron to pull down the latest version of the playlist I maintain. To keep an eye on it, I included a Slack webhook notification that let's me know when the playlist has been downloaded.&lt;/p&gt;
&lt;p&gt;My first version worked but I quickly realised that the script did not handle updates, only a complete re-download. To resolve this, youtube-dl has a &lt;code&gt;--download-archive&lt;/code&gt; flag that keeps track of downloaded videos.&lt;/p&gt;
&lt;p&gt;Check out the code below and hopefully you find it useful.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;#!/bin/bash

playlist_url=&amp;quot;https://www.youtube.com/playlist?list=ZZZ&amp;quot;

cd ~/Projects/music

youtube-dl --embed-thumbnail --download-archive downloaded.txt --no-post-overwrites --extract-audio --audio-quality 0 --format bestaudio --audio-format mp3 --yes-playlist --output &amp;quot;%(title)s-%(id)s.%(ext)s&amp;quot; $playlist_url

curl -X POST --data-urlencode &amp;quot;payload={\&amp;quot;username\&amp;quot;: \&amp;quot;youtubeb0t\&amp;quot;, \&amp;quot;text\&amp;quot;: \&amp;quot;Completed download of all Music playlist.\&amp;quot;, \&amp;quot;icon_emoji\&amp;quot;: \&amp;quot;:tv:\&amp;quot;}&amp;quot; https://hooks.slack.com/services/ZZZ/YYY
&lt;/code&gt;&lt;/pre&gt;</description><author/><pubDate>Thu, 10 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">/youtube-playlist-downloader/</guid></item><item><title>Bloom Filters - Much, much more than a space efficient hashmap!</title><link>https://boyter.org/posts/bloom-filter/</link><description>&lt;p&gt;A bloom filter is one of those data structures you are probably already aware of, or have at least heard about. For those looking for a simple recap, they are a probabilistic data structure which can be used to determine if something is in a set or not, giving a slight chance of returning a false positive result for some checks but while using less space than a full hashmap.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Thu, 10 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/bloom-filter/</guid></item><item><title>The planet is obese</title><link>https://stop.zona-m.net/2020/12/the-planet-is-obese/</link><description>&lt;p&gt;No, not humans. The WHOLE planet. We just take the merit.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 09 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/the-planet-is-obese/</guid></item><item><title>Requests in Python with requests package and Torpy</title><link>https://geo.rocks/post/requests-in-python/</link><description>&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre class="chroma" tabindex="0"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://webscraper.io/test-sites/e-commerce/allinone"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Wed, 09 Dec 2020 19:54:50 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/requests-in-python/</guid></item><item><title>The Strange Case of the Danish Aarhus Mafia</title><link>https://www.swyx.io/danish-mafia</link><description>Why are so many CS pioneers from Denmark?</description><author>swyx's site RSS Feed</author><pubDate>Wed, 09 Dec 2020 17:46:36 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/danish-mafia</guid></item><item><title>Leading with Data - Cascading Metrics</title><link>https://blog.harterrt.com/cascading_metrics.html</link><description>&lt;p&gt;It's surprisingly hard to lead a company with data.
There's a lot written about how to set good goals
and how to avoid common pitfalls (like &lt;a href="/surrogation.html"&gt;Surrogation&lt;/a&gt;)
but I haven't seen much written about the practicalities
of taking action on these metrics.&lt;/p&gt;
&lt;p&gt;I spent most of this year working with …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Wed, 09 Dec 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/cascading_metrics.html</guid></item><item><title>Emulating a Computer: Timing and Input</title><link>https://riv.dev/emulating-a-computer-part-4/</link><description>Correctly emulating time in a CHIP-8 emualtor.</description><author>River Gillis [riv.dev]</author><pubDate>Wed, 09 Dec 2020 04:44:00 GMT</pubDate><guid isPermaLink="true">https://riv.dev/emulating-a-computer-part-4/</guid></item><item><title>#!shebangs</title><link>https://voussoir.net/writing/shebangs</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;#!shebangs&lt;/h1&gt;&lt;ol id="table_of_contents"&gt;Table of contents&lt;li&gt;&lt;a href="#introduction"&gt;Introduction&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="#windows_file_extensions"&gt;Windows file extensions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#unix_shebangs"&gt;Unix shebangs&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#i_dont_like_shebangs"&gt;I don't like shebangs&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="#developer_over_user_or_else_byebye_checksums"&gt;Developer over user (or else bye-bye checksums)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#antiwindows_dogmatism"&gt;Anti-Windows dogmatism&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#pathext"&gt;PATHEXT&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#hedges"&gt;Hedges&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="#the_registry"&gt;The registry&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#mp3exe"&gt;.mp3.exe&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;a class="header_anchor_link" href="#introduction"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="windows_file_extensions"&gt;Windows file extensions&lt;a class="header_anchor_link" href="#windows_file_extensions"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On Windows, the file extension of a filename is used to automatically determine how the file should be opened when you double-click on it or run it on the command line. .exe are the kings, because they are Windows's native executables. For other extensions, the shell checks the registry to find the exe associated with the extension, and runs that program with your file as the first argument, plus the rest of your arguments. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; ipconfig.exe&lt;/code&gt; → runs directly&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; whatsmyip.py&lt;/code&gt; → &lt;code&gt;python.exe whatsmyip.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; dns.py www.example.com&lt;/code&gt; → &lt;code&gt;python.exe dns.py www.example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; clock.pyw&lt;/code&gt; → &lt;code&gt;pythonw.exe clock.pyw&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt; report.doc&lt;/code&gt; → &lt;code&gt;winword.exe report.doc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you remove the .exe extension from an executable file's name, the shell won't know what to do with it (but deeper APIs can still invoke it (&lt;a href="https://stackoverflow.com/questions/12655314/open-an-executable-file-without-an-exe-extension-with-shellexecute"&gt;one&lt;/a&gt;, &lt;a href="https://old.reddit.com/r/explainlikeimfive/comments/3iyn9a/eli5_how_do_computer_extensions_work_exe_inf_iso/culk1z9/"&gt;two&lt;/a&gt;)). That is to say, Windows does not inspect the content of files to determine their type for the purpose of double-click launching. Every file is either an exe or has an extension which maps to an exe, or has no extension and can't be associated to a program. &lt;a class="footnote_link" href="#footnote_text_1" id="footnote_link_1" title="[1] There is also .com, a legacy executable format which is natively executable, yet has a passthrough HKCR entry anyway, presumably because the shell is programmed to consult HKCR for anything that's not .exe. HKCR\comfile\shell\open\command\(Default)=&amp;quot;%1&amp;quot; %*"&gt;[1]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At no time does this prevent you from using any other executable to open a file. You can always &lt;code&gt;pythonw.exe dns.py&lt;/code&gt; or &lt;code&gt;winword.exe clock.pyw&lt;/code&gt;. Extensions are not restrictions, they are just shortcuts to launching your executable of choice.&lt;/p&gt;
&lt;p&gt;&lt;a class="footnote_text" href="#footnote_link_1" id="footnote_text_1"&gt;[1]&lt;/a&gt; There is also .com, a &lt;a href="https://en.wikipedia.org/wiki/COM_file"&gt;legacy executable format&lt;/a&gt; which is natively executable, yet has a passthrough HKCR entry anyway, presumably because the shell is programmed to consult HKCR for anything that's not .exe. &lt;code&gt;HKCR\comfile\shell\open\command\(Default)="%1" %*&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="unix_shebangs"&gt;Unix shebangs&lt;a class="header_anchor_link" href="#unix_shebangs"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On Unix operating systems, the extension is not used to help execute the file. Instead,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The file must have the &lt;code&gt;x&lt;/code&gt; permission, aka "executable bit", enabled by &lt;code&gt;chmod +x filename&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the file is a native executable, it will run directly. Otherwise, the system will look for the shebang. The system reads the first few bytes of the file to figure this out.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Shebang_(Unix)"&gt;shebang&lt;/a&gt; is a line which must be at the very top of the file and must start with &lt;code&gt;#!&lt;/code&gt;. Then, a path to an executable is given, which will actually interpret and run the remainder of the file. A Python file with a shebang might look like this:&lt;/p&gt;
&lt;div class="highlight python"&gt;&lt;pre&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can save this file using any extension you want, or no extension at all, and run it by calling &lt;code&gt;chmod +x ./filename&lt;/code&gt; and then &lt;code&gt;./filename&lt;/code&gt;. As always, you're welcome to pass the file as an argument to any other executable if you need to use a different interpreter.&lt;/p&gt;
&lt;p&gt;One of the principles here is that executables become abstractions, black boxes. The idea is that as a user, when you run some &lt;code&gt;program&lt;/code&gt; on the command line, you shouldn't need to know or care whether &lt;code&gt;program&lt;/code&gt; is a shell builtin, or an alias, or an executable on the PATH; and you shouldn't need to care what language it's written in. You could swap out a &lt;code&gt;dns&lt;/code&gt; program written in bash with one written in Python, and your callers won't know the difference.&lt;/p&gt;
&lt;p&gt;But...&lt;/p&gt;
&lt;h2 id="i_dont_like_shebangs"&gt;I don't like shebangs&lt;a class="header_anchor_link" href="#i_dont_like_shebangs"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And you won't find a shebang on any of the code I write.&lt;/p&gt;
&lt;p&gt;For these arguments, suppose that the file in question is checked into version control (e.g. git), or is seeding on IPFS, or is otherwise being hash-validated, or is restored to factory condition on every software/OS update, such that "just change the shebang" is not an appropriate solution. The file is handcuffed to the interpreter specified by the shebang.&lt;/p&gt;
&lt;p&gt;My dislike for shebangs is part principle and part practical. Principles like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;As a user, why should I be expected to agree with the developer's choice of interpreter and pathing (&lt;code&gt;/bin/x&lt;/code&gt; vs &lt;code&gt;/usr/bin/x&lt;/code&gt; vs &lt;code&gt;/usr/bin/env x&lt;/code&gt; ...)? You can search stackoverflow and find &lt;a href="https://stackoverflow.com/questions/16365130/what-is-the-difference-between-usr-bin-env-bash-and-usr-bin-bash"&gt;plenty&lt;/a&gt; of &lt;a href="https://unix.stackexchange.com/questions/29608/why-is-it-better-to-use-usr-bin-env-name-instead-of-path-to-name-as-my"&gt;discussions&lt;/a&gt; about the pros and cons of each technique. But I'm the user and I'll do what I want, stop subjecting me to your chosen set of pros and cons when I'm the one running the program.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As a developer, why should I add this boilerplate to every file I write? Why should I be encoding "this is how you run my program" in the file, when the user can simply configure their system to do it however they like best?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And practicals like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;My &lt;code&gt;python&lt;/code&gt; is really not the same as your &lt;code&gt;python&lt;/code&gt;, so stop assuming &lt;code&gt;/usr/bin/env python&lt;/code&gt; is the right thing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The shebang handcuffs also apply to hardlinks / symlinks which I might intentionally want to behave differently.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I will continue to use Python as the example language for this argument because that's what I'm most familiar with, but you may extend these issues to any case where there are alternative interpreters — even if the alternatives haven't been invented yet!&lt;/p&gt;
&lt;h3 id="developer_over_user_or_else_byebye_checksums"&gt;Developer over user (or else bye-bye checksums)&lt;a class="header_anchor_link" href="#developer_over_user_or_else_byebye_checksums"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Back in the day, Python code was written in Python 2, and it was fair to assume that the executable named &lt;code&gt;python&lt;/code&gt; on the PATH was the Python 2 interpreter, so people wrote shebangs pointing to &lt;code&gt;python&lt;/code&gt; expecting P2. Now, code is written in Python 3 and systems are shipping with &lt;code&gt;python&lt;/code&gt; referring to P3, but some P2 tools are still around and in use. So now their shebang is wrong, and will be wrong for the rest of time, and the user will always need to explicitly call &lt;code&gt;python2 program.py&lt;/code&gt; for as long as they hang on to that file. Great, thanks.&lt;/p&gt;
&lt;p&gt;On an extension-based system, the solution is easy. Although the &lt;code&gt;program.py&lt;/code&gt; file might be checked into version control, there's nothing stopping me from creating a symlink or hardlink on my PATH called &lt;code&gt;program.py2&lt;/code&gt; that points to the file, and an extension mapping from &lt;code&gt;.py2&lt;/code&gt; to &lt;code&gt;python2.exe&lt;/code&gt;. This requires no changes to the file content itself, so it won't interfere with the file's hash.&lt;/p&gt;
&lt;p&gt;To be clear, the file layout I would use for maintaining a Python2 and Python3 program simultaneously is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;D:\
├───cmd\ on the PATH
│   ├───a_program.py2 =&amp;gt; D:\software\a_program\a_program.py
│   └───b_program.py =&amp;gt; D:\software\b_program\b_program.py
└───software\
    ├───a_program\
    │   └───a_program.py
    └───b_program\
        └───b_program.py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So even if &lt;code&gt;a_program.py&lt;/code&gt; was written when &lt;code&gt;.py&lt;/code&gt; implied Python2 instead of Python3, it doesn't matter because the names I actually execute are those in \cmd on my PATH. I can name my links any way I want to take advantage of the file extension mapping, while the real software is not affected whatsoever. See &lt;a href="/writing/master_of_my_domain"&gt;Master of my domain&lt;/a&gt; for more about my software management practices.&lt;/p&gt;
&lt;p&gt;Sure, you can say that nobody should be using P2 programs any more, but that's moving the goalposts. Let's say someone wants to run some particular set of Python scripts through &lt;a href="https://www.pypy.org/"&gt;PyPy&lt;/a&gt; or &lt;a href="https://www.python.org/download/alternatives/"&gt;any other implementation&lt;/a&gt;. What then? To give one non-Python example, here is an SO thread about &lt;a href="https://stackoverflow.com/questions/10376206/what-is-the-preferred-bash-shebang"&gt;the right shebang for bash&lt;/a&gt;. To my eyes it's a disaster:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some people use &lt;code&gt;/bin/sh&lt;/code&gt; under the assumption that all people have that symlinked to bash, which is wrong.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/bin/bash&lt;/code&gt; or &lt;code&gt;/usr/bin/bash&lt;/code&gt; might be ok, but there's no guarantee that's the path for &lt;code&gt;bash&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr/bin/env bash&lt;/code&gt; is probably most common, but there's &lt;em&gt;still&lt;/em&gt; no guarantee that's the path for &lt;code&gt;env&lt;/code&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On a shebang-based system, the choices are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Edit the shebang in the file, thus changing its hash.&lt;/li&gt;
&lt;li&gt;Create a symlink for the interpreter executable that matches the developer's shebang but actually points to the the user's preferred interpreter. E.g. the program expects &lt;code&gt;/usr/bin/python&lt;/code&gt; so I create a symlink &lt;code&gt;/usr/bin/python =&amp;gt; /.../python3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a separate launcher script, a one-liner shell file that calls the preferred interpreter with the script as an argument — essentially a handwritten symlink. This option is most similar to the extension-based solution, except that if the preferred interpreter changes you've got to update all of the launcher files manually.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="antiwindows_dogmatism"&gt;Anti-Windows dogmatism&lt;a class="header_anchor_link" href="#antiwindows_dogmatism"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I don't like shebangs, but it's not such a big deal — all I have to do is not use them and that's that. They pose no restrictions upon me as long as I call the interpreter myself.&lt;/p&gt;
&lt;p&gt;What actually bothers me are the Unix elitists who in a single breath will mock Windows users as being stupid, helpless &lt;a href="https://en.wikipedia.org/wiki/Luser"&gt;lusers&lt;/a&gt;, pushed around by the Big Bad File Extension Who Dictates How Files Are Executed... then write a shebang that handcuffs their file to the name of the anticipated interpreter executable. A .rose by any other extension would smell as sweet.&lt;/p&gt;
&lt;p&gt;To demonstrate this isn't a strawman, here are some actual quotes gathered from around the 'net:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I know that files are identified by an identifier on their first line, which is why Linux files don't have file endings. But I liked file endings a lot. Isn't it nice to be able to tell what a file is/does without having to open it? In Windows I could open up a folder and immediately have a lot of information about the folder and the files within it, just from the file endings.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;If you're asking if there's some kind of setting that will "show" file extensions on system files, no, that is not a thing.
You seem really hung up on the idea that filename extensions are a superior method of associating type information with files. Most Linux applications just don't use this method, but have other ways of determining that information. Your question is based on the assumption that this is some kind of feature which has been disabled and can be re-enabled, which is fundamentally untrue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;I will not: I will not allow the ignorance that spews from Redmond to infect my software.&lt;/p&gt;
&lt;p&gt;I will not: I will not cater to users with a broken OS.&lt;/p&gt;
&lt;p&gt;I will not: I will not bother because it represents the minimal technical hurdle for Windows users.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;[A developer renames his &lt;code&gt;readme&lt;/code&gt; to &lt;code&gt;readme.txt&lt;/code&gt;]&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;While it may make logical sense to some people, the ultimate implication when you see a .txt file is that the developer uses Windows. I'm not sure a lot of developers are comfortable with that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;No. File extensions are stupid and broken.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Why? What's wrong with encoding metadata about the content in the filename?&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Because it then prevents me from changing the filename the way I want to. Because legacy garbage.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;Interesting... most commenters here (so far) seem to be against the extension. Can someone explain why? "README" doesn't tell me if it's text, or markdown, or HTML, or anything. Having ".txt" lets me know the format without opening it first to see.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I hate them because they're an abstraction leak. The type of a file's content is different from the application that I want to use to manipulate it, which both are in turn different from the name I chose to give the file. That current file systems and the GUI representations on top of them are so badly designed as to confuse three unrelated concepts is a failing of software and as clear an indication as you could ask for of the triumph of Worse Is Better.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;These two in particular point out a problem that's already solved on Windows:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;You should not use an extension for executables, as they they are not interchangeable. Imagine that you have a shell script a.sh, then re-write in python a.py, you now have to change every program that calls your script, you have leaked an implementation detail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;If you give a shell script a .sh extension, you'll have to type that .sh as part of the command name when starting it. That's the main reason why I don't like putting that extension in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We need to talk about PATHEXT.&lt;/p&gt;
&lt;h3 id="pathext"&gt;PATHEXT&lt;a class="header_anchor_link" href="#pathext"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On Windows, there is an environment variable called PATHEXT. It contains a semicolon-separated list of file extensions that you &lt;strong&gt;don't&lt;/strong&gt; have to type when running programs on the command line. For example, if .py is on PATHEXT, then you can just ask for &lt;code&gt;dns&lt;/code&gt; on the commandline and &lt;code&gt;dns.py&lt;/code&gt; will be a valid candidate. On the other hand, if PATHEXT is blank, then you must type the file extension for every executable, even .exe. At that point, the shell builtins will be the only extensionless commands you can run.&lt;/p&gt;
&lt;p&gt;The order of extensions on PATHEXT indicates the order of preference for candidate files.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\anywhere&amp;gt;set PATH=C:\cmd;C:\Windows\System32
C:\anywhere&amp;gt;set PATHEXT=.py;.bat;.exe
C:\anywhere&amp;gt;where dns
C:\cmd\dns.bat
C:\cmd\dns.exe
C:\cmd\dns.py
C:\anywhere&amp;gt;dns
You ran dns.py!&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;C:\anywhere&amp;gt;set PATHEXT=.bat;.py;.exe
C:\anywhere&amp;gt;dns
You ran dns.bat!&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;C:\anywhere&amp;gt;set PATHEXT=.exe;.bat;.py
C:\anywhere&amp;gt;dns
You ran dns.exe!&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;C:\anywhere&amp;gt;set PATHEXT=.py
C:\anywhere&amp;gt;where.exe dns
C:\cmd\dns.py
C:\anywhere&amp;gt;where.exe dns.bat
C:\cmd\dns.bat
C:\anywhere&amp;gt;dns
You ran dns.py!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice I am now calling &lt;code&gt;where.exe&lt;/code&gt;, since .exe is no longer on PATHEXT, thus &lt;code&gt;where&lt;/code&gt; no longer matches &lt;code&gt;C:\Windows\System32\where.exe&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\anywhere&amp;gt;set PATHEXT=
C:\anywhere&amp;gt;where.exe dns
INFO: Could not find files for the given pattern(s).
C:\anywhere&amp;gt;where.exe dns.py
C:\cmd\dns.py
C:\anywhere&amp;gt;dns.py
You ran dns.py!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Regardless of the value of PATHEXT, you are always allowed to specify the full name of the file, like &lt;code&gt;dns.py&lt;/code&gt;. Even if &lt;code&gt;.py&lt;/code&gt; is not on PATHEXT, &lt;code&gt;dns.py&lt;/code&gt; itself is still on the PATH. PATHEXT only affects the evaluation of the bare name, &lt;code&gt;dns&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And just like that, we've achieved the black box principle of executables. You can rewrite a .bat program in .py, or you can supercede a System32 exe with a script of your own. The only thing you can't do is supercede the shell builtins — &lt;code&gt;dir&lt;/code&gt; always does &lt;code&gt;dir&lt;/code&gt; even if you have a candidate in the cwd or on the PATH — you'll have to call those files by their extensioned names.&lt;/p&gt;
&lt;p&gt;Between my public &lt;a href="https://git.voussoir.net/voussoir/cmd"&gt;cmd&lt;/a&gt; repository and my non-public cmd folder, I've got more than 180 .py and .bat files making up my command line toolkit. Of course I'm not specifying the extensions when I run them, guys.&lt;/p&gt;
&lt;h2 id="hedges"&gt;Hedges&lt;a class="header_anchor_link" href="#hedges"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It's time for me to bat for the other team and explain why Windows's solution is also bad.&lt;/p&gt;
&lt;h3 id="the_registry"&gt;The registry&lt;a class="header_anchor_link" href="#the_registry"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Windows registry is not a beautiful place, and the mapping of extensions to executables is not as easy as one would hope. With Windows 10, Microsoft has introduced some new APIs for dealing with extension associations, mostly because with the old APIs, inconsiderate software developers would non-optionally dive into the registry and set their program as the default for a bunch of filetypes during install, leaving the average user without a clear understanding of how to revert. However, I haven't learned these new systems because Windows refers to them as "default apps" and I have a vendetta against the word "app" so I avoid that whole interface at all costs. When I need to edit extensions, I always just open the registry and do it myself.&lt;/p&gt;
&lt;p&gt;The most straightforward technique that I'm familiar with is to create a key &lt;code&gt;HKEY_CLASSES_ROOT\.ext&lt;/code&gt;. You can give it a &lt;code&gt;(Default)&lt;/code&gt; value containing the name of another HKCR key, and this will act as a redirect for the remainder of the process. Then, beneath either the &lt;code&gt;.ext&lt;/code&gt; or the redirect destination, you create &lt;code&gt;shell\open\command\(Default)="C:\myprogram.exe" "%L" %*&lt;/code&gt; for the most simple invocation.&lt;/p&gt;
&lt;p&gt;Beyond that, it's all a little confusing with keys like OpenWithList, OpenWithProgids, and values like Content Type and PerceivedType (do they do anything for files without an explicit &lt;code&gt;shell\open\command&lt;/code&gt;?), and if you want to make two extensions that run the same program but have different icons (.txt, .srt, .css → text editor) you wind up duplicating the whole shell command for each of them because you can't do multiple-inheritance style mappings. Unless I'm missing something, which is also likely.&lt;/p&gt;
&lt;p&gt;Also, there are &lt;em&gt;even more&lt;/em&gt; keys in &lt;code&gt;HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ext\UserChoice&lt;/code&gt;. When dealing with extensions that I didn't make myself, NirSoft's &lt;a href="https://www.nirsoft.net/utils/file_types_manager.html"&gt;filetypesman&lt;/a&gt; helps me locate their hodgepodge of keys.&lt;/p&gt;
&lt;p&gt;The point is that while I prefer extension-executable systems over shebang systems, that does not mean I'm praising the registry as it exists today.&lt;/p&gt;
&lt;h3 id="mp3exe"&gt;.mp3.exe&lt;a class="header_anchor_link" href="#mp3exe"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A common criticism of Windows is that non-savvy users can be tricked into downloading some file called "Hotel California.mp3.exe" and running it because they think it's an mp3 file. This is made 1,000 times worse by the unfathomable, unforgiveable, bone-headed decision by Microsoft to hide file extensions of "known file types" by default, hiding the &lt;code&gt;.exe&lt;/code&gt; but leaving the &lt;code&gt;.mp3&lt;/code&gt;. It boggles the mind and stupefies the senses that this default is still in place after all these years, but it is.&lt;/p&gt;
&lt;p&gt;On Unix, the downloaded file would not be executable until you &lt;code&gt;chmod +x&lt;/code&gt;, which is something you can't trick most people into doing. On Windows, the .exe requires no activation and is ready to detonate as soon as you double-click on it.&lt;/p&gt;
&lt;p&gt;That's why UAC was added to Windows, but users will Accept any dialog box that stands between them and their mp3 without reading it, so that hasn't changed much.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;a class="header_anchor_link" href="#conclusion"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let me re-quote two of the comments I shared above:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Because it then prevents me from changing the filename the way I want to.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;The type of a file's content is different from the application that I want to use to manipulate it, which both are in turn different from the name I chose to give the file&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These comments make a good point, that it would be nice to have the ability to associate files to programs without having to name them a certain way. Computing is still a relatively young field, and I wouldn't mind seeing new ways of solving this problem. I mentioned that I'd like to see some multiple-inheritance, which would simplify icon management, default programs, and human-friendly type names. But, by my insistence on maintaining file hashes, you can infer that I'd like a solution out-of-band from the file content itself. Current implementations of &lt;a href="https://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_(ADS)"&gt;alternate data streams&lt;/a&gt; are not ready to steal this stage because they aren't transmitted when sharing the file over the internet, for better and worse.&lt;/p&gt;
&lt;p&gt;For now, I am satisfied with file extensions (as long as I wrangle the registry myself), and I want the Unix elitists to see how I use them in my favor; that they impose no friction on my workflow at all. inb4 Stockholm syndrome.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/shebangs/shebangs.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/3475cb0abf63172e6392487ffaf41755f71a18e3"&gt;&lt;time datetime="2023-09-18T21:01:09-07:00"&gt;2023-09-18&lt;/time&gt; Replace github links with git.voussoir.net.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/3946a09872ee8b40ea8420b5587e35ccb3da9556"&gt;&lt;time datetime="2020-12-08T18:35:08-08:00"&gt;2020-12-08&lt;/time&gt; Add shebangs.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Wed, 09 Dec 2020 04:35:08 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/shebangs</guid></item><item><title>Quote 1</title><link>https://www.wints.org/quotes/1/</link><description>&lt;p&gt;For my part, I travel not to go anywhere, but to go. I travel for travel&amp;rsquo;s sake. The great affair is to move.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Robert Louis Stevenson&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/1/</guid></item><item><title>Quote 10</title><link>https://www.wints.org/quotes/10/</link><description>&lt;p&gt;We do not win our strength and stability by mastering ideas, but by being mastered by them—held in their grip.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Charles Henry Parkhurst&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/10/</guid></item><item><title>Quote 11</title><link>https://www.wints.org/quotes/11/</link><description>&lt;p&gt;Purpose, and to be thoroughly wedded to that purpose, is three quarters of salvation. It is sad to reflect how much motiveless insipidity there is among us that is steadily resolving itself into ethical rot, for no other reason than that it has never been awakened into vigor and electrified into effect by the touch of a supreme purpose.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Charles Henry Parkhurst&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/11/</guid></item><item><title>Quote 12</title><link>https://www.wints.org/quotes/12/</link><description>&lt;p&gt;Money is made on a competitive plane. Wealth is made on a creative plane.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Wallace Wattles&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/12/</guid></item><item><title>Quote 13</title><link>https://www.wints.org/quotes/13/</link><description>&lt;p&gt;Truth = Honesty&lt;/p&gt;
&lt;p&gt;Love = Compassion&lt;/p&gt;
&lt;p&gt;Courage = Valor&lt;/p&gt;
&lt;p&gt;Truth + Love = Justice&lt;/p&gt;
&lt;p&gt;Truth + Courage = Honor&lt;/p&gt;
&lt;p&gt;Love + Courage = Sacrifice&lt;/p&gt;
&lt;p&gt;Truth + Love + Courage = Spirituality&lt;/p&gt;
&lt;p&gt;The absence of Truth, Love, and Courage is Pride, the opposite of which is Humility.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Steve Pavlina&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/13/</guid></item><item><title>Quote 14</title><link>https://www.wints.org/quotes/14/</link><description>&lt;p&gt;For every one of us, living in this world means waiting for our end. Let whoever can  win glory before death. When a warrior is gone, that will be his best and only bulwark… Endure your troubles today. Bear up and be the man I expect you to be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Beowulf&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/14/</guid></item><item><title>Quote 15</title><link>https://www.wints.org/quotes/15/</link><description>&lt;p&gt;Self-respect is the fruit of discipline; the sense of dignity grows with the ability to say no to oneself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Abraham J. Heschel&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/15/</guid></item><item><title>Quote 16</title><link>https://www.wints.org/quotes/16/</link><description>&lt;p&gt;Seek freedom and become captive of your desires, seek discipline and find your liberty.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Frank Herbert (Dune)&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/16/</guid></item><item><title>Quote 17</title><link>https://www.wints.org/quotes/17/</link><description>&lt;p&gt;The reasonable man adapts himself to the world; the unreasonable one persists to adapt the world to himself. Therefore all progress depends on the unreasonable man.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-George Bernard Shaw&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/17/</guid></item><item><title>Quote 18</title><link>https://www.wints.org/quotes/18/</link><description>&lt;p&gt;&amp;ldquo;The sole cause of man&amp;rsquo;s unhappiness is that he does not know how to stay quietly in his room.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Pascal&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/18/</guid></item><item><title>Quote 19</title><link>https://www.wints.org/quotes/19/</link><description>&lt;p&gt;I came over from Greece when I was 17 and started out working in a market. I worked so much that I supported my mother, my father, and put my brother through college. Now my kids have everything, and don&amp;rsquo;t appreciate anything. You Americans cut &amp;rsquo;em off when they&amp;rsquo;re 18. And that’s probably for the best. But we can’t do that, cause we’re Greek. They&amp;rsquo;re ours until they&amp;rsquo;re married.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Greek Immigrant from the site &amp;ldquo;Humans of New York&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/19/</guid></item><item><title>Quote 2</title><link>https://www.wints.org/quotes/2/</link><description>&lt;p&gt;I am in the habit of looking not so much to the nature of a gift as to the spirit in which it is offered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Robert Louis Stevenson&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/2/</guid></item><item><title>Quote 20</title><link>https://www.wints.org/quotes/20/</link><description>&lt;p&gt;A human being should be able to change a diaper, plan an invasion, butcher a hog, conn a ship, design a building, write a sonnet, balance accounts, build a wall, set a bone, comfort the dying, take orders, give orders, cooperate, act alone, solve equations, analyze a new problem, pitch manure, program a computer, cook a tasty meal, fight efficiently, die gallantly. Specialization is for insects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Robert A. Heinlein&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/20/</guid></item><item><title>Quote 21</title><link>https://www.wints.org/quotes/21/</link><description>&lt;p&gt;Do not pray for an easy life. Pray for the strength to endure a difficult one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Bruce Lee&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/21/</guid></item><item><title>Quote 22</title><link>https://www.wints.org/quotes/22/</link><description>&lt;p&gt;Make mistakes of ambition and not mistakes of sloth.  Develop the strength to do bold things, not the strength to suffer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Machiavelli&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/22/</guid></item><item><title>Quote 23</title><link>https://www.wints.org/quotes/23/</link><description>&lt;p&gt;A master in the art of living draws no sharp distinction between his work and his play; his labor and his leisure; his mind and his body; his education and his recreation. He hardly knows which is which. He simply pursues his vision of excellence through whatever he is doing, and leaves others to determine whether he is working or playing. To himself, he always appears to be doing both.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/23/</guid></item><item><title>Quote 24</title><link>https://www.wints.org/quotes/24/</link><description>&lt;p&gt;When I was a boy of 14, my father was so ignorant I could hardly stand to have the old man around. But when I got to be 21, I was astonished at how much the old man had learned in seven years.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Mark Twain&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/24/</guid></item><item><title>Quote 25</title><link>https://www.wints.org/quotes/25/</link><description>&lt;p&gt;We are in an age that assumes the narrowing trends of specialization to be logical, natural, and desirable. Consequently, society expects all earnestly responsible communication to be crisply brief. Advancing science has now discovered that all the known cases of biological extinction have been caused by overspecialization, whose concentration of only selected genes sacrifices general adaptability. Thus the specialist’s brief for pinpointing brevity is dubious. In the meantime, humanity has been deprived of comprehensive understanding. Specialization has bred feelings of isolation, futility, and confusion in individuals. It has also resulted in the individual’s leaving responsibility for thinking and social action to others. Specialization breeds biases that ultimately aggregate as international and ideological discord, which in turn leads to war.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/25/</guid></item><item><title>Quote 26</title><link>https://www.wints.org/quotes/26/</link><description>&lt;p&gt;What man actually needs is not some tension-less state but rather the striving and struggling for some goal worthy of him.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Viktor Frankl&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/26/</guid></item><item><title>Quote 27</title><link>https://www.wints.org/quotes/27/</link><description>&lt;p&gt;Man’s commonest weakness, his aversion to being unpleasantly conspicuous, pointed at, shunned, as being on the unpopular side. Its other name is Moral Cowardice, and is the supreme feature of the make-up of 9,999 men in the 10,000.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Mark Twain&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/27/</guid></item><item><title>Quote 28</title><link>https://www.wints.org/quotes/28/</link><description>&lt;p&gt;The growing good of the world is partly dependent on unhistoric acts; and that things are not so ill with you and me as they might have been, is half owing to the number who lived faithfully a hidden life, and rest in unvisited tombs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-George Eliot (Middlemarch)&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/28/</guid></item><item><title>Quote 29</title><link>https://www.wints.org/quotes/29/</link><description>&lt;p&gt;Nobody should start to undertake a large project. You start with a small &lt;em&gt;trivial&lt;/em&gt; project, and you should never expect it to get large. If you do, you&amp;rsquo;ll just overdesign and generally think it is more important than it likely is at that stage. Or worse, you might be scared away by the sheer size of the work you envision. So start small, and think about the details. Don&amp;rsquo;t think about some big picture and fancy design. If it doesn&amp;rsquo;t solve some fairly immediate need, it&amp;rsquo;s almost certainly over-designed. And don&amp;rsquo;t expect people to jump in and help you. That&amp;rsquo;s not how these things work. You need to get something half-way &lt;em&gt;useful&lt;/em&gt; first, and then others will say &amp;ldquo;hey, that &lt;em&gt;almost&lt;/em&gt; works for me&amp;rdquo;, and they&amp;rsquo;ll get involved in the project.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/29/</guid></item><item><title>Quote 3</title><link>https://www.wints.org/quotes/3/</link><description>&lt;p&gt;If your morals make you dreary, depend on it, they are wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Robert Louis Stevenson&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/3/</guid></item><item><title>Quote 30</title><link>https://www.wints.org/quotes/30/</link><description>&lt;p&gt;Organizations are not a source of security but they are a source of identity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Bill Taylor, on Loyalty at Work&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/30/</guid></item><item><title>Quote 31</title><link>https://www.wints.org/quotes/31/</link><description>&lt;p&gt;Our forefathers had civilization inside themselves, the wild outside. We live in the civilization they created, but within us the wilderness still lingers. What they dreamed, we live, and what they lived, we dream.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-T. K. Whipple&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/31/</guid></item><item><title>Quote 32</title><link>https://www.wints.org/quotes/32/</link><description>&lt;p&gt;Understand the difference between dreams, goals, and expectations. Dreams live in far off places. They may come to us while we walk, hike, bike or take a shower. I like to think of dreams as the shining gemstones, just out of reach. Knowing that we have the desire to reach out and grab these gemstones gives us the motivation to get out of bed each morning.&lt;/p&gt;
&lt;p&gt;Goals are specific, measurable, achievable, results-focused and time bound items. Goals are things we’re actually going to do and commit to doing. I equate expectations to a yardstick.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/32/</guid></item><item><title>Quote 33</title><link>https://www.wints.org/quotes/33/</link><description>&lt;p&gt;The customers are buying the product just as fast as you can make it &amp;ndash; or usage is growing just as fast as you can add more servers. Money from customers is piling up in your company checking account. You&amp;rsquo;re hiring sales and customer support staff as fast as you can.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Marc Andreesen on product/market fit&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/33/</guid></item><item><title>Quote 34</title><link>https://www.wints.org/quotes/34/</link><description>&lt;p&gt;If your friend was standing next to you and their hair was on fire, that fire would be the only thing they really cared about in this world. It wouldn’t matter if they were hungry, just suffered a bad breakup, or were running late to a meeting—they’d prioritize putting the fire out. If you handed them a hose—the perfect product/solution—they would put the fire out immediately and go on their way. If you handed them a brick they would still grab it and try to hit themselves on the head to put out the fire. You need to find problems so dire that users are willing try half-baked, v1, imperfect solutions.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/34/</guid></item><item><title>Quote 35</title><link>https://www.wints.org/quotes/35/</link><description>&lt;p&gt;To burn always with this hard, gem-like flame, to maintain this ecstasy, is success in life.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Walter Pater&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/35/</guid></item><item><title>Quote 36</title><link>https://www.wints.org/quotes/36/</link><description>&lt;p&gt;Our language has wisely sensed the two sides of being alone. It has created the word loneliness to express the pain of being alone. And it has created the word solitude to express the glory of being alone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Paul Tillich&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/36/</guid></item><item><title>Quote 37</title><link>https://www.wints.org/quotes/37/</link><description>&lt;p&gt;All the world&amp;rsquo;s a stage, And all the men and women merely players; They have their exits and their entrances, And one man in his time plays many parts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-William Shakespeare&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/37/</guid></item><item><title>Quote 38</title><link>https://www.wints.org/quotes/38/</link><description>&lt;p&gt;..if you simply change your goal from &amp;ldquo;writing well&amp;rdquo; to &amp;ldquo;writing badly,&amp;rdquo; you will be a veritable fucking fountain of material, because guess what, man, we don&amp;rsquo;t like to admit it, because we&amp;rsquo;re raised to think lack of confidence is synonymous with paralysis, but, let&amp;rsquo;s just be honest with ourselves and each other: we can only hope to be good writers.
We can only ever hope and wish that will ever happen, that&amp;rsquo;s a bird in the bush. The one in the hand is: we suck. We are terrified we suck, and that terror is oppressive and pervasive because we can VERY WELL see the possibility that we suck. We are well acquainted with it.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/38/</guid></item><item><title>Quote 39</title><link>https://www.wints.org/quotes/39/</link><description>&lt;p&gt;I want to be my own reader.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Kartik Subbu when asked who does he want to write for&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/39/</guid></item><item><title>Quote 4</title><link>https://www.wints.org/quotes/4/</link><description>&lt;p&gt;Whatever you can do or dream you can, begin it. Boldness has genius, power and magic in it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Goethe&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/4/</guid></item><item><title>Quote 40</title><link>https://www.wints.org/quotes/40/</link><description>&lt;ol&gt;
&lt;li&gt;Remade website to be more professional looking, faster, more focused towards SEO, mobile friendly. I could write many pages on this :) but following online guides will get you in the ballpark&lt;/li&gt;
&lt;li&gt;Started writing interesting content. Truly good content is a PITA and you need to be a decent writer to make something compelling, but our first good article got us more traffic than the entire site with over 100 content pages.&lt;/li&gt;
&lt;li&gt;New tools. everything linked together to see where our sales were coming from. Phone system, website, live chat, in person. All of our leads funneled into one system. We could see what was getting people and what wasn&amp;rsquo;t&lt;/li&gt;
&lt;li&gt;Online advertising. Locally first, expand AD reach as campaign becomes more nationally competitive. Make sure all the tools you setup continue to track where all these leads are coming from&lt;/li&gt;
&lt;li&gt;Better &amp;ldquo;convincing&amp;rdquo; of clients that we&amp;rsquo;re legit. Company T-Shirts and swag. Hotel-type exaggerated pictures of our team and office. Meet the team page. Professional website like I mentioned earlier. FB, google maps, yellowpages, wherever we could get a free listing. Automated scheduling systems for client meetings, phone tree for calls, tons of previous work repurposed as marketing material for clients to see. Listing our bigger clients on our website. 800 phone #. All the hallmarks of a big successful business even though we weren&amp;rsquo;t exactly gave clients a much bigger confidence in our abilities and enabled us to charge more.&lt;/li&gt;
&lt;li&gt;Marketing toward high value targets &amp;ndash; we needed to get the ear of C level and VP&amp;rsquo;s. Concentrating on the fact that we were a US company without outsourcing. Marketing to wealthy areas &amp;ldquo;doctorville&amp;rdquo; we called it. Targeted marketing to business corridors. We went deep, going as far as checking the AS of your IP address and whether any services were running on it. A surprising amount of the time would could link an IP back to a company, so we could quietly market to your company just from you visiting our site.&lt;/li&gt;
&lt;li&gt;competitive research. Found our biggest local competitors. Quietly outbid them on all their ad keywords. Even more quietly made sure we had all the backlinks they did on search. Got a list of their clients one way or another, marketed directly to their clients already knowing their weaknesses from our clients who previously worked with those competitors. One competitor hosted their own servers, so I figured out who owned the IP and tracked ownership of the company through their email server. Another put their email address at the bottom of all public sites they wrote, a simple targeted google search returned all/most of their clients&amp;rsquo; sites. Another had a &amp;ldquo;client login&amp;rdquo; page setup on all of their sites that had a redirect to their main page. Searching for backlinks using SEO tools revealed most of these client sites.
Lots more. It took a lot of creative thinking and some failures :)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;-&lt;a href="https://news.ycombinator.com/item?id=13551066"&gt;79d697i6fdif answering &amp;ldquo;what&amp;rsquo;s your top growth strategy?&amp;rdquo;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/40/</guid></item><item><title>Quote 41</title><link>https://www.wints.org/quotes/41/</link><description>&lt;p&gt;Nobody tells this to people who are beginners, I wish someone told me. All of us who do creative work, we get into it because we have good taste. But there is this gap. For the first couple years you make stuff, it’s just not that good. It’s trying to be good, it has potential, but it’s not. But your taste, the thing that got you into the game, is still killer. And your taste is why your work disappoints you. A lot of people never get past this phase, they quit. Most people I know who do interesting, creative work went through years of this. We know our work doesn’t have this special thing that we want it to have. We all go through this. And if you are just starting out or you are still in this phase, you gotta know its normal and the most important thing you can do is do a lot of work. Put yourself on a deadline so that every week you will finish one story. It is only by going through a volume of work that you will close that gap, and your work will be as good as your ambitions. And I took longer to figure out how to do this than anyone I’ve ever met. It’s gonna take awhile. It’s normal to take awhile. You’ve just gotta fight your way through.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/41/</guid></item><item><title>Quote 42</title><link>https://www.wints.org/quotes/42/</link><description>&lt;p&gt;A man is honorable in proportion to the personal risks he takes for his opinion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Nassim Taleb&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/42/</guid></item><item><title>Quote 43</title><link>https://www.wints.org/quotes/43/</link><description>&lt;p&gt;Life gets interesting when we fail, because it&amp;rsquo;s a sign that we&amp;rsquo;ve surpassed ourselves.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Clemenceau&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/43/</guid></item><item><title>Quote 44</title><link>https://www.wints.org/quotes/44/</link><description>&lt;p&gt;Of course I agree with the preacher of Ecclesiastes that there is a time to love and a time to die—and when my skein runs out I hope to face the end calmly and in my own way. For most situations, however, I prefer the more martial view that death is the ultimate enemy—and I find nothing reproachable in those who rage mightily against the dying of the light.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Stephen Jay Gould&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/44/</guid></item><item><title>Quote 45</title><link>https://www.wints.org/quotes/45/</link><description>&lt;p&gt;You cannot overestimate the unimportance of practically everything. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Greg McKeown&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/45/</guid></item><item><title>Quote 46</title><link>https://www.wints.org/quotes/46/</link><description>&lt;p&gt;Be everything to everybody and you’ll be nothing for yourself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-John Rushton&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/46/</guid></item><item><title>Quote 47</title><link>https://www.wints.org/quotes/47/</link><description>&lt;p&gt;Nearly all men can stand adversity, but if you want to test a man’s character, give him power.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Abraham Lincoln&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/47/</guid></item><item><title>Quote 48</title><link>https://www.wints.org/quotes/48/</link><description>&lt;p&gt;Most people will never be successful because most people remain children, consciously, and never evolve.
They remain purely self-indulgent and self-absorbed.
They never develop convictions that drive them to dedicate their lives to a particular service and audience.
They aren’t willing to learn and transform themselves for a commitment. Instead, they only commit to something so long as it benefits them. Once things get tough, their &amp;lsquo;commitment&amp;rsquo; disappears.
In order to be truly successful, and to make an enormous impact on the world, you must give yourself fully to something. It can’t be about you anymore. You must be driven to serve. To help other people, and to solve specific problems.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/48/</guid></item><item><title>Quote 49</title><link>https://www.wints.org/quotes/49/</link><description>&lt;p&gt;Some people want it to happen, some wish it would happen, others make it happen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Michael Jordan&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/49/</guid></item><item><title>Quote 5</title><link>https://www.wints.org/quotes/5/</link><description>&lt;p&gt;It is not the critic who counts; not the man who points out how the strong man stumbles, or where the doer of deeds could have done them better.&lt;br /&gt;
The credit belongs to the man who is actually in the arena, whose face is marred by dust and sweat and blood; who strives valiantly; who errs, who comes short again and again, because there is no effort without error and shortcoming; but who does actually strive to do the deeds; who knows great enthusiasms, the great devotions; who spends himself in a worthy cause; who at the best knows in the end the triumph of high achievement, and who at the worst, if he fails, at least fails while daring greatly, so that his place shall never be with those cold and timid souls who neither know victory nor defeat.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/5/</guid></item><item><title>Quote 50</title><link>https://www.wints.org/quotes/50/</link><description>&lt;p&gt;Whatever you really want, wants don&amp;rsquo;t get met consistently, standards do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Tony Robbins&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/50/</guid></item><item><title>Quote 51</title><link>https://www.wints.org/quotes/51/</link><description>&lt;p&gt;Tell me and I forget. Teach me and I remember. Involve me and I learn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Benjamin Franklin&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/51/</guid></item><item><title>Quote 52</title><link>https://www.wints.org/quotes/52/</link><description>&lt;p&gt;How you do anything, is how you do everything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Unknown&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/52/</guid></item><item><title>Quote 53</title><link>https://www.wints.org/quotes/53/</link><description>&lt;p&gt;We are human beings, not human doings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Doylene Chan&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/53/</guid></item><item><title>Quote 54</title><link>https://www.wints.org/quotes/54/</link><description>&lt;ol&gt;
&lt;li&gt;Be patient. No matter what.&lt;/li&gt;
&lt;li&gt;Don’t badmouth: Assign responsibility, not blame. Say nothing of another you wouldn’t say to him.&lt;/li&gt;
&lt;li&gt;Never assume the motives of others are, to them, less noble than yours are to you.&lt;/li&gt;
&lt;li&gt;Expand your sense of the possible.&lt;/li&gt;
&lt;li&gt;Don’t trouble yourself with matters you truly cannot change.&lt;/li&gt;
&lt;li&gt;Expect no more of anyone than you can deliver yourself.&lt;/li&gt;
&lt;li&gt;Tolerate ambiguity.&lt;/li&gt;
&lt;li&gt;Laugh at yourself frequently.&lt;/li&gt;
&lt;li&gt;Concern yourself with what is right rather than who is right.&lt;/li&gt;
&lt;li&gt;Never forget that, no matter how certain, you might be wrong.&lt;/li&gt;
&lt;li&gt;Give up blood sports.&lt;/li&gt;
&lt;li&gt;Remember that your life belongs to others as well. Don’t risk it frivolously.&lt;/li&gt;
&lt;li&gt;Never lie to anyone for any reason. (Lies of omission are sometimes exempt.)&lt;/li&gt;
&lt;li&gt;Learn the needs of those around you and respect them.&lt;/li&gt;
&lt;li&gt;Avoid the pursuit of happiness. Seek to define your mission and pursue that.&lt;/li&gt;
&lt;li&gt;Reduce your use of the first personal pronoun.&lt;/li&gt;
&lt;li&gt;Praise at least as often as you disparage.&lt;/li&gt;
&lt;li&gt;Admit your errors freely and soon.&lt;/li&gt;
&lt;li&gt;Become less suspicious of joy.&lt;/li&gt;
&lt;li&gt;Understand humility.&lt;/li&gt;
&lt;li&gt;Remember that love forgives everything.&lt;/li&gt;
&lt;li&gt;Foster dignity.&lt;/li&gt;
&lt;li&gt;Live memorably.&lt;/li&gt;
&lt;li&gt;Love yourself.&lt;/li&gt;
&lt;li&gt;Endure&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;-John Perry Barlow on Life and Work&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/54/</guid></item><item><title>Quote 55</title><link>https://www.wints.org/quotes/55/</link><description>&lt;p&gt;Don&amp;rsquo;t ask what the world needs. Ask what makes you come alive. For what the world needs is more people who have come alive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Rev. Dr. Howard Thurman&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/55/</guid></item><item><title>Quote 56</title><link>https://www.wints.org/quotes/56/</link><description>&lt;p&gt;If you want to build a ship, don’t drum up the people to gather wood, divide the work, and give orders.
Instead, teach them to yearn for the vast and endless sea.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Antoine de Saint-Exupéry&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/56/</guid></item><item><title>Quote 57</title><link>https://www.wints.org/quotes/57/</link><description>&lt;p&gt;The design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;- &lt;a href="http://jehanne.io"&gt;http://jehanne.io&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/57/</guid></item><item><title>Quote 58</title><link>https://www.wints.org/quotes/58/</link><description>&lt;p&gt;You will come to understand that you were taking care of them because it made YOU feel good, it made YOU happy to see them smiling and without a care in the world — and that was extremely selfish of you. While you were feeling satisfied with yourself, you were slowly eating away at their own dreams and ambitions. You were adding material things to their lives, but subtracting the most precious gifts of all: independence and growth.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/58/</guid></item><item><title>Quote 59</title><link>https://www.wints.org/quotes/59/</link><description>&lt;p&gt;Someone once told me the definition of Hell: The last day you have on earth, the person you became will meet the person you could have become.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Unknown&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/59/</guid></item><item><title>Quote 6</title><link>https://www.wints.org/quotes/6/</link><description>&lt;p&gt;I think positivity, and good, is practical advice to building an empire and I want to be the poster child of the person that built the biggest, baddest empire and did it being a good dude along the way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Gary Vaynerchuck&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/6/</guid></item><item><title>Quote 60</title><link>https://www.wints.org/quotes/60/</link><description>&lt;p&gt;One day, you will be dead. Each year that passes after your death, fewer and fewer people will remember who you were, what you did or what your face looked like. Eventually, you&amp;rsquo;ll be completely forgotten. Who cares if that side project you put out sucked or not. Might as well put it out there and see what people think. There&amp;rsquo;s a good chance too that the project won&amp;rsquo;t even be remembered even by the time you die.
The best way to get experience is to do things, so given that no one is going to remember, might as well try to do it. Your successes won&amp;rsquo;t be remembered along with your failures.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/60/</guid></item><item><title>Quote 61</title><link>https://www.wints.org/quotes/61/</link><description>&lt;p&gt;So one day Jeff Bezos issued a mandate.  He&amp;rsquo;s doing that all the time, of course, and people scramble like ants being pounded with a rubber mallet whenever it happens. But on one occasion &amp;ndash; back around 2002 I think, plus or minus a year &amp;ndash; he issued a mandate that was so out there, so huge and eye-bulgingly ponderous, that it made all of his other mandates look like unsolicited peer bonuses.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/61/</guid></item><item><title>Quote 62</title><link>https://www.wints.org/quotes/62/</link><description>&lt;p&gt;Hard times create strong men. Strong men create good times. Good times create weak men. And, weak men create hard times.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-G. Michael Hopf&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/62/</guid></item><item><title>Quote 63</title><link>https://www.wints.org/quotes/63/</link><description>&lt;p&gt;We thought of life by analogy with a journey, a pilgrimage, which had a serious purpose at the end, and the thing was to get to that end, success or whatever it is, maybe heaven after you’re dead. But we missed the point the whole way along. It was a musical thing and you were supposed to sing or to dance while the music was being played.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Alan Watts&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/63/</guid></item><item><title>Quote 64</title><link>https://www.wints.org/quotes/64/</link><description>&lt;p&gt;Retirement is when you stop sacrificing today for some imaginary tomorrow. When today is complete in and of itself. How do you get there? One is, that you have so much money saved up that your passive income off of that covers your burn rate. Second is, you just drive your burn rate down to zero. Become a monk. Third is, you’re doing something you love. You’re enjoying it so much that it’s not about the money.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/64/</guid></item><item><title>Quote 65</title><link>https://www.wints.org/quotes/65/</link><description>&lt;p&gt;There are two great addictions - heroin and a monthly salary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Nassim Taleb&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/65/</guid></item><item><title>Quote 66</title><link>https://www.wints.org/quotes/66/</link><description>&lt;p&gt;Every man has two lives. And the second starts when he realizes he has just one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Confucius&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/66/</guid></item><item><title>Quote 67</title><link>https://www.wints.org/quotes/67/</link><description>&lt;p&gt;A healthy person wants 10,000 things. A sick person wants just one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Confucius&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/67/</guid></item><item><title>Quote 68</title><link>https://www.wints.org/quotes/68/</link><description>&lt;p&gt;Destroy the idea that you have to be constantly working or grinding in order to be successful. Embrace the concept that rest, recovery, and reflection are essential parts of progress towards a successful and ultimately happy life.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Unknown&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/68/</guid></item><item><title>Quote 69</title><link>https://www.wints.org/quotes/69/</link><description>&lt;p&gt;If you can keep your head when all about you&lt;/p&gt;
&lt;p&gt;Are losing theirs and blaming it on you,&lt;/p&gt;
&lt;p&gt;If you can trust yourself when all men doubt you,&lt;/p&gt;
&lt;p&gt;But make allowance for their doubting too;&lt;/p&gt;
&lt;p&gt;If you can wait and not be tired by waiting,&lt;/p&gt;
&lt;p&gt;Or being lied about, don&amp;rsquo;t deal in lies,&lt;/p&gt;
&lt;p&gt;Or being hated, don&amp;rsquo;t give way to hating,&lt;/p&gt;
&lt;p&gt;And yet don&amp;rsquo;t look too good, nor talk too wise:&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/69/</guid></item><item><title>Quote 7</title><link>https://www.wints.org/quotes/7/</link><description>&lt;p&gt;I want my pedestal moment, I want to become that big, and what I want to come from that is that kids that aren&amp;rsquo;t even born today think that they can build a $5 billion dollar company and be a great guy or great gal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Gary Vaynerchuck&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/7/</guid></item><item><title>Quote 70</title><link>https://www.wints.org/quotes/70/</link><description>&lt;p&gt;The only way to succeed is if the pain of doing something is less than the pain of doing nothing. You must, therefore, increase the pain of doing nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Jon Morrow&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/70/</guid></item><item><title>Quote 71</title><link>https://www.wints.org/quotes/71/</link><description>&lt;p&gt;The mind is a kite and the body is the string. In order to move the kite you must move the string.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Unknown&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/71/</guid></item><item><title>Quote 72</title><link>https://www.wints.org/quotes/72/</link><description>&lt;p&gt;Make your interests gradually wider and more impersonal, until bit by bit the walls of the ego recede, and your life becomes increasingly merged in the universal life. An individual human existence should be like a river — small at first, narrowly contained within its banks, and rushing passionately past rocks and over waterfalls. Gradually the river grows wider, the banks recede, the waters flow more quietly, and in the end, without any visible break, they become merged in the sea, and painlessly lose their individual being.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/72/</guid></item><item><title>Quote 73</title><link>https://www.wints.org/quotes/73/</link><description>&lt;p&gt;It is useless work that darkens the heart. The delight of the nursing mother, of the scholar, of the successful hunter, of the good cook, of the skillful maker, of anyone doing needed work and doing it well, - this durable joy is perhaps the deepest source of human affection and of society as a whole.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Ursula K LeGuin&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/73/</guid></item><item><title>Quote 74</title><link>https://www.wints.org/quotes/74/</link><description>&lt;p&gt;I wonder, I wonder, what you would do if you had the power to dream at night any dream you wanted to dream? And you would, of course, be able to alter your time sense, and slip, say, 75 years of subjective time into 8 hours of sleep.&lt;/p&gt;
&lt;p&gt;You would, I suppose, start out by fulfilling all your wishes. You could design for yourself what would be the most ecstatic life: love affairs, banquets, dancing girls, wonderful journeys, gardens, music beyond belief.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/74/</guid></item><item><title>Quote 75</title><link>https://www.wints.org/quotes/75/</link><description>&lt;p&gt;To be a warrior is not a simple matter of wishing to be one. It is rather an endless struggle that will go on to the very last moment of our lives. Nobody is born a warrior, in exactly the same way that nobody is born an average man. We make ourselves into one or the other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Carlos Castaneda&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/75/</guid></item><item><title>Quote 76</title><link>https://www.wints.org/quotes/76/</link><description>&lt;p&gt;And in truth, I&amp;rsquo;ve never known a man worth his salt who, in the long run, deep down in his heart, didn&amp;rsquo;t appreciate the grind, the discipline. The difference between a successful person and others is not a lack of strength, not a lack of knowledge, but rather&amp;hellip; a lack of will.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Vince Lombardi&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/76/</guid></item><item><title>Quote 77</title><link>https://www.wints.org/quotes/77/</link><description>&lt;p&gt;Work is love made visible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Kahlil Gibran&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/77/</guid></item><item><title>Quote 78</title><link>https://www.wints.org/quotes/78/</link><description>&lt;p&gt;If you are depressed you are living in the past. If you are anxious you are living in the future. If you are at peace you are living in the present.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Lao Tzu&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/78/</guid></item><item><title>Quote 79</title><link>https://www.wints.org/quotes/79/</link><description>&lt;p&gt;I divide my officers into four classes as follows: The clever, the industrious, the lazy, and the stupid. Each officer always possesses two of these qualities.&lt;/p&gt;
&lt;p&gt;Those who are clever and industrious I appoint to the General Staff. Use can under certain circumstances be made of those who are stupid and lazy. The man who is clever and lazy qualifies for the highest leadership posts. He has the requisite nerves and the mental clarity for difficult decisions. But whoever is stupid and industrious must be got rid of, for he is too dangerous.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/79/</guid></item><item><title>Quote 8</title><link>https://www.wints.org/quotes/8/</link><description>&lt;p&gt;Massive action without clearly defined objectives is a form of laziness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Timothy Ferriss&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/8/</guid></item><item><title>Quote 80</title><link>https://www.wints.org/quotes/80/</link><description>&lt;p&gt;Above all, don&amp;rsquo;t lie to yourself. The man who lies to himself and listens to his own lie comes to a point that he cannot distinguish the truth within him, or around him, and so loses all respect for himself and for others. And having no respect he ceases to love… “Above all, avoid falsehood, every kind of falsehood, especially to yourself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Zosima&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/80/</guid></item><item><title>Quote 81</title><link>https://www.wints.org/quotes/81/</link><description>&lt;p&gt;When you go out into the woods, and you look at trees, you see all these different trees. And some of them are bent, and some of them are straight, and some of them are evergreens, and some of them are whatever. And you look at the tree and you allow it. You see why it is the way it is. You sort of understand that it didn’t get enough light, and so it turned that way. And you don’t get all emotional about it. You just allow it. You appreciate the tree.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/81/</guid></item><item><title>Quote 82</title><link>https://www.wints.org/quotes/82/</link><description>&lt;p&gt;Step 1: Consider the habit you want to build, e.g. “I want to meditate 10 minutes every day”&lt;/p&gt;
&lt;p&gt;Step 2: Make it the absolute smallest possible version of itself; so small that it requires zero motivation/willpower, e.g. “I want to close my eyes and take 3 deep breaths every day”&lt;/p&gt;
&lt;p&gt;Step 3: Place this habit immediately following an existing habit, e.g. “After I brush my teeth in the morning, I will close my eyes and take 3 deep breaths”&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/82/</guid></item><item><title>Quote 83</title><link>https://www.wints.org/quotes/83/</link><description>&lt;p&gt;Motivation is what gets you started. Habit is what keeps you going.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Jim Ryun&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/83/</guid></item><item><title>Quote 84</title><link>https://www.wints.org/quotes/84/</link><description>&lt;p&gt;There are only two mistakes one can make along the road to truth; not going all the way, and not starting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Buddha&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/84/</guid></item><item><title>Quote 85</title><link>https://www.wints.org/quotes/85/</link><description>&lt;p&gt;If your plan is for 1 year, plant rice. If your plan is 10 years, plant trees. If your plan is for a 100 years, educate children.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Confucius&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/85/</guid></item><item><title>Quote 86</title><link>https://www.wints.org/quotes/86/</link><description>&lt;p&gt;A ship is always safe at the shore - but that is NOT what it is built for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Albert Einstein&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/86/</guid></item><item><title>Quote 87</title><link>https://www.wints.org/quotes/87/</link><description>&lt;p&gt;Find ecstasy in life; the mere sense of living is joy enough.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Emily Dickinson&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/87/</guid></item><item><title>Quote 88</title><link>https://www.wints.org/quotes/88/</link><description>&lt;p&gt;The successful warrior is the average man, with laser-like focus.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Bruce Lee&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/88/</guid></item><item><title>Quote 89</title><link>https://www.wints.org/quotes/89/</link><description>&lt;p&gt;You will either step forward into growth or you will step back into safety.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Abraham Maslow&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/89/</guid></item><item><title>Quote 9</title><link>https://www.wints.org/quotes/9/</link><description>&lt;p&gt;Income without time has no value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Timothy Ferriss&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/9/</guid></item><item><title>Quote 90</title><link>https://www.wints.org/quotes/90/</link><description>&lt;p&gt;Discipline is doing something you hate, like you love it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Mike Tyson&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/90/</guid></item><item><title>Quote 91</title><link>https://www.wints.org/quotes/91/</link><description>&lt;p&gt;Children do not belong to you, and they do not come from you. They only come through you. It is a privilege that we must appreciate and enjoy, rather than thinking it is our right or trying to determine where they should go and what they should do. As long as they are working towards their wellbeing and they are not doing something negative against their own life, you must wait. For the entire time until the child becomes twenty-one, you must feel like you are still pregnant. Just wait. When the child was inside, you did nothing, right? Just nourished yourself well and waited. Just like that – provide the atmosphere and wait.&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/91/</guid></item><item><title>Quote 92</title><link>https://www.wints.org/quotes/92/</link><description>&lt;p&gt;You want to know the certainty of death in life. This is called belief, belonging, identification.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-Sadhguru&lt;/strong&gt;&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/92/</guid></item><item><title>Quote 93</title><link>https://www.wints.org/quotes/93/</link><description>&lt;p&gt;Your children are not your children.&lt;/p&gt;
&lt;p&gt;They are the sons and daughters of Life&amp;rsquo;s longing for itself.&lt;/p&gt;
&lt;p&gt;They come through you but not from you,&lt;/p&gt;
&lt;p&gt;And though they are with you yet they belong not to you.&lt;/p&gt;
&lt;p&gt;You may give them your love but not your thoughts,&lt;/p&gt;
&lt;p&gt;For they have their own thoughts.&lt;/p&gt;
&lt;p&gt;You may house their bodies but not their souls,&lt;/p&gt;
&lt;p&gt;For their souls dwell in the house of tomorrow,&lt;/p&gt;</description><author>A Holding Company</author><pubDate>Wed, 09 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wints.org/quotes/93/</guid></item><item><title>SMZ: Updated Drafts Actions</title><link>http://evantravers.com/articles/2020/12/08/smz-updated-drafts-actions/</link><description>&lt;p&gt;Today was the first day I used the &lt;em&gt;whole&lt;/em&gt; revamped SMZ system, and it feels &lt;strong&gt;real&lt;/strong&gt; good.&lt;/p&gt;
&lt;p&gt;I've made a few tweaks to it, but the &lt;a href="https://github.com/evantravers/plaintext-migration"&gt;migration script&lt;/a&gt; has stayed stable and I haven't needed to run it in a little while… I believe that's over.&lt;/p&gt;
&lt;p&gt;The final step was updating &lt;a href="https://github.com/evantravers/smz-drafts-actions"&gt;my JS actions&lt;/a&gt; for my beloved &lt;a href="https://getdrafts.com"&gt;Drafts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm only a couple of weeks into using it, but so far the new version has been much more stable and usable. In the highly unlikely chance that you were using my library to build your actions, here's what's changed:&lt;/p&gt;
&lt;p&gt;The &amp;quot;library&amp;quot; step has been renamed to &lt;code&gt;Zettelkasten API&lt;/code&gt;. Some of the booknotes specific steps have been moved to another &amp;quot;library&amp;quot; step called &lt;code&gt;Booknotes API&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the previous version, the library treated the active draft as the &amp;quot;data model.&amp;quot; This caused weird heisenbugs related to what functions called &lt;code&gt;draft.update()&lt;/code&gt; and which tried to not thrash the view constantly. In the V2, (&lt;code&gt;Zettelkasten API&lt;/code&gt;,) the only methods that touch the active Draft object are &lt;code&gt;Zettel.parse(draft)&lt;/code&gt; and &lt;code&gt;Zettel.update()&lt;/code&gt;. All the other transformations happen on a simple JS object (built by &lt;code&gt;Zettel.parse/1&lt;/code&gt; that takes the form of &lt;code&gt;&amp;amp;lbracemeta: &amp;amp;lbrace … &amp;amp;rbrace, content: &amp;quot;foo&amp;quot; &amp;amp;rbrace&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So far this approach has meant &lt;em&gt;much&lt;/em&gt; easier debugging and predictability. I'm a fan.&lt;/p&gt;
&lt;p&gt;The previous versions had dependencies on &amp;quot;template&amp;quot; drafts that couldn't possibly exist on another person's database… so all the &amp;quot;templates&amp;quot; are now in the actions themselves. I think there's still a dependency on having a workspace named &amp;quot;Booknotes,&amp;quot; but that's pretty solvable by an end user.&lt;/p&gt;
&lt;p&gt;The use-cases are still about the same. As I move through my day, I throw quotes, links, and snippets of ideas in Drafts. During the daily review at the end of the day I go through Drafts, expand and save the thoughts that need to be saved. The new actions don't add all the kluge metadata that blocks the view of the title until it's saved.&lt;/p&gt;
&lt;p&gt;If it's something you are interested in... message me on twitter and I'll try to fix it for you. Until then, &lt;a href="https://actions.getdrafts.com/g/16J"&gt;add it to Drafts here&lt;/a&gt;.&lt;/p&gt;</description><author>trv.rs</author><pubDate>Tue, 08 Dec 2020 22:55:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/12/08/smz-updated-drafts-actions/</guid></item><item><title>Really smart cities help their stores to go Dark</title><link>https://stop.zona-m.net/2020/12/really-smart-cities-help-their-stores-to-go-dark/</link><description>&lt;p&gt;The digital dark side or retailing is more smart than dark.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 08 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/really-smart-cities-help-their-stores-to-go-dark/</guid></item><item><title>Emulating a Computer: Graphics and Texture Streaming</title><link>https://riv.dev/emulating-a-computer-part-3/</link><description>Displaying graphics using SDL for our emulator.</description><author>River Gillis [riv.dev]</author><pubDate>Tue, 08 Dec 2020 05:51:00 GMT</pubDate><guid isPermaLink="true">https://riv.dev/emulating-a-computer-part-3/</guid></item><item><title>Solving my fun, frustrating docker-machine error</title><link>https://ntietz.com/blog/solving-frustrating-docker-machine-error/?utm_source=atom&amp;utm_medium=feed</link><description>&lt;p&gt;Last Saturday, I ran into a problem doing a routine backup of a web app I maintain. In fact, this was the &lt;em&gt;second&lt;/em&gt; time I ran into the &lt;em&gt;exact&lt;/em&gt; same issue, so it's time to write it down. (Hopefully, the third time I run into this, I have the presence of mind to look up my own solution!)&lt;/p&gt;
&lt;p&gt;My web app is deployed using docker-machine and docker-compose. This is not a great production setup, but it works for me and there are just a handful of users. Every week, I manually run a backup script that copies down the database and all the images from this web app. (I could set up a cron job, but I consciously chose to keep it manual so I would, every week, be able to see that the backups are working: this has paid off, since I saw when it did NOT work!)&lt;/p&gt;
&lt;p&gt;When I ran the backups, I ran into a mysterious error message:&lt;/p&gt;
&lt;pre style="background-color: #282828; color: #fdf4c1aa;"&gt;&lt;code&gt;&lt;span&gt;$ backup.sh
&lt;/span&gt;&lt;span&gt;Error checking TLS connection: Error checking and/or regenerating the certs: There was an error validating certificates for host &amp;quot;xx.xx.xx.xx:2376&amp;quot;: dial tcp xx.xx.xx.xx:2376: i/o timeout
&lt;/span&gt;&lt;span&gt;You can attempt to regenerate them using 'docker-machine regenerate-certs [name]'.
&lt;/span&gt;&lt;span&gt;Be advised that this will trigger a Docker daemon restart which might stop running containers.
&lt;/span&gt;&lt;span&gt;
&lt;/span&gt;&lt;span&gt;Error response from daemon: Container 06916a79c735b152c287c8aaa57ff65958898f819c604ceee83fadf3f502922f is not running
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First thought: Okay, well, that's weird that the certs are expired but let's just follow what it says. Let's regenerate those. So, I did, and then... the entire app was down, because it shut down the containers but could not start them! Now a routine backup has turned into an outage.&lt;/p&gt;
&lt;p&gt;Aaand I can't see the machine:&lt;/p&gt;
&lt;pre style="background-color: #282828; color: #fdf4c1aa;"&gt;&lt;code&gt;&lt;span&gt;$ docker-machine ls
&lt;/span&gt;&lt;span&gt;NAME        ACTIVE   DRIVER    STATE     URL   SWARM   DOCKER   ERRORS
&lt;/span&gt;&lt;span&gt;picklejar            generic   Timeout
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The strange thing? &lt;code&gt;docker-machine ssh &amp;lt;host&amp;gt;&lt;/code&gt; worked.&lt;/p&gt;
&lt;p&gt;So... I cannot see the machine, I cannot validate the certs, but ssh works.&lt;/p&gt;
&lt;p&gt;If you're screaming at the monitor right now because the answer is obvious, &lt;em&gt;I know&lt;/em&gt;. I missed it in the moment, but it was right there in front of me (sort of) in that first error message: &lt;code&gt;dial tcp xx.xx.xx.xx:2376: i/o timout&lt;/code&gt;: This means that we can't establish a TCP connection on that port, which could be... caused by the firewall. Let's not talk about how long it took me to realize this, and how many other things I tried before I had that head smack moment: doh!&lt;/p&gt;
&lt;p&gt;The problem was: I have the instance firewalled in a way that allows my home network to establish the TCP connections needed for docker-machine, but no external traffic. BUT I have ssh allowed from &lt;em&gt;any&lt;/em&gt; port, so that I can get into the host while I'm on the go (or that was the idea, when travel was a thing). So when my ISP issued me a new IP address, suddenly I could do some things on the machine (ssh) but could not do others, leading to this confusing situation of docker-machine kinda sorta half working.&lt;/p&gt;
&lt;p&gt;So if you get an error message from docker-machine about an error validating certificates, don't just assume (as I did) that its suggested fix is a good idea: verify that you don't have a network/firewall issue first.&lt;/p&gt;</description><author>ntietz.com blog - technically a blog</author><pubDate>Tue, 08 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://ntietz.com/blog/solving-frustrating-docker-machine-error/?utm_source=atom&amp;utm_medium=feed</guid></item><item><title>IPython embed and autoreload</title><link>https://gaganpreet.in/posts/ipython-embed-autoreload/</link><description>&lt;p&gt;IPython makes for very productive and effortless sessions working interactively with Python. From the numerous extensions for IPython, &lt;a href="https://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html#autoreload" rel="noreferrer" target="_blank"&gt;autoreload&lt;/a&gt; is one I use often. It&amp;rsquo;s very useful for working with existing code and being able to edit code from my code editor and have changes reflected automatically within the IPython terminal.&lt;/p&gt;</description><author>Gaganpreet Arora</author><pubDate>Mon, 07 Dec 2020 22:01:38 GMT</pubDate><guid isPermaLink="true">https://gaganpreet.in/posts/ipython-embed-autoreload/</guid></item><item><title>Pumpkin pie recipe [Video]</title><link>https://www.youtube.com/watch?v=2sZA-ohO06M</link><description>One of my favourite desserts! Recipe from my great-grandmother.</description><author>David Schlachter</author><pubDate>Mon, 07 Dec 2020 21:23:00 GMT</pubDate><guid isPermaLink="true">https://www.youtube.com/watch?v=2sZA-ohO06M</guid></item><item><title>You are losing easy publishing, consuming and remixing</title><link>https://stop.zona-m.net/2020/12/you-are-losing-easy-publishing-consuming-and-remixing/</link><description>&lt;p&gt;Where? Right here on the web, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 07 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/you-are-losing-easy-publishing-consuming-and-remixing/</guid></item><item><title>AoC day7</title><link>https://evilcookie.de/aoc-day7.html</link><description/><author>blog</author><pubDate>Mon, 07 Dec 2020 19:35:56 GMT</pubDate><guid isPermaLink="true">https://evilcookie.de/aoc-day7.html</guid></item><item><title>Emulating a Computer: Images and Rendering</title><link>https://riv.dev/emulating-a-computer-part-2/</link><description>Adding images to our CHIP-8 emulator.</description><author>River Gillis [riv.dev]</author><pubDate>Mon, 07 Dec 2020 04:21:00 GMT</pubDate><guid isPermaLink="true">https://riv.dev/emulating-a-computer-part-2/</guid></item><item><title>Go Tour Summary</title><link>https://lukesingham.com/go-tour-summary/</link><description>&lt;p&gt;These are my summary notes of &lt;a href="https://tour.golang.org/"&gt;A Tour of Go&lt;/a&gt; - which is meant for people who are familiar with programming to have a quick tour of the Go language. I'm most familiar with dynamic languages (&lt;code&gt;R&lt;/code&gt;, &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;JavaScript&lt;/code&gt;) so there are some go-lang features that naturally feel new by the nature of Go being a statically typed language. A subsequent post will expand upon some of the more advanced features like pointers, concurrency and polymorphism.&lt;/p&gt;
&lt;h2 id="named-return-values"&gt;Named Return Values &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#named-return-values"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A return statement without arguments returns the named return values. This is known as a &amp;quot;naked&amp;quot; return.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;split&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;mynumber &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;x&lt;span class="token punctuation"&gt;,&lt;/span&gt; y &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	x &lt;span class="token operator"&gt;=&lt;/span&gt; mynumber &lt;span class="token operator"&gt;*&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;br /&gt;	y &lt;span class="token operator"&gt;=&lt;/span&gt; mynumber &lt;span class="token operator"&gt;-&lt;/span&gt; x&lt;br /&gt;	&lt;span class="token keyword"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token function"&gt;split&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;17&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// This will print x and y:&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 68 -51&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="variables"&gt;Variables &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#variables"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;var&lt;/code&gt; statement declares a list of variables; as in function argument lists, the type is last.&lt;/p&gt;
&lt;h3 id="variables-with-initializers"&gt;Variables with initializers &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#variables-with-initializers"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;var&lt;/code&gt; declaration can include initializers, one per variable.&lt;/p&gt;
&lt;p&gt;If an initializer is present, the type can be omitted; the variable will take the type of the initializer.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; a &lt;span class="token builtin"&gt;int&lt;/span&gt; &lt;span class="token comment"&gt;// will have a value of 0 as a placeholder&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; f &lt;span class="token builtin"&gt;float64&lt;/span&gt; &lt;span class="token comment"&gt;// 0&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; b &lt;span class="token builtin"&gt;bool&lt;/span&gt; &lt;span class="token comment"&gt;// false&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; s &lt;span class="token builtin"&gt;string&lt;/span&gt; &lt;span class="token comment"&gt;// ""&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; i&lt;span class="token punctuation"&gt;,&lt;/span&gt; j &lt;span class="token builtin"&gt;int&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt; &lt;span class="token comment"&gt;// explicit&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; k&lt;span class="token punctuation"&gt;,&lt;/span&gt; l &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt; &lt;span class="token comment"&gt;// implicit&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="%3A%3D"&gt;&lt;code&gt;:=&lt;/code&gt; &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#%3A%3D"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Inside a function, the &lt;code&gt;:=&lt;/code&gt; short assignment statement can be used in place of a var declaration with implicit type.&lt;/p&gt;
&lt;p&gt;Outside a function, every statement begins with a keyword (var, func, and so on) and so the &lt;code&gt;:=&lt;/code&gt; construct is not available.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="token comment"&gt;// := only within fn&lt;/span&gt;&lt;br /&gt;  k &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;3&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="types-in-go"&gt;Types in go &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#types-in-go"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token builtin"&gt;bool&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;  &lt;span class="token builtin"&gt;int8&lt;/span&gt;  &lt;span class="token builtin"&gt;int16&lt;/span&gt;  &lt;span class="token builtin"&gt;int32&lt;/span&gt;  &lt;span class="token builtin"&gt;int64&lt;/span&gt;&lt;br /&gt;&lt;span class="token builtin"&gt;uint&lt;/span&gt; &lt;span class="token builtin"&gt;uint8&lt;/span&gt; &lt;span class="token builtin"&gt;uint16&lt;/span&gt; &lt;span class="token builtin"&gt;uint32&lt;/span&gt; &lt;span class="token builtin"&gt;uint64&lt;/span&gt; &lt;span class="token builtin"&gt;uintptr&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token builtin"&gt;byte&lt;/span&gt; &lt;span class="token comment"&gt;// alias for uint8&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token builtin"&gt;rune&lt;/span&gt; &lt;span class="token comment"&gt;// alias for int32&lt;/span&gt;&lt;br /&gt;     &lt;span class="token comment"&gt;// represents a Unicode code point&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token builtin"&gt;float32&lt;/span&gt; &lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token builtin"&gt;complex64&lt;/span&gt; &lt;span class="token builtin"&gt;complex128&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="type-conversions"&gt;Type conversions &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#type-conversions"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; i &lt;span class="token builtin"&gt;int&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;42&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; f &lt;span class="token builtin"&gt;float64&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;float64&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;i&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;//or&lt;/span&gt;&lt;br /&gt;i &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;42&lt;/span&gt;&lt;br /&gt;f &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token function"&gt;float64&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;i&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="constants"&gt;Constants &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#constants"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Constants are declared like variables, but with the const keyword.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;const&lt;/span&gt; Pi &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;3.14&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="for"&gt;For &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#for"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go has only one looping construct, the &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	sum &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;for&lt;/span&gt; i &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;10&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i&lt;span class="token operator"&gt;++&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		sum &lt;span class="token operator"&gt;+=&lt;/span&gt; i&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;sum&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The init and post statements are optional.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;sum &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;for&lt;/span&gt; &lt;span class="token punctuation"&gt;;&lt;/span&gt; sum &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;1000&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;  sum &lt;span class="token operator"&gt;+=&lt;/span&gt; sum&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="if"&gt;If &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#if"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go's &lt;code&gt;if&lt;/code&gt; statements are like its &lt;code&gt;for&lt;/code&gt; loops; the expression need not be surrounded by parentheses ( ) but the braces { } are required.&lt;/p&gt;
&lt;h3 id="if-with-a-short-statement"&gt;If with a short statement &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#if-with-a-short-statement"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Like the &lt;code&gt;for&lt;/code&gt; loop, the &lt;code&gt;if&lt;/code&gt; statement can start with a short statement to execute before the condition.&lt;/p&gt;
&lt;p&gt;Variables declared by the statement are only in scope until the end of the if.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;pow&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;x&lt;span class="token punctuation"&gt;,&lt;/span&gt; n&lt;span class="token punctuation"&gt;,&lt;/span&gt; lim &lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token builtin"&gt;float64&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="token comment"&gt;// v doesn't exist outside of the if statement scope&lt;/span&gt;&lt;br /&gt;  &lt;span class="token keyword"&gt;if&lt;/span&gt; v &lt;span class="token operator"&gt;:=&lt;/span&gt; math&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Pow&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;x&lt;span class="token punctuation"&gt;,&lt;/span&gt; n&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; v &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; lim &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class="token keyword"&gt;return&lt;/span&gt; v&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;return&lt;/span&gt; lim&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="switch"&gt;Switch &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#switch"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A switch statement is a shorter way to write a sequence of &lt;code&gt;if&lt;/code&gt; &lt;code&gt;else&lt;/code&gt; statements. It runs the first case whose value is equal to the condition expression.&lt;/p&gt;
&lt;p&gt;Go's switch is like the one in &lt;code&gt;C&lt;/code&gt;, &lt;code&gt;C++&lt;/code&gt;, &lt;code&gt;Java&lt;/code&gt;, &lt;code&gt;JavaScript&lt;/code&gt; and &lt;code&gt;PHP&lt;/code&gt;, except that Go only runs the selected case, not all the cases that follow. In effect, the break statement that is needed at the end of each case in those languages is provided automatically in Go. Another important difference is that Go's switch cases need not be constants, and the values involved need not be integers.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;switch&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"matches"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt; &lt;span class="token operator"&gt;+&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"doesnt match"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// matches&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="switch-with-no-condition"&gt;Switch with no condition &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#switch-with-no-condition"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Switch without a condition is the same as switch true. This construct can be a clean way to write long if-then-else chains.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	t &lt;span class="token operator"&gt;:=&lt;/span&gt; time&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Now&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;switch&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;case&lt;/span&gt; t&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Hour&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;12&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"Good morning!"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;case&lt;/span&gt; t&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Hour&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;17&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"Good afternoon."&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;default&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"Good evening."&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="defer"&gt;Defer &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#defer"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Defer evaluates but doesn't execute&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"hello1"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;defer&lt;/span&gt; fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"world"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;  fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"hello2"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// hello1&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// hello2&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// world&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="stacking-defers"&gt;Stacking defers &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#stacking-defers"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Deferred function calls are pushed onto a stack. When a function returns, its deferred calls are executed in last-in-first-out order.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"counting"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;for&lt;/span&gt; i &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i&lt;span class="token operator"&gt;++&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class="token keyword"&gt;defer&lt;/span&gt; fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;i&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"done"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// counting&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// done&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 3&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 2&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 1&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="pointers"&gt;Pointers &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#pointers"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pointers are useful if you have read something into memory and you don't want to duplicate it. So you can just point to the memory address. Useful for optimising your code.&lt;/p&gt;
&lt;p&gt;So if you want to change a variable stored in memory, you can 'mutate' it by using pointers.&lt;/p&gt;
&lt;p&gt;The type &lt;code&gt;*T&lt;/code&gt; is a pointer to a &lt;code&gt;T&lt;/code&gt; value. Its zero value is nil.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;var p *int&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;amp;&lt;/code&gt; operator generates a pointer to its operand.&lt;br /&gt;
n.b. In 3+6, 3 and 6 are operands. And the + is the operator.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;i &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;42&lt;/span&gt;&lt;br /&gt;p &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token operator"&gt;&amp;amp;&lt;/span&gt;i &lt;span class="token comment"&gt;// a pointer p=0xc00002c008&lt;/span&gt;&lt;br /&gt;z &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token operator"&gt;*&lt;/span&gt;p &lt;span class="token comment"&gt;// dereferences the pointer. z=42&lt;/span&gt;&lt;br /&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"i"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;i&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;span class="token string"&gt;"p"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;p&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token string"&gt;"z"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; z&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// i 42 p 0xc00002c008 z 42&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;*&lt;/code&gt; operator denotes the pointer's underlying value.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token operator"&gt;*&lt;/span&gt;p&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;// read i through the pointer p&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 42&lt;/span&gt;&lt;br /&gt;&lt;span class="token operator"&gt;*&lt;/span&gt;p &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;21&lt;/span&gt;         &lt;span class="token comment"&gt;// set i through the pointer p&lt;/span&gt;&lt;br /&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;i&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 21&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is known as &amp;quot;dereferencing&amp;quot; or &amp;quot;indirecting&amp;quot;.&lt;/p&gt;
&lt;h2 id="structs"&gt;Structs &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#structs"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A struct is a collection of fields.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt; Vertex &lt;span class="token keyword"&gt;struct&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	X &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;br /&gt;	Y &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// {1 2}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="pointers-to-structs"&gt;Pointers to structs &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#pointers-to-structs"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Struct fields can be accessed through a struct pointer.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt; Vertex &lt;span class="token keyword"&gt;struct&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	X &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;br /&gt;	Y &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	v &lt;span class="token operator"&gt;:=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	p &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token operator"&gt;&amp;amp;&lt;/span&gt;v&lt;br /&gt;	p&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;10&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// {10 2}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="struct-literals"&gt;Struct Literals &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#struct-literals"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A struct literal denotes a newly allocated struct value by listing the values of its fields.&lt;/p&gt;
&lt;p&gt;You can list just a subset of fields by using the Name: syntax. The order of named fields is irrelevant.&lt;/p&gt;
&lt;p&gt;The special prefix &lt;code&gt;&amp;amp;&lt;/code&gt; returns a pointer to the struct value.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt; Vertex &lt;span class="token keyword"&gt;struct&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	X&lt;span class="token punctuation"&gt;,&lt;/span&gt; Y &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;br /&gt;	v1 &lt;span class="token operator"&gt;=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;  &lt;span class="token comment"&gt;// has type Vertex&lt;/span&gt;&lt;br /&gt;	v2 &lt;span class="token operator"&gt;=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;X&lt;span class="token punctuation"&gt;:&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;  &lt;span class="token comment"&gt;// Y:0 is implicit&lt;/span&gt;&lt;br /&gt;	v3 &lt;span class="token operator"&gt;=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;      &lt;span class="token comment"&gt;// X:0 and Y:0&lt;/span&gt;&lt;br /&gt;	p  &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token operator"&gt;&amp;amp;&lt;/span&gt;Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt; &lt;span class="token comment"&gt;// has type *Vertex&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v1&lt;span class="token punctuation"&gt;,&lt;/span&gt; p&lt;span class="token punctuation"&gt;,&lt;/span&gt; v2&lt;span class="token punctuation"&gt;,&lt;/span&gt; v3&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// {1 2} &amp;amp;{1 2} {1 0} {0 0}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="arrays"&gt;Arrays &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#arrays"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The type &lt;code&gt;[n]T&lt;/code&gt; is an array of &lt;code&gt;n&lt;/code&gt; values of type &lt;code&gt;T&lt;/code&gt;. The expression&lt;br /&gt;
&lt;code&gt;var a [10]int&lt;/code&gt;&lt;br /&gt;
declares a variable &lt;code&gt;a&lt;/code&gt; as an array of ten integers. &lt;strong&gt;An array's length is part of its type, so arrays cannot be resized.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;var&lt;/span&gt; a &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;br /&gt;	a&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token string"&gt;"Hello"&lt;/span&gt;&lt;br /&gt;	a&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token string"&gt;"World"&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;a&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; a&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;a&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	primes &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;6&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;5&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;7&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;11&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;13&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;primes&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// Hello World&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// [Hello World]&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// [2 3 5 7 11 13]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="slices"&gt;Slices &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#slices"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An array has a fixed size. A slice, on the other hand, is a dynamically-sized, flexible view into the elements of an array&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	primes &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;6&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;5&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;7&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;11&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;13&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;var&lt;/span&gt; sliced &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; primes&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;sliced&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A slice does not store any data, it just describes a section of an underlying array. Changing the elements of a slice modifies the corresponding elements of its underlying array. Other slices that share the same underlying array will see those changes.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	names &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class="token string"&gt;"John"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;		&lt;span class="token string"&gt;"Paul"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;		&lt;span class="token string"&gt;"George"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;		&lt;span class="token string"&gt;"Ringo"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	a &lt;span class="token operator"&gt;:=&lt;/span&gt; names&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;br /&gt;	b &lt;span class="token operator"&gt;:=&lt;/span&gt; names&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;a&lt;span class="token punctuation"&gt;,&lt;/span&gt; b&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	b&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token string"&gt;"XXX"&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;a&lt;span class="token punctuation"&gt;,&lt;/span&gt; b&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;names&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// [John Paul] [Paul George]&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// [John XXX] [XXX George]&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// [John XXX George Ringo]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="slice-literals"&gt;Slice literals &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#slice-literals"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A slice literal is like an array literal without the length.&lt;br /&gt;
This is an array literal:&lt;br /&gt;
&lt;code&gt;[3]bool{true, true, false}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And this creates the same array as above, then builds a slice that references it:&lt;br /&gt;
&lt;code&gt;[]bool{true, true, false}&lt;/code&gt;&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;	q &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;5&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;7&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;11&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;13&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;  fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;q&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="token comment"&gt;// [2 3 5 7 11 13]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="slice-length-and-capacity"&gt;Slice length and capacity &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#slice-length-and-capacity"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The length of a slice is the number of elements it contains.&lt;br /&gt;
The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice.&lt;br /&gt;
The length and capacity of a slice &lt;code&gt;s&lt;/code&gt; can be obtained using the expressions &lt;code&gt;len(s)&lt;/code&gt; and &lt;code&gt;cap(s)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="nil-slices"&gt;Nil slices &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#nil-slices"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The zero value of a slice is &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;var&lt;/span&gt; s &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token function"&gt;len&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token function"&gt;cap&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;if&lt;/span&gt; s &lt;span class="token operator"&gt;==&lt;/span&gt; &lt;span class="token boolean"&gt;nil&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"nil!"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// [] 0 0&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// nil!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="creating-a-slice-with-make"&gt;Creating a slice with &lt;code&gt;make&lt;/code&gt; &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#creating-a-slice-with-make"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Slices can be created with the built-in &lt;code&gt;make&lt;/code&gt; function; this is how you create dynamically-sized arrays. The make function allocates a zeroed array and returns a slice that refers to that array:&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;a &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token function"&gt;make&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;5&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;  &lt;span class="token comment"&gt;// len(a)=5&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// To specify a capacity, pass a third argument to make:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;b &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token function"&gt;make&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;5&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;// len(b)=0, cap(b)=5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="appending-to-a-slice"&gt;Appending to a slice &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#appending-to-a-slice"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;var&lt;/span&gt; s &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;printSlice&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	&lt;span class="token comment"&gt;// append works on nil slices.&lt;/span&gt;&lt;br /&gt;	s &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;append&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;printSlice&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	&lt;span class="token comment"&gt;// The slice grows as needed.&lt;/span&gt;&lt;br /&gt;	s &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;append&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;printSlice&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	&lt;span class="token comment"&gt;// We can add more than one element at a time.&lt;/span&gt;&lt;br /&gt;	s &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;append&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;printSlice&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;printSlice&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Printf&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"len=%d cap=%d %v\n"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token function"&gt;len&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token function"&gt;cap&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// len=0 cap=0 []&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// len=1 cap=1 [0]&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// len=2 cap=2 [0 1]&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// len=5 cap=6 [0 1 2 3 4]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="range"&gt;Range &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#range"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;range&lt;/code&gt; form of the &lt;code&gt;for&lt;/code&gt; loop iterates over a slice or map.&lt;br /&gt;
When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;n.b.&lt;/strong&gt; &lt;a href="https://golang.org/pkg/fmt/#hdr-Printing"&gt;verbs in string templates.&lt;/a&gt;&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; pow &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;8&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;16&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;for&lt;/span&gt; i&lt;span class="token punctuation"&gt;,&lt;/span&gt; v &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token keyword"&gt;range&lt;/span&gt; pow &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Printf&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"2**%d = %d\n"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; i&lt;span class="token punctuation"&gt;,&lt;/span&gt; v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 2**0 = 1&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 2**1 = 2&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 2**2 = 4&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 2**3 = 8&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// 2**4 = 16&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can skip the index or value by assigning to _.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;for&lt;/span&gt; i&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token boolean"&gt;_&lt;/span&gt; &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token keyword"&gt;range&lt;/span&gt; pow&lt;br /&gt;&lt;span class="token keyword"&gt;for&lt;/span&gt; &lt;span class="token boolean"&gt;_&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; value &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token keyword"&gt;range&lt;/span&gt; pow&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="map-literals"&gt;Map literals &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#map-literals"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Map literals are like struct literals, but the keys are required.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt; Vertex &lt;span class="token keyword"&gt;struct&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	Lat&lt;span class="token punctuation"&gt;,&lt;/span&gt; Long &lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; m &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token keyword"&gt;map&lt;/span&gt;&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token string"&gt;"Bell Labs"&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class="token number"&gt;40.68433&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;74.39967&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;	&lt;span class="token string"&gt;"Google"&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		&lt;span class="token number"&gt;37.42202&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;122.08408&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// m can also be expressed&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; m &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token keyword"&gt;map&lt;/span&gt;&lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token string"&gt;"Bell Labs"&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;40.68433&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;74.39967&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;	&lt;span class="token string"&gt;"Google"&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;    &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;37.42202&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;122.08408&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;m&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="mutating-maps"&gt;Mutating Maps &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#mutating-maps"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token comment"&gt;// Insert or update an element in map m:&lt;/span&gt;&lt;br /&gt;m&lt;span class="token punctuation"&gt;[&lt;/span&gt;key&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; elem&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// Retrieve an element:&lt;/span&gt;&lt;br /&gt;elem &lt;span class="token operator"&gt;=&lt;/span&gt; m&lt;span class="token punctuation"&gt;[&lt;/span&gt;key&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// Delete an element:&lt;/span&gt;&lt;br /&gt;&lt;span class="token function"&gt;delete&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;m&lt;span class="token punctuation"&gt;,&lt;/span&gt; key&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// Test that a key is present with a two-value assignment:&lt;/span&gt;&lt;br /&gt;elem&lt;span class="token punctuation"&gt;,&lt;/span&gt; ok &lt;span class="token operator"&gt;=&lt;/span&gt; m&lt;span class="token punctuation"&gt;[&lt;/span&gt;key&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="function-values"&gt;Function values &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#function-values"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Functions are values too. They can be passed around just like other values. Function values may be used as function arguments and return values.&lt;/p&gt;
&lt;h2 id="function-closures"&gt;Function closures &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#function-closures"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go functions may be closures. A closure is a function value that references variables from outside its body. The function may access and assign to the referenced variables; in this sense the function is &amp;quot;bound&amp;quot; to the variables.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;adder&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token keyword"&gt;func&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token builtin"&gt;int&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	sum &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;return&lt;/span&gt; &lt;span class="token keyword"&gt;func&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;x &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token builtin"&gt;int&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		sum &lt;span class="token operator"&gt;+=&lt;/span&gt; x&lt;br /&gt;		&lt;span class="token keyword"&gt;return&lt;/span&gt; sum&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	pos&lt;span class="token punctuation"&gt;,&lt;/span&gt; neg &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token function"&gt;adder&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token function"&gt;adder&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;for&lt;/span&gt; i &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;10&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i&lt;span class="token operator"&gt;++&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;br /&gt;			&lt;span class="token function"&gt;pos&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;i&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;			&lt;span class="token function"&gt;neg&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token operator"&gt;*&lt;/span&gt;i&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt;&lt;br /&gt;		&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="methods"&gt;Methods &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#methods"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go does not have classes. However, you can define methods on types.&lt;br /&gt;
A method is a function with a special receiver argument.&lt;br /&gt;
The receiver appears in its own argument list between the func keyword and the method name.&lt;br /&gt;
In this example, the &lt;code&gt;Abs&lt;/code&gt; method has a receiver of type &lt;code&gt;Vertex&lt;/code&gt; named &lt;code&gt;v&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt; Vertex &lt;span class="token keyword"&gt;struct&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	X&lt;span class="token punctuation"&gt;,&lt;/span&gt; Y &lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// as a method&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;v Vertex&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token function"&gt;Abs&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token builtin"&gt;float64&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;return&lt;/span&gt; math&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Sqrt&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X&lt;span class="token operator"&gt;*&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;+&lt;/span&gt; v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y&lt;span class="token operator"&gt;*&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	v &lt;span class="token operator"&gt;:=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Abs&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// as a normal function&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;Abs&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v Vertex&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token builtin"&gt;float64&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;return&lt;/span&gt; math&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Sqrt&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X&lt;span class="token operator"&gt;*&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;+&lt;/span&gt; v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y&lt;span class="token operator"&gt;*&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	v &lt;span class="token operator"&gt;:=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token function"&gt;Abs&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="pointer-receivers"&gt;Pointer receivers &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#pointer-receivers"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Methods with pointer receivers can modify the value to which the receiver points (as &lt;code&gt;Scale&lt;/code&gt; does here 👇). Since methods often need to modify their receiver, pointer receivers are more common than value receivers.&lt;/p&gt;
&lt;p&gt;With a value receiver, the Scale method operates on a copy of the original Vertex value. (This is the same behavior as for any other function argument.) The Scale method must have a pointer receiver to change the Vertex value declared in the main function.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt; Vertex &lt;span class="token keyword"&gt;struct&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	X&lt;span class="token punctuation"&gt;,&lt;/span&gt; Y &lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;v Vertex&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token function"&gt;Abs&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token builtin"&gt;float64&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;return&lt;/span&gt; math&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Sqrt&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X&lt;span class="token operator"&gt;*&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;+&lt;/span&gt; v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y&lt;span class="token operator"&gt;*&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// method on a pointer&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;v &lt;span class="token operator"&gt;*&lt;/span&gt;Vertex&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token function"&gt;Scale&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;f &lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;=&lt;/span&gt; v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;*&lt;/span&gt; f&lt;br /&gt;	v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y &lt;span class="token operator"&gt;=&lt;/span&gt; v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y &lt;span class="token operator"&gt;*&lt;/span&gt; f&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	v &lt;span class="token operator"&gt;:=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	v&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Scale&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;10&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// {30 40}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// method on value receiver&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;v Vertex&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token function"&gt;Scale&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;f &lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;=&lt;/span&gt; v&lt;span class="token punctuation"&gt;.&lt;/span&gt;X &lt;span class="token operator"&gt;*&lt;/span&gt; f&lt;br /&gt;	v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y &lt;span class="token operator"&gt;=&lt;/span&gt; v&lt;span class="token punctuation"&gt;.&lt;/span&gt;Y &lt;span class="token operator"&gt;*&lt;/span&gt; f&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	v &lt;span class="token operator"&gt;:=&lt;/span&gt; Vertex&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;4&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;	v&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Scale&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;10&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// {3 4}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// the result {3 4} is because the the original values are not changed. A copy is made on execution. As opposed to the pointer receiver, which modifies the original values.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="methods-and-pointer-indirection-(2)"&gt;Methods and pointer indirection (2) &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#methods-and-pointer-indirection-(2)"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Functions that take a value argument must take a value of that specific type:&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; v Vertex&lt;br /&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token function"&gt;AbsFunc&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;  &lt;span class="token comment"&gt;// OK&lt;/span&gt;&lt;br /&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token function"&gt;AbsFunc&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token operator"&gt;&amp;amp;&lt;/span&gt;v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;// Compile error!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Methods with value receivers take either a value or a pointer as the receiver when they are called:&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; v Vertex&lt;br /&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Abs&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;// OK&lt;/span&gt;&lt;br /&gt;p &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token operator"&gt;&amp;amp;&lt;/span&gt;v&lt;br /&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;p&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Abs&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;// OK&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="interfaces"&gt;Interfaces &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#interfaces"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An interface type is defined as a set of method signatures.&lt;br /&gt;
A value of interface type can hold any value that implements those methods.&lt;/p&gt;
&lt;p&gt;A type implements an interface by implementing its methods. There is no explicit declaration of intent, no &amp;quot;implements&amp;quot; keyword&lt;/p&gt;
&lt;h3 id="interface-values"&gt;Interface values &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#interface-values"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Under the hood, interface values can be thought of as a tuple of a value and a concrete type:&lt;br /&gt;
&lt;code&gt;(value, type)&lt;/code&gt;&lt;br /&gt;
An interface value holds a value of a specific underlying concrete type.&lt;/p&gt;
&lt;h3 id="interface-values-with-nil-underlying-values"&gt;Interface values with &lt;code&gt;nil&lt;/code&gt; underlying values &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#interface-values-with-nil-underlying-values"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If the concrete value inside the interface itself is nil, the method will be called with a &lt;code&gt;nil&lt;/code&gt; receiver.&lt;br /&gt;
In some languages this would trigger a null pointer exception, but in Go it is common to write methods that gracefully handle being called with a &lt;code&gt;nil&lt;/code&gt; receiver.&lt;/p&gt;
&lt;h3 id="the-empty-interface"&gt;The empty interface &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#the-empty-interface"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The interface type that specifies zero methods is known as the empty interface:&lt;br /&gt;
&lt;code&gt;interface{}&lt;/code&gt;&lt;br /&gt;
An empty interface may hold values of any type. Every type implements at least zero methods. Empty interfaces are used by code that handles values of unknown type. For example, &lt;code&gt;fmt.Print&lt;/code&gt; takes any number of arguments of type interface{}.&lt;/p&gt;
&lt;h3 id="type-assertions"&gt;Type assertions &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#type-assertions"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A type assertion provides access to an interface value's underlying concrete value.&lt;br /&gt;
&lt;code&gt;t := i.(T)&lt;/code&gt;&lt;br /&gt;
This statement asserts that the interface value &lt;code&gt;i&lt;/code&gt; holds the concrete type &lt;code&gt;T&lt;/code&gt; and assigns the underlying &lt;code&gt;T&lt;/code&gt; value to the variable &lt;code&gt;t&lt;/code&gt;.&lt;br /&gt;
If &lt;code&gt;i&lt;/code&gt; does not hold a &lt;code&gt;T&lt;/code&gt;, the statement will trigger a panic.&lt;br /&gt;
To test whether an interface value holds a specific type, a type assertion can return two values: the underlying value and a boolean value that reports whether the assertion succeeded.&lt;br /&gt;
&lt;code&gt;t, ok := i.(T)&lt;/code&gt;&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;var&lt;/span&gt; i &lt;span class="token keyword"&gt;interface&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token string"&gt;"hello"&lt;/span&gt; &lt;span class="token comment"&gt;// implicit string type&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	s &lt;span class="token operator"&gt;:=&lt;/span&gt; i&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;//"hello"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	s&lt;span class="token punctuation"&gt;,&lt;/span&gt; ok &lt;span class="token operator"&gt;:=&lt;/span&gt; i&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;,&lt;/span&gt; ok&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;//"hello", true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	f&lt;span class="token punctuation"&gt;,&lt;/span&gt; ok &lt;span class="token operator"&gt;:=&lt;/span&gt; i&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;f&lt;span class="token punctuation"&gt;,&lt;/span&gt; ok&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;//0, false&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;	f &lt;span class="token operator"&gt;=&lt;/span&gt; i&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token builtin"&gt;float64&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;// panic&lt;/span&gt;&lt;br /&gt;	fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;f&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;//panic: interface conversion: interface {} is string, not float64&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="type-switches"&gt;Type switches &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#type-switches"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A type switch is a construct that permits several type assertions in series.&lt;br /&gt;
A type switch is like a regular switch statement, but the cases in a type switch specify types (not values), and those values are compared against the type of the value held by the given interface value.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;do&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;i &lt;span class="token keyword"&gt;interface&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;switch&lt;/span&gt; v &lt;span class="token operator"&gt;:=&lt;/span&gt; i&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token builtin"&gt;int&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Printf&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"Twice %v is %v\n"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; v&lt;span class="token punctuation"&gt;,&lt;/span&gt; v&lt;span class="token operator"&gt;*&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;case&lt;/span&gt; &lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Printf&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"%q is %v bytes long\n"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; v&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token function"&gt;len&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;default&lt;/span&gt;&lt;span class="token punctuation"&gt;:&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Printf&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"I don't know about type %T!\n"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; v&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;do&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;21&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;do&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"hello"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;do&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;true&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// Twice 21 is 42&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// "hello" is 5 bytes long&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// I don't know about type bool!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="errors"&gt;Errors &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#errors"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go programs express error state with error values. The error type is a built-in interface similar to &lt;code&gt;fmt.Stringer&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;type&lt;/span&gt; &lt;span class="token builtin"&gt;error&lt;/span&gt; &lt;span class="token keyword"&gt;interface&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="token function"&gt;Error&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As with &lt;code&gt;fmt.Stringer&lt;/code&gt;, the fmt package looks for the error interface when printing values.&lt;br /&gt;
Functions often return an error value, and calling code should handle errors by testing whether the error equals nil.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;i&lt;span class="token punctuation"&gt;,&lt;/span&gt; err &lt;span class="token operator"&gt;:=&lt;/span&gt; strconv&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Atoi&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"42"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;if&lt;/span&gt; err &lt;span class="token operator"&gt;!=&lt;/span&gt; &lt;span class="token boolean"&gt;nil&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;    fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Printf&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"couldn't convert number: %v\n"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; err&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;return&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"Converted integer:"&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; i&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="goroutines"&gt;Goroutines &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#goroutines"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A goroutine is a lightweight thread managed by the Go runtime.&lt;/p&gt;
&lt;pre class="language-go"&gt;&lt;code class="language-go"&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;say&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s &lt;span class="token builtin"&gt;string&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;for&lt;/span&gt; i &lt;span class="token operator"&gt;:=&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;3&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt; i&lt;span class="token operator"&gt;++&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;		time&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Sleep&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;100&lt;/span&gt; &lt;span class="token operator"&gt;*&lt;/span&gt; time&lt;span class="token punctuation"&gt;.&lt;/span&gt;Millisecond&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;		fmt&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;Println&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;func&lt;/span&gt; &lt;span class="token function"&gt;main&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;	&lt;span class="token keyword"&gt;go&lt;/span&gt; &lt;span class="token function"&gt;say&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"world"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;	&lt;span class="token function"&gt;say&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;"hello"&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// hello&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// world&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// world&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// hello&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// hello&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id="observations"&gt;Observations &lt;a class="direct-link" href="https://lukesingham.com/go-tour-summary/#observations"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;unused variables are not allowed by the compiler - very cool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hard concepts (read more on)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pointer indirection
&lt;ul&gt;
&lt;li&gt;performance&lt;/li&gt;
&lt;li&gt;modify in place&lt;/li&gt;
&lt;li&gt;when optional, pointer to a string... no empty strings in go. But the pointer to the string will be &lt;code&gt;nil&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;interfaces and polymorphism (types)&lt;/li&gt;
&lt;li&gt;concurrency&lt;/li&gt;
&lt;li&gt;stringer, but why? Pretty printing? &lt;a href="https://tour.golang.org/methods/17"&gt;https://tour.golang.org/methods/17&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;skipped&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;exercises&lt;/li&gt;
&lt;li&gt;reader&lt;/li&gt;
&lt;li&gt;images&lt;/li&gt;
&lt;li&gt;routines, channels, buffered channels, range and close, select,sync.Mutex&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;typing a particular concept into youtube usual has a human to explain it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sentdex is pretty good at explaining in 5mins&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;is go functional? Nope and it's not OO. It's procedural. Very explicit.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description><author>Luke Singham</author><pubDate>Mon, 07 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lukesingham.com/go-tour-summary/</guid></item><item><title>A Call</title><link>https://ho.dges.online/words/commonplace/a-call/</link><description>&lt;p&gt;‘Hold on,’ she said, ‘I’ll just run out and get him.&lt;br /&gt;
The weather here’s so good, he took the chance.&lt;br /&gt;
To do a bit of weeding.”&lt;/p&gt;
&lt;p&gt;So I saw him&lt;br /&gt;
Down on his hands and knees beside the leek rig,&lt;br /&gt;
Touching, inspecting, separating one&lt;br /&gt;
Stalk from the other, gently pulling up&lt;br /&gt;
Everything not tapered, frail and leafless,&lt;br /&gt;
Pleased to feel each little weed-root break,&lt;br /&gt;
But rueful also&amp;hellip;&lt;/p&gt;
&lt;p&gt;Then I found myself listening to&lt;br /&gt;
The amplified grave ticking of hall clocks&lt;br /&gt;
Where the phone lay unattended in a calm&lt;br /&gt;
Of mirror glass and sunstruck pendulums…&lt;/p&gt;</description><author>ho.dges.online</author><pubDate>Mon, 07 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/words/commonplace/a-call/</guid></item><item><title>Why I turned my homepage into a timeline</title><link>https://www.mootoday.com/blog/why-i-turned-my-homepage-into-a-timeline</link><description>A short explanation of why I streamlined the homepage into a timeline showcasing my blog posts, Twitter stats, YouTube videos, and projects.</description><author>www.mootoday.com - RSS Feed</author><pubDate>Sun, 06 Dec 2020 22:21:32 GMT</pubDate><guid isPermaLink="true">https://www.mootoday.com/blog/why-i-turned-my-homepage-into-a-timeline</guid></item><item><title>Learning to Program by Making a Game</title><link>https://www.mikekasberg.com/blog/2020/12/06/learning-to-program-by-making-a-game.html</link><description>&lt;p&gt;This year, &lt;a href="https://www.csedweek.org/"&gt;Computer Science Education Week&lt;/a&gt; will be
December 7-13, 2020. In honor of CS Education Week, I wanted to write this blog
post about the first computer game I wrote, and what I learned along the way. I
was about thirteen, and this story picks up near where I left off in my previous
blog post about &lt;a href="https://www.mikekasberg.com/blog/2017/12/04/my-first-program.html"&gt;my first computer program&lt;/a&gt;. When I wrote that blog post in 2017, I was
working mostly from memory. Since then, I actually &lt;em&gt;found an old floppy disk&lt;/em&gt;
with my game on it. And finding that old floppy disk got me thinking about about
how much I learned from writing computer games in my childhood, and how much
others might be able to learn from writing their own first computer games today.&lt;/p&gt;

&lt;p&gt;&lt;img alt="3.5&amp;quot; floppy disk - Tag Game" src="https://www.mikekasberg.com/images/tag-game/floppy.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;At a young age, I became fascinated with computers because by programming, you
can make something from nothing. You don’t need to pay money for a new Lego set,
and you don’t need a trip to the craft shop or the hardware store. You don’t
need any building material. With computers, you can make something that’s
interesting and valuable with just your brain. Most thirteen-year-olds probably
just want to &lt;em&gt;play&lt;/em&gt; computer games, but I wanted to &lt;em&gt;build my own&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id="building-games-with-game-maker"&gt;Building Games with Game Maker&lt;/h2&gt;

&lt;p&gt;My desire to build my own computer game led me to a piece of software called
&lt;a href="https://web.archive.org/web/20030623090955/http://gamemaker.nl:80/"&gt;Game Maker&lt;/a&gt;.
This software made it relatively easy to program computer games from scratch. At
least, easy enough that a thirteen-year-old could figure it out. Although it
wasn’t &lt;em&gt;quite&lt;/em&gt; as easy as the drag-and-drop programming
&lt;a href="https://scratch.mit.edu"&gt;Scratch&lt;/a&gt; provides today, the principles were largely
the same. In Game Maker, you create rooms and objects, and the objects can
display as &lt;a href="https://en.wikipedia.org/wiki/Sprite_(computer_graphics)"&gt;sprites&lt;/a&gt;.
Game Maker provides a UI for programming the game by making the objects respond
to different events. You can make objects move by responding to keyboard events,
and you can make objects interact with each other by responding to collision
events. The combination of these inputs and interactions makes a complete game.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Game Maker screenshot" src="https://www.mikekasberg.com/images/tag-game/game-maker-interface.png" /&gt;&lt;/p&gt;

&lt;p&gt;When I was a young teenager, Game Maker was the perfect program to satisfy my
curiosity about programming video games. It was relatively easy to learn, but it
was also very powerful. I wanted to program a multiplayer game so several people
could play at once on the same machine, like a Nintendo or a PlayStation. My
idea was simple – I was going to program a computer version of the playground
game “tag”. Fortunately for me, the logic for a tag game isn’t too complex. Each
player needs to be able to move, and you need to know when someone runs into
someone else. A perfect programming challenge for a young teenager!&lt;/p&gt;

&lt;p&gt;&lt;img alt="Tag game" src="https://www.mikekasberg.com/images/tag-game/animated-tag.webp" /&gt;&lt;/p&gt;

&lt;h2 id="programming-games-is-educational"&gt;Programming Games Is… Educational?&lt;/h2&gt;

&lt;p&gt;Yes! Programming computer games can be very educational! As a lot of research
around &lt;a href="https://www.pblworks.org/what-is-pbl"&gt;project based learning&lt;/a&gt; shows,
there’s no better way to learn something than to jump right in and do it. By
getting into a project a little outside your comfort zone, you quickly realize
what you don’t know and you’re motivated to learn so you can finish your
project. You’ll remember what you’ve learned better too because you understand
how to apply it.  Project based learning can be significantly more effective
than other forms of education.&lt;/p&gt;

&lt;h3 id="scratch"&gt;Scratch&lt;/h3&gt;

&lt;p&gt;Today, there are a variety of platforms that people (both young and old) can use
to make their own games while building skills in software development.
&lt;a href="https://scratch.mit.edu/"&gt;Scratch&lt;/a&gt; is probably the easiest to get started with
and also the most well-known. Unfortunately, I’ve personally known a few kids
who developed a bad impression of Scratch at a young age. Their first experience
with it might have been a silly project that they didn’t like, or perhaps they
only used it for animations in the past (which they weren’t interested in).
Scratch isn’t limited to silly animations or simple programming like making a
robot follow a path. Advanced Scratch projects can be very complex and look like
“real” video games – see &lt;a href="https://www.pblworks.org/what-is-pbl"&gt;Flappy Bird&lt;/a&gt;,
&lt;a href="https://scratch.mit.edu/projects/424511068/"&gt;The Crusty Quest&lt;/a&gt;, or
&lt;a href="https://scratch.mit.edu/projects/148769358/"&gt;Chess&lt;/a&gt;. So while programming games
won’t appeal to &lt;em&gt;everyone&lt;/em&gt;, most kids get excited when they see what Scratch can
do. I’ve taught an &lt;a href="https://www.mikekasberg.com/blog/2017/12/09/hour-of-code-2017.html"&gt;Hour of Code&lt;/a&gt;
for several years using Scratch (usually with some variation of a simple game)
and every single time the kids get excited when they see my game and realize
they’re going to be given the tools and knowledge to build their own.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Scratch asteroids game" src="https://www.mikekasberg.com/images/tag-game/scratch-asteroids.png" /&gt;&lt;/p&gt;

&lt;p&gt;Fundamentally, Scratch works with all the same principles I used when I made my
first game in Game Maker. You create a scene, you put objects in the scene, and
you program those objects to respond to input and events. I even re-wrote my tag
game (the one I made with Game Maker) &lt;a href="https://scratch.mit.edu/projects/453364463/"&gt;in
Scratch&lt;/a&gt;, just to prove to myself
that it wouldn’t be hard to do. In addition to that, I’ve written an &lt;a href="https://scratch.mit.edu/projects/187823663/"&gt;asteroids
game&lt;/a&gt;, a &lt;a href="https://scratch.mit.edu/projects/24016542/"&gt;drawing
program&lt;/a&gt;, a &lt;a href="https://scratch.mit.edu/projects/24030594/"&gt;platform
game&lt;/a&gt;, and a simple &lt;a href="https://scratch.mit.edu/projects/20975600/"&gt;Frogger
clone&lt;/a&gt;. I designed most of these as
part of lessons I was teaching, but the important thing is that any of these
games could be written by a motivated 5th grader. When I wrote these projects,
my goal was to make a fun game with simple code that’s easy to understand.
Scratch lets you look at the code behind any game, and the code for most of mine
is usually no more than about 50 lines long (&lt;a href="https://scratch.mit.edu/projects/187823663/editor/"&gt;take a
look&lt;/a&gt;)! This makes it easy
to modify other people’s projects (turn Asteroids into
&lt;a href="https://scratch.mit.edu/projects/188436807/"&gt;Dodgeball&lt;/a&gt;) or learn from them to
make your own!&lt;/p&gt;

&lt;h3 id="other-tools"&gt;Other Tools&lt;/h3&gt;

&lt;p&gt;Of course, in addition to Scratch, there are several other more advanced tools
available. At some point, Scratch becomes too limiting and too boring, and you
want to build better things with more advanced tools. &lt;a href="https://appinventor.mit.edu/"&gt;MIT App
Inventor&lt;/a&gt; uses the same kind of programming blocks
that Scratch uses, but provides a wider variety of blocks and allows you to
create phone apps that will actually run on real phones. It’s a great tool to
move on to when you get bored with Scratch! Alternatively, you could give
&lt;a href="https://gdevelop-app.com/"&gt;GDevelop&lt;/a&gt; a try. GDevelop is a much more advanced
tool for building real computer games, but it operates on many of the same of
the program I used back in 2003. No matter what tool you’re using, finding a
good tutorial (either written or on YouTube) isn’t a bad place to start.&lt;/p&gt;

&lt;p&gt;Building computer games can be as fun as playing them, and I hope I’ve inspired
you (or your children!) to try building something and to learn something new
along the way! If you like my Scratch games, come &lt;a href="https://scratch.mit.edu/users/mkasberg/"&gt;follow me on
Scratch&lt;/a&gt;!&lt;/p&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Sun, 06 Dec 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/12/06/learning-to-program-by-making-a-game.html</guid></item><item><title>Using Jupyter Notebook as GIS</title><link>https://geo.rocks/post/using-jupyter-as-gis/</link><description>&lt;p&gt;&lt;img alt="Jupyter Basemap Plot" src="https://geo.rocks/img/jupyter-basemap-plot-small.jpg" title="Jupyter Basemap Plot" /&gt;
Clipping a geodataframe and displaying it on a basemap in Jupyter.&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Sun, 06 Dec 2020 13:23:22 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/using-jupyter-as-gis/</guid></item><item><title>Update on Old Posts</title><link>https://rjp.is/blogging/posts/2020/12/update-on-old-posts/</link><description>In which we look back and update ourselves.</description><author>infrequent oscillations</author><pubDate>Sun, 06 Dec 2020 10:52:43 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/12/update-on-old-posts/</guid></item><item><title>CSS Variables are cool</title><link>https://secretGeek.net/var_hue</link><description>&lt;p&gt;&lt;small&gt;(Technically they're called &lt;strong&gt;properties&lt;/strong&gt;, but everyone calls them &lt;strong&gt;variables&lt;/strong&gt; because of the &lt;code&gt;var(--mycolor)&lt;/code&gt; syntax -- and I'm a descriptivist not a prescriptivist, so I'm gonna call 'em &lt;strong&gt;variables&lt;/strong&gt; too.)&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;Now... CSS Variables are &lt;strong&gt;COOL&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The hooded figures who lurk near the Forbidden Dog Park don't want you to know about CSS Variables. The Sherriff's Secret Police  would rather we did not discuss CSS Variables. But I Must Press On With This Blog Post.&lt;/p&gt;
&lt;p&gt;I started using CSS Variables when &lt;a href="https://nimbletext.com/live"&gt;revamping NimbleText with dark mode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But I didn't even begin to scratch the surface then. I didn't &lt;em&gt;get it&lt;/em&gt; (I didn't need to) but now the deeper I dig, the more power I find. No wonder shadowy helicopters hover outside the window of my office tower, even now.&lt;/p&gt;
&lt;h2 id="basic-usage"&gt;Basic usage&lt;/h2&gt;
&lt;p&gt;First, I used Css Variables as a way to make sure I could define useful colors &amp;quot;just once&amp;quot;, and reuse them consistently.&lt;/p&gt;
&lt;p&gt;e.g. you can define a &amp;quot;main&amp;quot; background color like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;:root {
	--main-bg: #FFF;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;And apply it to any selectors you want:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;body {
	background-color: var(--main-bg);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;And you can override that... for example for your dark theme:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;@media (prefers-color-scheme: dark) {
	:root {
		--main-bg: #222;
	}
}
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;And that's fun. But the fun doesn't stop there!&lt;/p&gt;
&lt;h2 id="sidebar-wait-whats-the-root"&gt;Sidebar: wait what's the &lt;code&gt;:root&lt;/code&gt; ??&lt;/h2&gt;
&lt;p&gt;You may have noticed, above, that we applied our variable definition to a &lt;code&gt;:root&lt;/code&gt; selector... &lt;em&gt;what is that strange thing?&lt;/em&gt; and what other options do we have?&lt;/p&gt;
&lt;p&gt;The colon prefix tells us it's a &amp;quot;pseudo-class&amp;quot; (like &lt;code&gt;:hover&lt;/code&gt; or &lt;code&gt;:focus&lt;/code&gt;), in this case it's a special pseudo-class meaning the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:root"&gt;root of the document&lt;/a&gt;. So the variable we created applies to the whole document.&lt;/p&gt;
&lt;p&gt;We could also have &amp;quot;scoped&amp;quot; the variable to just a part of the document...&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;footer {
	--bg: #222;
	background-color:var(--bg);
}&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;I'm not using &lt;em&gt;that&lt;/em&gt; piece of knowledge yet, but I mention it because many authors gloss over it, and also, perhaps because a skeletal figure just dragged his ragged body across the floor of my office, rose to his bony feet, brandished a glistening metallic weapon with a bright logo from &amp;quot;Cranial Extracto Matic&amp;quot; and screamed, in a voice like a thousand metal polar bears shrieking in agony as they are fed into a terrible grinding machine, that it would perhaps be wisest if I refrained from mentioning &amp;quot;:pseudo elements&amp;quot; in this particular blog post. And I am a bit of a contrarian on these things.&lt;/p&gt;
&lt;h2 id="now-for-something-cool"&gt;Now for something cool&lt;/h2&gt;
&lt;p&gt;The cool thing I've noticed more recently (and why I'm writing to you about this now) is this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can reference variables from variables.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;🤯&lt;/p&gt;
&lt;p&gt;... and referencing variables from variables must have many uses, an infinite number of uses.&lt;/p&gt;
&lt;p&gt;For me, an immediate and powerful use is for doing custom themes &lt;em&gt;properly&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In a real world theme, on a real world site, you don't end up with just 2 or 3 colors. You end up with many, many slightly different variations on a smaller number of &lt;em&gt;hues&lt;/em&gt;. (A good recent article on the topic is &lt;a href="https://refactoringui.com/previews/building-your-color-palette/"&gt;here&lt;/a&gt;). If a button has a gradient, then it has several variations of the initial color. A panel may have a less saturated version of a background color, pushing it into the distance. Many variations, many colors -- but very few hues.&lt;/p&gt;
&lt;p&gt;With Css Variables we can reuse an underlying &lt;em&gt;hue&lt;/em&gt; with different &lt;code&gt;saturation&lt;/code&gt;, &lt;code&gt;lightness&lt;/code&gt; or &lt;code&gt;opacity&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of putting an entire &lt;em&gt;color&lt;/em&gt; into a variable, start by putting your &lt;em&gt;hue&lt;/em&gt; into a variable.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;:root {
	--main-hue: 124; /* a green hue */
}
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;If we have a &amp;quot;greenish&amp;quot; theme, perhaps a variation on the hue of the green slime that has begun to bleed from the shadowy apparition who hovers even now abaft the cavernous black void that threatens the rusted children's play equipment in the boarded up park across the road, then we can store our &amp;quot;hue&amp;quot; and  make sure that every &amp;quot;greenish&amp;quot; color on our site is based upon that hue.&lt;/p&gt;
&lt;p&gt;Write your colors in &lt;code&gt;hsla&lt;/code&gt; format... e.g:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;:root {
	--main-hue: 124; /* a green hue */
	--main-bg: hsla(var(--main-hue),100%, 13%, 1); /* background */
	--main-fg: hsla(var(--main-hue), 17%, 86%,1); /* foreground */
}&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;... and so on.&lt;/p&gt;
&lt;p&gt;Thus your whole theme can build up and having many colors based on a small number of hues.&lt;/p&gt;
&lt;p&gt;The dark theme might even use the same hue, but flip the saturation/lightness of the colors that build upon it. It's flexible enough to achieve anything you need. And all the while, a single fact such as the base hues of your theme are not repeated.&lt;/p&gt;
&lt;p&gt;It's DRY, it's separation of concerns. All those &amp;quot;principles&amp;quot; people used to go on about back in the Olden times of Before.&lt;/p&gt;
&lt;p&gt;With your underlying &lt;em&gt;hue&lt;/em&gt; defined in a variable, you can change a single line of CSS and completely alter your theme.&lt;/p&gt;
&lt;h2 id="now-make-it-dynamic"&gt;Now make it dynamic...&lt;/h2&gt;
&lt;p&gt;Oh but wait, it's cooler than that.&lt;/p&gt;
&lt;p&gt;In one line you can also change those variables with javascript.&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;var root = document.documentElement;
root.style.setProperty('--main-hue', 0); // now the theme color is pure red (`hue = 0`), not that slime-like green.
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Or if -- like me -- you're a fan of taking things too far, you can have a timer that randomly tries out different hues, and a stop button for when you're happy.&lt;/p&gt;
&lt;p&gt;Or you can have several hues all rotated by various amounts from each other, in triads, or complements etc. You can &amp;quot;AB test&amp;quot; different values, or survey a small group to see the best possible themes.&lt;/p&gt;
&lt;p&gt;This is much closer to how things should be (and it's also much more satisfying than using a pre-processor). The stylesheet encodes the underlying relationships between the properties, instead of just hard-coding the final values everywhere.&lt;/p&gt;
&lt;p&gt;The art of science is the science of turning art into a science and the art of turning science into an art of science. Or something.&lt;/p&gt;
&lt;p&gt;All of this is powerful stuff that no one is talking about. Maybe because THE MAN wants to keep us DOWN, or because BIG CSS wants us to be silent and happy with our &lt;code&gt;rem&lt;/code&gt;s and our &lt;code&gt;em&lt;/code&gt;s. But I'm not going to be quiet about this anymore. Variables are there: do something extraordinary with them today.&lt;/p&gt;
&lt;p&gt;Oh and bonus points if you also use &lt;code&gt;calc()&lt;/code&gt; with them -- i'd love to hear about some interesting uses of &lt;code&gt;calc&lt;/code&gt; with &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My lawyer also wishes me to make it known that certain elements of this blog post would not have been possible if I had not recently begun listening to far too much &amp;quot;&lt;a href="http://www.welcometonightvale.com/"&gt;Welcome to Night Vale&lt;/a&gt;&amp;quot;; a very, very, &lt;strong&gt;very&lt;/strong&gt; good podcast. There are also books.&lt;/p&gt;</description><author>secretgeek.net</author><pubDate>Sun, 06 Dec 2020 09:29:36 GMT</pubDate><guid isPermaLink="true">https://secretGeek.net/var_hue</guid></item><item><title>Type classes with Scala 2</title><link>http://justinhj.github.io/2020/12/06/type-classes-scala-2.html</link><description>&lt;p&gt;
&lt;img alt="A colourful abascus" src="/../images/crissy-jarvis-cHhbULJbPwM-unsplash-small.jpg" title="Abacus" /&gt;
&lt;/p&gt;
&lt;span&gt;Photo by &lt;a href="https://unsplash.com/@crissyjarvis?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Crissy Jarvis&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/abacus?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/span&gt;

&lt;div class="outline-2" id="outline-container-orge38ea18"&gt;
&lt;h2 id="orge38ea18"&gt;Make your own Numeric type class&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orge38ea18"&gt;
&lt;p&gt;
This is the companion blog for a Functional Justin video which you can
find here &lt;a href="https://youtu.be/pJFfXhZlR5o"&gt;https://youtu.be/pJFfXhZlR5o&lt;/a&gt;. This is a series of
coffee-break sized videos that each explore a topic in the world of
Scala Functional Programming.
&lt;/p&gt;

&lt;p&gt;
In this video I talk about Type classes and here is the blog version for those that would rather read.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-orge66e206"&gt;
&lt;h2 id="orge66e206"&gt;What are type classes&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orge66e206"&gt;
&lt;p&gt;
Here are some good references for reading about type classes in Scala (they can of course be implemented in other functional programming languages).
&lt;/p&gt;

&lt;p&gt;
Sam Halliday has a great introduction to data types and type classes in his book Functional Programming for Mortals.
&lt;a href="https://leanpub.com/fpmortals/read#leanpub-auto-data-and-functionality"&gt;https://leanpub.com/fpmortals/read#leanpub-auto-data-and-functionality&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
This idea of separating data from functions can also be found in the Cats functional programming library, with the library itself being organised into distinct sections for data types and type classes.
&lt;a href="https://typelevel.org/cats/typeclasses.html"&gt;https://typelevel.org/cats/typeclasses.html&lt;/a&gt;
&lt;a href="https://typelevel.org/cats/datatypes"&gt;https://typelevel.org/cats/datatypes&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
My former colleague and functional programming advocate Francis Toth also has a nice blog on this topic.
&lt;a href="https://contramap.dev/2020/04/09/typeclasses.html"&gt;https://contramap.dev/2020/04/09/typeclasses.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
In my own words, type classes are not explicitly part of the Scala
language, but are rather a pattern of implementation that enable you
to define behaviours which can then be implemented for data
types. Data types are values like strings and numbers, collections
like lists and sets and "higher kinded types" like IO, ZIO and so on.
&lt;/p&gt;

&lt;p&gt;
Type classes do not have to be implemented a certain way, but in Cats,
Scalaz and other libraries you will find them implemented just as they
are here, but additional layers of complexity to manage things like
stack safety and take advantage of tools to generate boilerplate code.
&lt;/p&gt;

&lt;p&gt;
In general type classes consist of:
&lt;/p&gt;

&lt;ul class="org-ul"&gt;
&lt;li&gt;A trait that has one, or sometimes more, type parameters.&lt;/li&gt;
&lt;li&gt;It contains one or more abstract methods. These define behaviours that must be implemented for each &lt;code&gt;instance&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Also you will find generalized methods that are built using the abstract ones.&lt;/li&gt;
&lt;li&gt;Typically a type class contains no data&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-org6576dab"&gt;
&lt;h2 id="org6576dab"&gt;Numeric&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org6576dab"&gt;
&lt;p&gt;
In the video I implemented the Numeric type class. What is Numeric? It
is a type class you'll find in the Scala standard library and is used
to build a generic representation of numbers.
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://www.scala-lang.org/api/current/scala/math/Numeric.html"&gt;https://www.scala-lang.org/api/current/scala/math/Numeric.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
What I develop here is just enough that we can use it for the
expression evaluator in the first video (which only requires add and
multiply operations).
&lt;/p&gt;

&lt;p&gt;
You can find the complete code here
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://github.com/justinhj/evalexample/blob/master/src/main/scala/Scala2Numeric.scala"&gt;https://github.com/justinhj/evalexample/blob/master/src/main/scala/Scala2Numeric.scala&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Let's look at the pieces one by one&amp;#x2026;
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;trait&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;] {
  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;Add&lt;/span&gt;(a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;, b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;
  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;Mul&lt;/span&gt;(a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;, b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;

  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;square&lt;/span&gt;(a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; mul(a, a)
}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here we define the trait which decribes the core of our type class;
what it can do, and what you need to implement if you want your data
type to be an instance of this typeclass.
&lt;/p&gt;

&lt;p&gt;
Add and Mul are abstract, whilst the square function is derived or
generalized and does not need to be implemented when making new
supported instances.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-org059d026"&gt;
&lt;h2 id="org059d026"&gt;Instances&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org059d026"&gt;
&lt;p&gt;
Once you have the interface for your type class you can define instances for various data types. Here we define the instance for &lt;code&gt;Long&lt;/code&gt;.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;numericLong&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Long&lt;/span&gt;] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;new&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Long&lt;/span&gt;] {
  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;add&lt;/span&gt;(a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Long&lt;/span&gt;, b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Long&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Long&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; a + b
  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;mul&lt;/span&gt;(a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Long&lt;/span&gt;, b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Long&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Long&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; a * b
}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Note that this is implicit to make it easier to use our instances with
other types, taking advantage of the fact that users can import the
definititions and then use them in their code.
&lt;/p&gt;

&lt;p&gt;
Here's an example function that is written using the Numeric type
class as a parameter. This function displays what we call &lt;code&gt;ad-hoc
polymorphism&lt;/code&gt;, in that this function does not know all of the
instances that exist for the input type &lt;code&gt;T&lt;/code&gt;, nor does it need to. All
it knows is that to do its work it needs an instance of &lt;code&gt;Numeric[T]&lt;/code&gt;
so that it can access the &lt;code&gt;add&lt;/code&gt; method.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;sumList&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;](ts&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;List&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;])(&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; numeric&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;])&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; {
  ts.reduce((a, b) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; numeric.&lt;span style="color: #00bcff;"&gt;Add&lt;/span&gt;(a,b))
}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now we can sum a list of any &lt;code&gt;T&lt;/code&gt; where T has a Numeric instance. Here we use the Int instance (not shown).
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;l1&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;List&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;1&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;2&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;3&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;4&lt;/span&gt;)
&lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;sum&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; sumList(l1)

println(s&lt;span style="color: #79a8ff;"&gt;"sum of int list is &lt;/span&gt;&lt;span style="color: #00d3d0;"&gt;$sum&lt;/span&gt;&lt;span style="color: #79a8ff;"&gt;"&lt;/span&gt;)
&lt;span style="color: #a8a8a8;"&gt;// &lt;/span&gt;&lt;span style="color: #a8a8a8;"&gt;sum of int list is 10&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-org645a66c"&gt;
&lt;h2 id="org645a66c"&gt;Improving the ergonomics&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org645a66c"&gt;
&lt;p&gt;
So that's all you need to build type classes but we can take a couple
of steps to make things more ergonomic. For one we can ditch the
implicit parameter and instead make use of
[[&lt;a href="https://docs.scala-lang.org/tutorials/FAQ/context-bounds.html"&gt;https://docs.scala-lang.org/tutorials/FAQ/context-bounds.html&lt;/a&gt;]context
bounds]]. This makes things clearer for the caller of the function.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;sumList&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;](ts&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;List&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;])&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; {
  &lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;numeric&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; implicitly[&lt;span style="color: #00bcff;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;]]
  ts.reduce((a, b) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; numeric.add(a,b))
}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Note that we have to &lt;code&gt;summon&lt;/code&gt; the implicit Numeric instance using
&lt;code&gt;implicitly&lt;/code&gt;. This is a function in the standard library which takes
advantage of the way context bounds work: the context bound &lt;code&gt;Numeric&lt;/code&gt;
specifies that there is an implicit Numeric instance in scope, but
there is no named parameter as before. The implicitly function lets
us access that implicit in a succinct way.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;implicitly&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;](&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; e&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; e
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
So using context bounds helps a little with the use of type classes,
the next step is to use implicit conversions so that we take the
functions in our type class and make them look like ordinary methods
on the data type.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;object&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;ops&lt;/span&gt; {

  &lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;class&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;NumericOps&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;](a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)(&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; numeric&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;]) {
    &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;add&lt;/span&gt;(b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; numeric.add(a, b)
    &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;mul&lt;/span&gt;(b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; numeric.mul(a, b)

    &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;+&lt;/span&gt;(b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; add(b)
    &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;*&lt;/span&gt;(b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;T&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; mul(b)
  }

}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now if we import ops we can take advantage of the implicit conversion from type T to type NumericOps[T] to give us syntax like below.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;s1&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #79a8ff;"&gt;"abcd"&lt;/span&gt;
&lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;s2&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #79a8ff;"&gt;"efgh"&lt;/span&gt;
&lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;product&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; s1 * s2
println(s&lt;span style="color: #79a8ff;"&gt;"product &lt;/span&gt;&lt;span style="color: #00d3d0;"&gt;$product&lt;/span&gt;&lt;span style="color: #79a8ff;"&gt;"&lt;/span&gt;)
&lt;span style="color: #a8a8a8;"&gt;// &lt;/span&gt;&lt;span style="color: #a8a8a8;"&gt;product aeafagahbebfbgbhcecfcgchdedfdgdh&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
So you can see that by implementing a somewhat goofy instance of
Numeric for string (given below) we now have the ability to use the
multiplication operator on it as if it was a regular number.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;stringNumeric&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;String&lt;/span&gt;] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;new&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Numeric&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;String&lt;/span&gt;] {
    &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;add&lt;/span&gt;(a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;, b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; a + b

    &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;mul&lt;/span&gt;(a&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;, b&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;for&lt;/span&gt; (
      as &lt;span style="color: #b6a0ff;"&gt;&amp;lt;-&lt;/span&gt; a;
      bs &lt;span style="color: #b6a0ff;"&gt;&amp;lt;-&lt;/span&gt; b;
      s &lt;span style="color: #b6a0ff;"&gt;&amp;lt;-&lt;/span&gt; as.toString ++ bs.toString) &lt;span style="color: #b6a0ff;"&gt;yield&lt;/span&gt; s
  }
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Note that while this implentation of string arithmetic is not very
rigorous and just for fun, there's nothing to stop you from
implementing Numeric for data types that do have well defined
arithmetic operations such as Roman Numerals.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-org40f4c54"&gt;
&lt;h2 id="org40f4c54"&gt;Coherence&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org40f4c54"&gt;
&lt;p&gt;
Type class coherence is an important concept I'll leave you with. This
is a guideline in place to keep programs easy to reason about. It's a
good practice to keep common instances together with your type classes
so that users can easily find them, and don't duplicate the work. It's
also important that you don't try to make multiple instances and let
the users select one depending on their needs. The reason for that is
the behaviour of your program can change profoundly when you do this,
and that's terrible. It means you can't take advantage of &lt;code&gt;local
reasoning&lt;/code&gt;, one of the benefits of functional programming. You would
need to be very careful with imports to make sure you are using the
instance you think you are.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-orgc682686"&gt;
&lt;h2 id="orgc682686"&gt;Final words&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orgc682686"&gt;
&lt;p&gt;
If you're coming from Java or similar OOP language you may recognise
some of this as the adapter pattern (except with Scala
implicits). Type class traits also have similarities to Go interfaces,
although the type class pattern goes a bit beyond them in scope.
&lt;/p&gt;

&lt;p&gt;
I would be amiss not to mention Haskell here, which has type classes
implemented as a first-class language construct, and for some people
the over-use of type classes in Scala is somewhat of an
anti-pattern. We will see in future videos that the pattern will be
greatly simplified in Scala 3 however.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-orgc07e8a4"&gt;
&lt;h2 id="orgc07e8a4"&gt;References&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orgc07e8a4"&gt;
&lt;p&gt;
Typelevel Cats functional programming library documentation
&lt;a href="https://typelevel.org/cats/"&gt;https://typelevel.org/cats/&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Functional Programming for Mortals
&lt;a href="https://leanpub.com/fpmortals"&gt;https://leanpub.com/fpmortals&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&amp;copy; 2020 Justin Heyes-Jones. All Rights Reserved.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><author>Functional[Justin]</author><pubDate>Sun, 06 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://justinhj.github.io/2020/12/06/type-classes-scala-2.html</guid></item><item><title>Update for December, year of total chaos 2020</title><link>https://ciesie.com/post/update_06122020/</link><description>&lt;p&gt;This will be the last update for 2020. We&amp;rsquo;re almost on the other side! We shouldn&amp;rsquo;t expect much out
of 2021, since the time doesn&amp;rsquo;t care about our labels. Still, there is a feeling of hope that we&amp;rsquo;ll
be able to, slowly, transition to post pandemic world. How will that world look like? Time will
tell.&lt;/p&gt;
&lt;p&gt;Last few months have been very productive for me. For better or worse. It&amp;rsquo;s nice to create and have
a lot of fun ideas but&amp;hellip; there is only so much time in a day. Self isolation, working from home,
etc. help save time but that means I&amp;rsquo;m working way more than before pandemic. I&amp;rsquo;ll certainly need
some quality vacation soon.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Sun, 06 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/update_06122020/</guid></item><item><title>Beach • Art</title><link>https://muffinman.io/art/beach/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;Two separate plots, and I&amp;#x27;m super happy how I managed to align them. On the last image, you can see the lines I drew to help me align it. My wife insisted we keep this one.&lt;/p&gt;
&lt;p&gt;Pigma Micron pens are indestructible, just saying.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;December 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;70x35cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Bristol 220gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Pigma Micron&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery art-gallery--wide"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1239" src="./0.jpg" width="2500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="2200" src="./w_500-h_500--1.jpg" width="2200" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./2.jpg"&gt;&lt;img alt="" class="gallery__image" height="1680" src="./w_500-h_500--2.jpg" width="2000" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Sun, 06 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/beach/</guid></item><item><title>AWS Sagegemaker Jupyter Notebook</title><link>https://blog.cetinich.net/content/2020/2020-aws-sagemaker/</link><description>I wanted to upgrade the version of pandas that comes with AWS Sagemaker
Notebook to &gt; 1.1 because this simplify handling of group by with null
or NaN values.</description><author>Brent's Blog</author><pubDate>Sun, 06 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-aws-sagemaker/</guid></item><item><title>[Computing] Modifying and running a binary by recompiling a reverse engineered disassembly</title><link>https://www.devever.net/~hl/recompile</link><description>&lt;p&gt;You're reverse engineering an executable and you want to modify it. Perhaps you
want to add or tweak functionality of the executable, or perhaps you want to be
able to modify parts of the program to get a better understanding of how it
works. Either way, you want to start with a working binary and gradually
replace some parts of it (but not others) with C code as you gradually
understand more of the binary.&lt;/p&gt;</description><author>devever.net/~hl</author><pubDate>Sun, 06 Dec 2020 01:36:00 GMT</pubDate><guid isPermaLink="true">https://www.devever.net/~hl/recompile</guid></item><item><title>Language Servers are the New Frameworks</title><link>https://www.swyx.io/language-servers</link><description>Developer Experience is shifting left, all the way to onKeyUp.</description><author>swyx's site RSS Feed</author><pubDate>Sat, 05 Dec 2020 22:51:05 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/language-servers</guid></item><item><title>Lessons from Sweden about going cashless</title><link>https://stop.zona-m.net/2020/12/lessons-from-sweden-about-going-cashless/</link><description>&lt;p&gt;The most interesting ones are about the MEANING of money.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 05 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/lessons-from-sweden-about-going-cashless/</guid></item><item><title>Emulating a Computer: The CHIP-8 Interpreter</title><link>https://riv.dev/emulating-a-computer-part-1/</link><description>How to write a CHIP-8 emulator.</description><author>River Gillis [riv.dev]</author><pubDate>Sat, 05 Dec 2020 02:42:00 GMT</pubDate><guid isPermaLink="true">https://riv.dev/emulating-a-computer-part-1/</guid></item><item><title>Emacs: Rotate my macOS display</title><link>https://xenodium.com/emacs-rotate-my-macos-display</link><description>&lt;p&gt;Every so often, I rotate my monitor (vertical vs horizontal) for either work or to watch a movie. macOS enables changing the display rotation via a dropdown menu (under &lt;em&gt;Preferences &amp;gt; Displays &amp;gt; Rotation&lt;/em&gt;) where you can pick between &lt;em&gt;Standard&lt;/em&gt;, &lt;em&gt;90°&lt;/em&gt;, &lt;em&gt;180°&lt;/em&gt;, and &lt;em&gt;270°&lt;/em&gt;. That's all fine, but what I'd really like is a quick way to toggle between my preferred two choices: &lt;em&gt;Standard&lt;/em&gt; and &lt;em&gt;270°&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Unsurprisingly, I'd also like to invoke it as an interactive command via Emacs's &lt;em&gt;M-x&lt;/em&gt; (see &lt;a href="http://xenodium.com/emacs-connect-my-bluetooth-speaker/index.html"&gt;Emacs: connect my Bluetooth speaker&lt;/a&gt;). With narrowing frameworks like &lt;a href="https://github.com/abo-abo/swiper"&gt;ivy&lt;/a&gt;, &lt;a href="https://emacs-helm.github.io/helm/"&gt;helm&lt;/a&gt;, and &lt;a href="https://www.gnu.org/software/emacs/manual/html_mono/ido.html"&gt;ido&lt;/a&gt;, invoking these commands is just a breeze.&lt;/p&gt;
&lt;p&gt;Turns out, this was pretty simple to accomplish, thanks to Eric Nitardy's &lt;a href="https://github.com/CdLbB/fb-rotate"&gt;fb-rotate&lt;/a&gt; command line utility. All that's left to do is wrap it in a tiny elisp &lt;s&gt;function&lt;/s&gt; hack, add the toggling logic, and voilà!&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-rotate-my-macos-display/rotate.gif" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The screen capture goes a little funky when rotating the display, but you get the idea. It works better in person :)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;…and here's the snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun ar/display-toggle-rotation ()
  (interactive)
  (require 'cl-lib)
  (cl-assert (executable-find &amp;quot;fb-rotate&amp;quot;) nil
             &amp;quot;Install fb-rotate from https://github.com/CdLbB/fb-rotate&amp;quot;)
  ;; #  Display_ID    Resolution  ____Display_Bounds____  Rotation
  ;; 2  0x2b347692    1440x2560      0     0  1440  2560    270    [main]
  ;; From fb-rotate output, get the `current-rotation' from Column 7, row 1 zero-based.
  (let ((current-rotation (nth 7 (split-string (nth 1 (process-lines &amp;quot;fb-rotate&amp;quot; &amp;quot;-i&amp;quot;))))))
    (call-process-shell-command (format &amp;quot;fb-rotate -d 1 -r %s&amp;quot;
                                        (if (equal current-rotation &amp;quot;270&amp;quot;)
                                            &amp;quot;0&amp;quot;
                                          &amp;quot;270&amp;quot;)))))
&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sat, 05 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-rotate-my-macos-display</guid></item><item><title>Setup VSCode to run and debug C / C++ code</title><link>https://gourav.io/blog/setup-vscode-to-run-debug-c-cpp-code</link><description>Follow this guide to run, debug, and get IntelliSense for C/C++ files in VSCode</description><author>Gourav Goyal</author><pubDate>Sat, 05 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://gourav.io/blog/setup-vscode-to-run-debug-c-cpp-code</guid></item><item><title>Build a bulletin board using scotty and friends</title><link>https://gilmi.me/post/2020/12/05/scotty-bulletin-board</link><description>A tutorial for haskell-scotty, building a very simple bulletin board website.</description><author>λm.me</author><pubDate>Sat, 05 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://gilmi.me/post/2020/12/05/scotty-bulletin-board</guid></item><item><title>Seldom discussed tips for working in the tech industry</title><link>https://jasoneckert.github.io/myblog/seldom-discussed-tech-industry-tips/</link><description>&lt;p&gt;&lt;img alt="jason tech tips" src="jasontechtips.png#right" title="jason tech tips" /&gt;&lt;/p&gt;
&lt;p&gt;There are plenty of blog posts on the Web that give sage advice for anyone working in the tech industry. However, most of them focus on the same topics: time management, resourcefulness, continuous learning, verbal and written communication skills, caffeine consumption, and so on.&lt;/p&gt;
&lt;p&gt;In this blog post, I&amp;rsquo;ll discuss 6 tech industry tips that are rarely discussed online, but that are equally (if not more) important from my experience over the past three decades in this industry.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Sat, 05 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/seldom-discussed-tech-industry-tips/</guid></item><item><title>Firefox : extensions, configuration et quelques astuces</title><link>/post/2020/12/05/firefox-extensions-configuration-et-quelques-astuces/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Mozilla Firefox est un navigateur libre développé par la fondation Mozilla. Il utilise le moteur de rendu Gecko, le seul concurrent au moteur de Google Chrome sur le marché des moteurs web modernes.&lt;/p&gt;
&lt;figure&gt;&lt;img src="/images/firefox/firefox-logo-horizontal-lockup.png" width="400" /&gt;
&lt;/figure&gt;

&lt;p&gt;Malheureusement Firefox perd constamment des parts de marché face aux autres navigateurs. Selon &lt;a href="https://radar.cloudflare.com/"&gt;radar.cloudflare.com&lt;/a&gt;, Firefox ne représenterait que 6,40% du traffic.&lt;/p&gt;
&lt;figure&gt;&lt;img src="/images/firefox/radarcloudflare.png" /&gt;
&lt;/figure&gt;

&lt;p&gt;Pourtant Firefox dispose de beaucoup d&amp;rsquo;atouts pour qui souhaite un navigateur moderne, éthique et respectueux de la vie privée.&lt;/p&gt;</description><author>Accueil on dbeley</author><pubDate>Sat, 05 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">/post/2020/12/05/firefox-extensions-configuration-et-quelques-astuces/</guid></item><item><title>2020–12–05: Alternate EG25G userspace project</title><link>https://xnux.eu/log/#028</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 05 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#028</guid></item><item><title>Sometimes the best data are those that do not exist</title><link>https://stop.zona-m.net/2020/12/sometimes-the-best-data-are-those-that-do-not-exist/</link><description>&lt;p&gt;Or, what you can learn about privacy from Soviet weapon&amp;rsquo;s philosophy.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 04 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/sometimes-the-best-data-are-those-that-do-not-exist/</guid></item><item><title>Separate core logic from the framework</title><link>https://adamcraven.com/writing/separate-core-logic-from-the-framework/</link><description/><author>Writing on Adam Craven</author><pubDate>Fri, 04 Dec 2020 19:49:16 GMT</pubDate><guid isPermaLink="true">https://adamcraven.com/writing/separate-core-logic-from-the-framework/</guid></item><item><title>QGIS - How to use custom SVG-Markers</title><link>https://geo.rocks/post/qgis-custom-svg-markers/</link><description>&lt;p&gt;&lt;img alt="Using custom SVG-Markers in QGIS" src="https://geo.rocks/img/custom-svg-marker.jpg" title="Using custom SVG-Markers in QGIS" /&gt;&lt;/p&gt;
&lt;p&gt;Use your own SVG as a QGIS marker!&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Fri, 04 Dec 2020 12:13:18 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/qgis-custom-svg-markers/</guid></item><item><title>HttpResponseMessage.Content is non-nullable in NET5</title><link>https://nicolaiarocci.com/httpresponsemessage.content-is-non-nullable-in-net5/</link><description>Today I learned the hard way that NET5 changed the HttpResponseMessage.Content type from nullable to non-nullable</description><author>Nicola Iarocci</author><pubDate>Fri, 04 Dec 2020 08:05:25 GMT</pubDate><guid isPermaLink="true">https://nicolaiarocci.com/httpresponsemessage.content-is-non-nullable-in-net5/</guid></item><item><title>Web Scraping Is Vital</title><link>https://stop.zona-m.net/2020/12/web-scraping-is-vital/</link><description>&lt;p&gt;Seriously. Even if you have NO idea what it is. Keep reading:&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 03 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/web-scraping-is-vital/</guid></item><item><title>The UX of Proving Our Humanity To Machines</title><link>https://www.swyx.io/proving-our-humanity</link><description>What happens when we can't convince machines that we are human?</description><author>swyx's site RSS Feed</author><pubDate>Thu, 03 Dec 2020 18:13:27 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/proving-our-humanity</guid></item><item><title>Using Tailwind UI and Next.js Together</title><link>https://www.khanna.law/blog/using-tailwind-ui-and-next-js-together</link><description>These instructions have been updated to reflect the installation process for TailwindCSS 2.0 and Next.js 10.</description><author>Khanna Law Blog</author><pubDate>Thu, 03 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.khanna.law/blog/using-tailwind-ui-and-next-js-together</guid></item><item><title>Contact Lost • Art</title><link>https://muffinman.io/art/contact-lost/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;It ended up being vertically symmetrical because I forgot to change parameters for the bottom half.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;December 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;30x42cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Fabriano Bristol 250gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Pigma Micron&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="2200" src="./0.jpg" width="1546" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="2200" src="./w_500-h_500--1.jpg" width="1650" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./plot_1080x1280.mp4"&gt;&lt;video class="gallery__video" src="./plot_1080x1280.mp4#t=0.001"&gt;&lt;/video&gt;&lt;svg class="gallery__play-icon" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20 c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Thu, 03 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/contact-lost/</guid></item><item><title>References in Rust</title><link>https://hashrust.com/blog/references-in-rust/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Rust references are very simple at runtime: they are plain memory addresses. At compile time, in contrast, references participate in more complex compiler analysis. For example, references help to prove memory safety of a program. But in this post, I will not cover the safety aspects of references. You have already read about that in the post &lt;a href="https://hashrust.com/blog/memory-safety-in-rust-part-2/" rel="external"&gt;Memory safety in Rust - part 2&lt;/a&gt;. In this post, you will understand the syntactical and usage aspects of references. Let's start with the very basics.&lt;/p&gt;
&lt;h2 id="basics"&gt;Basics&lt;/h2&gt;
&lt;p&gt;Let's say you have a variable &lt;code&gt;x&lt;/code&gt;, which owns a value:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create a reference to &lt;code&gt;x&lt;/code&gt;, you'd use the &lt;code&gt;&amp;amp;&lt;/code&gt; operator:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And to get the value of the referent, you'd use the &lt;code&gt;*&lt;/code&gt; operator:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = *&lt;/span&gt;&lt;span class="z-variable"&gt;r&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All the values and references created above were immutable, which is the default in Rust. If you want to change the value through a reference, create a mutable reference. The &lt;code&gt;&amp;amp;mut&lt;/code&gt; operator creates a mutable reference:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this alone is not enough. You will realize this if you try to compile it:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;2 |     let x: i32 = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |         - help: consider changing this to be mutable: `mut x`&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;5 |     let m = &amp;amp;mut x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |             ^^^^^^ cannot borrow as mutable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error makes sense because it avoids surprises for the programmer. If the compiler had allowed this, a mutable reference (&lt;code&gt;m&lt;/code&gt;) could change an immutable value (&lt;code&gt;x&lt;/code&gt;). Such changes in an immutable value would have been confusing. Let's try the fix suggested by the error message:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//make x mut&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the code compiles fine. Finally, you can change the value through the reference:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-operator"&gt;*&lt;/span&gt;&lt;span class="z-variable"&gt;m&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 100&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="shared-and-mutable-references"&gt;Shared and mutable references&lt;/h2&gt;
&lt;p&gt;Let's now try to create another mutable reference to &lt;code&gt;x&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; n&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;m is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;n is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; n&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it doesn't work:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;error[E0499]: cannot borrow `x` as mutable more than once at a time&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;3 |     let m: &amp;amp;mut i32 = &amp;amp;mut x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                       ------ first mutable borrow occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;4 |     let n: &amp;amp;mut i32 = &amp;amp;mut x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                       ^^^^^^ second mutable borrow occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;5 |     println!(&amp;quot;m is {}&amp;quot;, m);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                         - first borrow later used here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, the error tells us exactly what went wrong. We cannot have two mutable references to a value at the same time. In fact, it goes even further. As long as a mutable reference is alive, it locks the original value.  You can't mutate the value through the owner during the lifetime of a mutable reference:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 100&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;m is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in the following error:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;error[E0506]: cannot assign to `x` because it is borrowed&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;3 |     let m: &amp;amp;mut i32 = &amp;amp;mut x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                       ------ borrow of `x` occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;4 |     x = 100;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |     ^^^^^^^ assignment to borrowed `x` occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;5 |     println!(&amp;quot;m is {}&amp;quot;, m);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                         - borrow later used here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the flip side, you &lt;em&gt;can&lt;/em&gt; create many immutable references to a value at the same time:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; n&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;m is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;n is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; n&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is safe since there is no mutation. But what about both mutable and immutable references at the same time? Should the compiler allow that? The answer is no. Again, for safety reasons this is forbidden:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; n&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;m is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; m&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;n is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; n&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You'll get below error if you try:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;3 |     let m: &amp;amp;i32 = &amp;amp;x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                   -- immutable borrow occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;4 |     let n: &amp;amp;mut i32 = &amp;amp;mut x;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                       ^^^^^^ mutable borrow occurs here&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;5 |     println!(&amp;quot;m is {}&amp;quot;, m);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;  |                         - immutable borrow later used here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To summarize, the usage rules for immutable and mutable references are as follows. For a value, there can be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Either many immutable references.&lt;/li&gt;
&lt;li&gt;Or one mutable reference.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But not both at the same time. For this reason, another term for immutable references is shared references. And a similar term for mutable references is exclusive references.&lt;/p&gt;
&lt;p&gt;So why do references have these rules? You might have guessed by now — to enforce memory safety. (It is in fact due to safety reasons that Rustaceans term creating a reference as &lt;em&gt;borrowing&lt;/em&gt;.) To understand how these rules achieve memory safety, read &lt;a href="https://hashrust.com/blog/memory-safety-in-rust-part-2/" rel="external"&gt;Memory safety in Rust - part 2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even though that post covers memory safety, it still leaves one question unanswered. Why does Rust ban more than one mutable reference on the same thread? That shouldn't cause any harm, right? Turns out that it does. Read Manish's excellent post &lt;a href="https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/" rel="external"&gt;The Problem With Single-threaded Shared Mutability&lt;/a&gt; to know how.&lt;/p&gt;
&lt;p&gt;Do these rules remind you of something? To me they look exactly like a &lt;a href="https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock" rel="external"&gt;reader-writer&lt;/a&gt; lock. But that's where the similarities end. Unlike a reader-writer lock, the compiler enforces the reference rules at compile time. At runtime, a reference behaves exactly like a raw pointer; It is just a memory address. If you do want a construct with these same rules but at runtime, take a look at &lt;a href="https://doc.rust-lang.org/std/cell/struct.RefCell.html" rel="external"&gt;RefCell&lt;/a&gt;. If you are looking for an actual reader-writer lock, &lt;a href="https://doc.rust-lang.org/std/sync/struct.RwLock.html" rel="external"&gt;RwLock&lt;/a&gt; is your guy.&lt;/p&gt;
&lt;h2 id="implicit-dereferencing"&gt;Implicit dereferencing&lt;/h2&gt;
&lt;p&gt;Let's say you have a struct instance &lt;code&gt;s&lt;/code&gt; and a reference &lt;code&gt;r&lt;/code&gt; to that instance:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Int&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Int&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class="z-variable"&gt; i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 10&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;s&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get &lt;code&gt;s&lt;/code&gt;'s member &lt;code&gt;i&lt;/code&gt; you'd write:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, if you were accessing the member through the reference, you'd write:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But wait a minute, shouldn't you dereference  &lt;code&gt;r&lt;/code&gt;  before accessing the members? Like this:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;*&lt;/span&gt;&lt;span class="z-variable"&gt;r&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You could, but it is not necessary because Rust has spared us needless verbosity. The explicit dereference is not needed because the &lt;code&gt;.&lt;/code&gt; operator automatically dereferences the operand on its left. Not only that, the &lt;code&gt;.&lt;/code&gt; operator also dereferences its left operand as many times as needed to reach the member:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;s&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; rr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;s&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; rrr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;s&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; rr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; rrr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
The &lt;code&gt;.&lt;/code&gt; operator is not the only operator which automatically dereferences its operands. The comparison operators &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;&lt;=&lt;/code&gt; and &lt;code&gt;&gt;=&lt;/code&gt; also dereference operands on either side as needed.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;.&lt;/code&gt; operator also follows any &lt;a href="https://doc.rust-lang.org/std/ops/trait.Deref.html" rel="external"&gt;&lt;code&gt;Deref&lt;/code&gt; trait&lt;/a&gt; implementations on the left operand:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Inner&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Outer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    o&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Inner&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;impl&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Deref&lt;/span&gt;&lt;span class="z-keyword"&gt; for&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Outer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    type&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Target&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Inner&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;    fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; deref&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;self&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;Self&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Target&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-operator"&gt;        &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;self&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Outer&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class="z-variable"&gt; o&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Inner&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class="z-variable"&gt; i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 10&lt;/span&gt;&lt;span&gt; }};&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//s.i is transformed into s.deref().i by the compiler&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; k&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here the &lt;code&gt;s&lt;/code&gt; struct doesn't have a member &lt;code&gt;i&lt;/code&gt;. But this still compiles because the compiler transforms the expression &lt;code&gt;s.i&lt;/code&gt; into &lt;code&gt;s.deref().i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;One last trick up the &lt;code&gt;.&lt;/code&gt; operator's sleeve is that it automatically takes its left operand's reference if needed:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Int&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;impl&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Int&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;    fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;self&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;        println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;i is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; self&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span&gt;i);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Int&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class="z-variable"&gt; i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 10&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;s&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;print&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//calls the print method&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;print&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//so does this&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might think that you should call the &lt;code&gt;print&lt;/code&gt; method by creating a reference like this: &lt;code&gt;(&amp;amp;s).print()&lt;/code&gt;. This sounds sensible because the &lt;code&gt;print&lt;/code&gt; method takes a reference to &lt;code&gt;Int&lt;/code&gt; (via the &lt;code&gt;&amp;amp;self&lt;/code&gt; argument). But the shorter version &lt;code&gt;s.print()&lt;/code&gt; works just as well because the compiler implicitly creates a reference for you. Rust goes to great lengths to avoid even such small paper cuts. This shows the attention to detail that goes into making Rust more ergonomic.&lt;/p&gt;
&lt;h2 id="rust-references-vs-c-references"&gt;Rust references vs C++ references&lt;/h2&gt;
&lt;p&gt;In some ways Rust's references resemble pointers in C++. For example, the &lt;code&gt;&amp;amp;&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt; operators are very similar in the two languages. But these syntactical similarities are superficial. C++ pointers (even smart pointers) can't match Rust references' safety.&lt;/p&gt;
&lt;p&gt;References in C++, in contrast, are quite dissimilar to Rust references, even syntactically. Creating and dereferencing a reference is implicit in C++:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;r &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span&gt; i;&lt;/span&gt;&lt;span class="z-comment"&gt;//no &amp;amp; operator before i&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span&gt; j &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span&gt; r;&lt;/span&gt;&lt;span class="z-comment"&gt;//no * operator before r&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While in Rust these are explicit:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//note the &amp;amp; operator before i&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = *&lt;/span&gt;&lt;span class="z-variable"&gt;r&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//note the * operator before r&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another difference is that you can reassign a reference in Rust to another object:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;i&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//r is a reference to i&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 84&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;j&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//r is now a reference to j&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But you can't reseat a C++ reference:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span&gt; i &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;r &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span&gt; i;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span&gt; j &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 84&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//might look like r is reseated but&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//r still refers to i whose value is&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//updated to become 84&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;r &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span&gt; j;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apart from those differences, the two languages are similar in one aspect: references can't be null in either language.&lt;/p&gt;
&lt;p&gt;And that concludes a whirlwind tour of references in Rust.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, I covered an everyday usage of references in Rust. I showed how you can create shared and mutable references, and what rules govern their use. I also covered implicit dereferencing, which makes it easy to write clearer code. At last I compared Rust's references with C++ references, highlighting their superficial similarity. But pointed out that Rust's references are unmatched in safety, even by smart pointers in C++.&lt;/p&gt;</description><author/><pubDate>Thu, 03 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://hashrust.com/blog/references-in-rust/</guid></item><item><title>Comparing conversion at control and treatment sites</title><link>https://bytepawn.com/comparing-conversion-at-control-and-treatment-sites.html</link><description>&lt;p&gt;In real-life, non-digital situations, it's often not feasible to run true A/B tests. In such cases, we can compare before and after rollout conversions at a treatment site, while using a similar control site to measure and correct for seasonality. The post discusses how to compute increasingly correct p-values and bayesian probabilities in such scenarios.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Monte Carlo simulated control lifts" src="/images/ct_site_control_bayes.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Thu, 03 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/comparing-conversion-at-control-and-treatment-sites.html</guid></item><item><title>Journal Article: â€œThe Dordrecht Synod at 400: A Guide for the Church in Times of Crysisâ€</title><link>https://shadow.sombragris.org/?p=1105</link><description>The end of the year is nearing, and if it was hectic before, now we are reaching â€œcore meltdownâ€ status. However, in moments of rare respite within this race, I had time to write a small journal article for Espacio TeolÃ³gico, the theological journal of the Evangelical Faculty of Theology with the title stated above....</description><author>The Grey Shadow</author><pubDate>Wed, 02 Dec 2020 23:13:56 GMT</pubDate><guid isPermaLink="true">https://shadow.sombragris.org/?p=1105</guid></item><item><title>Migrating a Decade of Plaintext to Zettelkasten</title><link>http://evantravers.com/articles/2020/12/02/migrating-a-decade-of-plaintext-to-zettelkasten/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/12/graph.png" /&gt;&lt;/p&gt;&lt;div class="admonition tldr"&gt;
&lt;p&gt;This is going to be a code-heavy post. Use a repeatable script, take advantage of good programming practices to control the data going into your system and normalize it. Borrow liberally from me if that helps. 🙏_&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; I'm done with an eight month-long struggle to import all my previous plaintext notes into the Simple Markdown Zettelkasten format. It was not easy… but I thought I'd share some of the lessons that I learned and tricks that I used.&lt;/p&gt;
&lt;p&gt;I've been playing around with Zettelkasten style note-taking for a while now… and I'm pretty convinced that having everything in one place is the right path for me for now.&lt;/p&gt;
&lt;p&gt;Abbreviated version of my plaintext adventures to this point…&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Notepad documents from Windows and Ubuntu computers.&lt;/li&gt;
&lt;li&gt;Plain text on an Android Dev-1 phone… some terrible text editor.&lt;/li&gt;
&lt;li&gt;nvALT and Simplenote for &lt;em&gt;years&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Daily devotional note on iPhone using Byword that got &lt;em&gt;so&lt;/em&gt; long it routinely crashed my phone.&lt;/li&gt;
&lt;li&gt;Vimwiki diary and wiki for five years at my last job.&lt;/li&gt;
&lt;li&gt;Experimental zettelkasten using the MMD metadata.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There's some duplication, some craziness… and in the end it's &lt;strong&gt;2,068&lt;/strong&gt; files. Let's get to work.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#use-a-script" id="use-a-script"&gt;&lt;/a&gt;Use a script.&lt;/h2&gt;
&lt;p&gt;Just like any &lt;a href="http://evantravers.com/articles/2020/07/20/migrating-from-middleman-to-another-static-site/"&gt;large scale migration&lt;/a&gt;, using a script has &lt;em&gt;huge&lt;/em&gt; advantages over a series of manual &amp;quot;find and replace.&amp;quot; If you write it correctly, it's repeatable, and you'll get the same results each time, which means that if you get more data to migrate, or change your mind about a format... you change the script and run it again. I changed my mind half a dozen times while I was working on this script, and I was actively using the zettelkasten as I went.&lt;/p&gt;
&lt;p&gt;For instance... while working on the script, &lt;a href="http://evantravers.com/articles/2020/11/28/obsidian-fixed-unlinked-mentions-for-zk-ids/"&gt;Obsidian released the &lt;code&gt;aliases&lt;/code&gt; feature&lt;/a&gt; that lets backlinks work with Zettelkasten notes... I just &lt;a href="https://github.com/evantravers/plaintext-migration/commit/923e914e506f1e6de8502f28bd241a8a23124e64"&gt;adjusted my script&lt;/a&gt; and kept on rolling.&lt;/p&gt;
&lt;p&gt;(Also, running the script while having Obisdian open on graph mode made for a &lt;em&gt;really&lt;/em&gt; cool building animation that was definitely fun!)&lt;/p&gt;
&lt;p&gt;I did flex some computer science muscles, and &lt;a href="https://github.com/evantravers/plaintext-migration/blob/master/lib/zettel.rb"&gt;defined a class&lt;/a&gt; with a bunch of (inconsistently named) convenient methods and a standardized metadata format.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;require&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;Zettel&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;Zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;add_tag&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;knowledge&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set_meta&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;Zettelkasten is cool!&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;content&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;This note is useful, but short.&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set_meta&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;20201228369&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# this would render as:&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;
&lt;/div&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;title: 'Zettelkasten is cool!'
&lt;/div&gt;&lt;div class="line"&gt;tags: ['#knowledge']
&lt;/div&gt;&lt;div class="line"&gt;id: 20201228369
&lt;/div&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;This note is useful, but short.
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(using &lt;a href="https://github.com/evantravers/plaintext-migration/blob/master/lib/zettel.rb"&gt;zettel.rb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;The code is &lt;em&gt;not&lt;/em&gt; pretty... you can rip it off, but don't look too closely. 🤣&lt;/p&gt;
&lt;p&gt;Having a single code-path to make a zettel makes the next step easy...&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#adjust-your-script-per-source" id="adjust-your-script-per-source"&gt;&lt;/a&gt;Adjust your script per source.&lt;/h2&gt;
&lt;p&gt;I wrote a customized script per &amp;quot;source&amp;quot; that I listed in my history above. Each one has details specific to that system...&lt;/p&gt;
&lt;p&gt;My nvALT notes have titles in their filenames:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;title&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;basename&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;entry&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;.*&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/plaintext-migration/blob/ab76fd79e208d759d9b0f6df016e37e9ae769959/migrate.rb#L265"&gt;migrate.rb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;But, vimwiki diary entries have &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;s for some reason:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;title&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;content&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;scan&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;^&lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;+&lt;/span&gt; &lt;span&gt;.&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_s&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;gsub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;^&lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;+&lt;/span&gt; &lt;span&gt;/&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/plaintext-migration/blob/ab76fd79e208d759d9b0f6df016e37e9ae769959/migrate.rb#L222"&gt;migrate.rb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;This kind of flexibility is &lt;em&gt;super&lt;/em&gt; handy.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#guarantee-unique-ids" id="guarantee-unique-ids"&gt;&lt;/a&gt;Guarantee unique IDs.&lt;/h2&gt;
&lt;p&gt;This is critical... and hard. I used a &lt;code&gt;Set&lt;/code&gt; in Ruby like I have in the past, and it worked pretty well. I added a bunch of instrumentation to help me troubleshoot.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;class&lt;/span&gt; &lt;span&gt;Migrator&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;DST&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;../../wiki/&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;def&lt;/span&gt; &lt;span&gt;initialize&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;@unique_ids&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;Set&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;# [ ... ]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;def&lt;/span&gt; &lt;span&gt;ensure_uniqueness&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;@unique_ids&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;include?&lt;/span&gt; &lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;# we've got a dup&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;puts&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;🔴 Duplicate ID! &lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;:id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_i&lt;/span&gt; &lt;span&gt;+&lt;/span&gt; &lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;puts&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;trying &lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;self&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ensure_uniqueness&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;if&lt;/span&gt; &lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt; &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;12&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;puts&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt; 🟡 ID is too long! &lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;elsif&lt;/span&gt; &lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt; &lt;span&gt;&amp;lt;&lt;/span&gt; &lt;span&gt;12&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;puts&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt; 🟡 ID is too short! &lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;@unique_ids&lt;/span&gt; &lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/plaintext-migration/blob/ab76fd79e208d759d9b0f6df016e37e9ae769959/migrate.rb#L27-L43"&gt;migrate.rb&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#filter-tags-in-place" id="filter-tags-in-place"&gt;&lt;/a&gt;Filter tags in place.&lt;/h2&gt;
&lt;p&gt;I also used the &lt;code&gt;Zettel&lt;/code&gt; class to change and filter data going into the knowledge system graph:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;def&lt;/span&gt; &lt;span&gt;add_tag&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;tag&lt;/span&gt; &lt;span&gt;then&lt;/span&gt; &lt;span&gt;# not nil&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;tag&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;tag&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;.&lt;/span&gt;&lt;span&gt;gsub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;.&lt;/span&gt;&lt;span&gt;gsub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;!&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span&gt;# not just a number&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;tag&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;size&lt;/span&gt; &lt;span&gt;&amp;gt;&lt;/span&gt; &lt;span&gt;1&lt;/span&gt; &lt;span&gt;# not a single character&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;# blacklist&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;unless&lt;/span&gt; &lt;span&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;'&lt;/span&gt;&lt;span&gt;responsible&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;'&lt;/span&gt;&lt;span&gt;todos_archived&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;'&lt;/span&gt;&lt;span&gt;wizardsetupstep&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;'&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;'&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;'&lt;/span&gt;&lt;span&gt;create_tickets&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;# [ ... ]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;'&lt;/span&gt;&lt;span&gt;todo&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;include?&lt;/span&gt; &lt;span&gt;tag&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;tag&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;case&lt;/span&gt; &lt;span&gt;tag&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;when&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;pmux&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;            &lt;span&gt;'&lt;/span&gt;&lt;span&gt;ux&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;when&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;interview&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;            &lt;span&gt;'&lt;/span&gt;&lt;span&gt;career&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;when&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;project&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;            &lt;span&gt;'&lt;/span&gt;&lt;span&gt;projects&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;when&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;book&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;            &lt;span&gt;'&lt;/span&gt;&lt;span&gt;books&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;# [ ... ]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;            &lt;span&gt;tag&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;if&lt;/span&gt; &lt;span&gt;@meta&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;:tags&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;@meta&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;:tags&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;@meta&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;:tags&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;[&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/plaintext-migration/blob/master/lib/zettel.rb#L40-L152"&gt;zettel.rb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;By having a single &amp;quot;point of contact&amp;quot; with the &lt;code&gt;Zettel&lt;/code&gt; class, I was able to filter out or modify tags as they went into the final product.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#use-the-internet-to-supplement-metadata" id="use-the-internet-to-supplement-metadata"&gt;&lt;/a&gt;Use the internet to supplement metadata.&lt;/h2&gt;
&lt;p&gt;Probably the cleverest thing I did was to grab data from Google Books to add metadata to my booknotes.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;filename&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;basename&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;booknote&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;query&lt;/span&gt;  &lt;span&gt;=&lt;/span&gt; &lt;span&gt;filename&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;gsub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\.&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;title&lt;/span&gt;  &lt;span&gt;=&lt;/span&gt; &lt;span&gt;query&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;split&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; by &lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;first&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;strip&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;author&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;query&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;split&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt; by &lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;last&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;strip&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;books&lt;/span&gt; &lt;span&gt;=&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;JSON&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;parse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Net&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;HTTP&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get_response&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;URI&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;https://www.googleapis.com/books/v1/volumes?q=&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;URI&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;encode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;book&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;books&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;items&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;min_by&lt;/span&gt; &lt;span&gt;do&lt;/span&gt; &lt;span&gt;|&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;levenshtein_distance&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;volumeInfo&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;volumeInfo&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;:title&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;title&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;:subtitle&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;book&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;subtitle&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;:author&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;book&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;authors&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;# close enough to MLA&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;:publisher&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;book&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;publisher&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;zettel&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;:identifer&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;book&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;industryIdentifiers&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;identifier&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/plaintext-migration/blob/569e39bb075e969e55e263d993f76173f407a904/migrate.rb#L113-L139"&gt;migrate.rb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;I'm pretty proud of using using the &lt;a href="https://en.wikipedia.org/wiki/Levenshtein_distance"&gt;Levenshtein distance&lt;/a&gt; to choose the most likely search result. It works fine for me, and my &amp;quot;database&amp;quot; has a little more information.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#go-do-it" id="go-do-it"&gt;&lt;/a&gt;Go do it!&lt;/h2&gt;
&lt;p&gt;I'm &lt;em&gt;really&lt;/em&gt; happy that I'm done, and I've &lt;a href="https://github.com/evantravers/plaintext-migration/"&gt;got the script&lt;/a&gt; if I ever discover something isn't quite out of whack. I can now start using my knowledge system fearlessly... except I have to finish writing &lt;a href="https://github.com/evantravers/smz-drafts-actions"&gt;my Drafts actions&lt;/a&gt;.&lt;/p&gt;</description><author>trv.rs</author><pubDate>Wed, 02 Dec 2020 22:26:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/12/02/migrating-a-decade-of-plaintext-to-zettelkasten/</guid></item><item><title>What is more important, reading or job prospects?</title><link>https://stop.zona-m.net/2020/12/what-is-more-important-reading-or-job-prospects/</link><description>&lt;p&gt;Lies, damn lies, international agencies and priorities.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 02 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/what-is-more-important-reading-or-job-prospects/</guid></item><item><title>Log Pattern Recognition: LogMine</title><link>https://sayr.us/log-pattern-recognition/logmine/</link><description>When retrieving logs from an application, you are often looking for outliers (such as a unique error) or what pattern occurs the most. However, defining patterns manually is time-consuming and requires rigour across projects. In this series of blog posts, we are going to explore automated Log Pattern Recognition.</description><author>Sayr.us</author><pubDate>Wed, 02 Dec 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://sayr.us/log-pattern-recognition/logmine/</guid></item><item><title>Master of my domain</title><link>https://voussoir.net/writing/master_of_my_domain</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Master of my domain&lt;/h1&gt;&lt;ol id="table_of_contents"&gt;Table of contents&lt;li&gt;&lt;a href="#introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#prefer_portable_over_installers"&gt;Prefer portable over installers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#with_installers_always_choose_your_directory"&gt;With installers, always choose your directory&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#separate_subdirectories_for_each_version"&gt;Separate subdirectories for each version&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#use_latest_junctions_for_program_shortcuts"&gt;Use 'latest' junctions for program shortcuts&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#reserve_path_for_nobility_only"&gt;Reserve PATH for nobility only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#use_junctions_to_reign_in_appdata"&gt;Use junctions to reign in appdata&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#back_up_your_software"&gt;Back up your software&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#dealing_with_uncooperative_software"&gt;Dealing with uncooperative software&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;a class="header_anchor_link" href="#introduction"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This article is about how I manage the software on my computer to stay organized and in control. I've developed these habits over years of dealing with software installations that each want to behave a little differently and go their own way. But I'm the master of my domain — queen of my castle, if you will — and I run the show around here. So here's how I put software in its place:&lt;/p&gt;
&lt;h2 id="prefer_portable_over_installers"&gt;Prefer portable over installers&lt;a class="header_anchor_link" href="#prefer_portable_over_installers"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If a software download page offers a choice between "portable"/.zip/.7z downloads and "setup"/.exe/.msi downloads, always pick the portable option. The reason they're called portable is because you can unzip them to a flash drive and just run the .exe on any computer you plug it in to, so that you don't have to actually install the program on every computer you use.&lt;/p&gt;
&lt;p&gt;As a result, a well-behaved portable program will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Store configuration files in the same folder as the .exe, instead of the computer's central registry or other paths.&lt;/li&gt;
&lt;li&gt;Not rely on files outside of the program's folder — the whole thing is self-contained.&lt;/li&gt;
&lt;li&gt;Not leave much, or anything, behind on the main computer — usually just some log files in appdata.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These properties are what I want from &lt;em&gt;all&lt;/em&gt; software! The benefits even for non-portable use are many. Portable software makes it easy to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;find and modify config files by hand — no hunting for registry keys or configuration paths.&lt;/li&gt;
&lt;li&gt;uninstall — just delete the folder.&lt;/li&gt;
&lt;li&gt;run multiple simultaneous instances of the program, even of different versions or with different configurations.&lt;/li&gt;
&lt;li&gt;sync with &lt;a href="https://syncthing.net/"&gt;Syncthing&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;back up and restore — just zip the folder. No need to worry about important files hiding anywhere else.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is even a website, &lt;a href="https://portableapps.com/apps"&gt;portableapps.com&lt;/a&gt;, dedicated to promoting portable software and preparing portable-ized versions of software that isn't normally available as portable. In the second case, however, you rely on portableapps being trustworthy.&lt;/p&gt;
&lt;p&gt;Ostensibly, the benefits of installers over portables is they can set file associations, integrate with the right-click menu, and so forth. Well, I can handle file associations myself (&lt;code&gt;HKCR\.ext\shell\open\command\(Default)&lt;/code&gt;), and even the most well-meaning context menu items really just contribute to an ever-growing list of junk so I'd rather not have those anyway. I can write those myself, too, if I really need them (&lt;code&gt;HKCR\.ext\shell\mycommandname\command\(Default)&lt;/code&gt;). Then I'll know exactly where they're defined should I ever decide to remove them. This is in contrast to properties set by installers which are always in crazy places and mapped through GUIDs and whatnot.&lt;/p&gt;
&lt;h2 id="with_installers_always_choose_your_directory"&gt;With installers, always choose your directory&lt;a class="header_anchor_link" href="#with_installers_always_choose_your_directory"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some software isn't available as a portable download, so you've got to suffer through the installer. If it gives you the opportunity to change the install directory, always take that chance. Software installers on Windows have a nasty habit of scattering themselves throughout &lt;code&gt;C:\Program Files&lt;/code&gt;, &lt;code&gt;C:\Program Files (x86)&lt;/code&gt;, &lt;code&gt;C:\ProgramData&lt;/code&gt;, and &lt;code&gt;%appdata%&lt;/code&gt;. I'm king of this county and I hereby declare that I'm not gonna go on a wild goose chase looking for &lt;strong&gt;my&lt;/strong&gt; software on &lt;strong&gt;my&lt;/strong&gt; computer — they'll go where I tell them to go.&lt;/p&gt;
&lt;p&gt;If I have to install a program from an installer, I'll usually try to zip up the resulting folder and keep that as my own portable copy for later. A lot of installers are nothing more than extractors, so as long as the program doesn't rely on some system changes during install, keeping the portable copy works fine (besides, system changes are often anti-user anyway). And I really don't need an installer acting as a glorified file extractor, I can do that myself from a zip. Unfortunately, some software doesn't work after re-extracting it, and I do have to keep the installer.&lt;/p&gt;
&lt;p&gt;Some software authors take this &lt;a href="https://en.wikipedia.org/wiki/L%C3%A8se-majest%C3%A9"&gt;Lèse-majesté&lt;/a&gt; a step further by not even offering a chance to change the install directory. There is no justifiable reason for this. I operate on a two or three strikes policy depending on how important the software is: I expect simply moving the installed folder, possibly leaving a junction in its place, to work properly. But now that the program is on my bad side it takes a lot less for me to uninstall.&lt;/p&gt;
&lt;p&gt;The worst offenders are the likes of Adobe. A search on my computer right now shows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Program Files\Adobe
C:\Program Files\Common Files\Adobe
C:\Program Files (x86)\Adobe
C:\Program Files (x86)\Common Files\Adobe
C:\ProgramData\Adobe
C:\Users\All Users\Adobe
C:\Users\voussoir\AppData\Local\Adobe
C:\Users\voussoir\AppData\LocalLow\Adobe
C:\Users\voussoir\AppData\Roaming\Adobe
C:\Users\voussoir\AppData\Roaming\Adobe\Adobe
C:\Users\voussoir\Documents\Adobe
C:\Users\Public\Documents\Adobe&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You're not the lord of this manor, Adobe!&lt;/p&gt;
&lt;h2 id="separate_subdirectories_for_each_version"&gt;Separate subdirectories for each version&lt;a class="header_anchor_link" href="#separate_subdirectories_for_each_version"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My Software folder looks like this, with a subdirectory for each version of every program:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;D:\Software\Git\2.25.0
D:\Software\Inkscape\0.92.3
D:\Software\QuiteRSS\0.19.4
D:\Software\WinSCP\5.17.8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, I can maintain multiple versions of the software at the same time, which makes updating totally stress-free because I can stick with the old version as long as I want if the update has a regression. Contrast that with an in-place updater where you might regret the update after finding a new bug. My Android phone has several apps that I simply don't bother to update because I don't want to deal with reverting the .apks by hand through adb should I regret the update &lt;a class="footnote_link" href="#footnote_text_1" id="footnote_link_1" title="[1] F-Droid offers historical apks for download so I've got no concern there, but Google doesn't. Raccoon can help you download present-day apks from Google for your future benefit, though."&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The only problem occurs when multiple versions expect &lt;code&gt;%appdata%\Program&lt;/code&gt; to belong to themselves alone. If there is no commandline switch to change the appdata directory, I am somewhat out of luck on that point. One thing I had never though of until now is modifying the environment variables before running the program to manipulate &lt;code&gt;%appdata%&lt;/code&gt; to a separate directory, similar to &lt;a href="https://superuser.com/q/424001"&gt;this SE thread&lt;/a&gt;. However, that solution didn't work for me, but I'll keep an eye out for something similar. This seems fragile since the program might (wrongfully) construct appdata from &lt;code&gt;%userprofile%\appdata\roaming&lt;/code&gt;, or cache the value of &lt;code&gt;%appdata%&lt;/code&gt; during install to a registry key, etc.&lt;/p&gt;
&lt;p&gt;&lt;a class="footnote_text" href="#footnote_link_1" id="footnote_text_1"&gt;[1]&lt;/a&gt; &lt;a href="https://f-droid.org/"&gt;F-Droid&lt;/a&gt; offers historical apks for download so I've got no concern there, but Google doesn't. &lt;a href="https://raccoon.onyxbits.de/"&gt;Raccoon&lt;/a&gt; can help you download present-day apks from Google for your future benefit, though.&lt;/p&gt;
&lt;h2 id="use_latest_junctions_for_program_shortcuts"&gt;Use 'latest' junctions for program shortcuts&lt;a class="header_anchor_link" href="#use_latest_junctions_for_program_shortcuts"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here's a fantastic trick I started using just recently. Since all my software is separated by version number, when I download the newest version of a program, all of my shortcuts or scripts which call that program will still be using the old path, and I'd have to update them manually. I came up with this solution: just &lt;code&gt;mklink /j __latest X.Y.Z&lt;/code&gt; inside the program folder, and have all your shortcuts point to the exe inside &lt;code&gt;__latest&lt;/code&gt;. Since it's a filesystem junction, it will behave transparently to any calling program. In the past I had tried to achieve this by making a single shorcut and pointing any future shortcuts to that one, but that didn't work because when you assign a shortcut to a shortcut it resolves to the real path and saves that path forever instead of folowing the link every time.&lt;/p&gt;
&lt;p&gt;When I download a new version of a program, I just delete that junction and make it again with the new version number, and all linked paths work as normal, as long as the name of the .exe itself hasn't changed.&lt;/p&gt;
&lt;p&gt;I don't like filling up my desktop or start menu with shortcuts, so I wrote &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/PGUI.pyw"&gt;PGUI&lt;/a&gt; which acts as a launcher for any .lnk files located inside my PGUI folder. Each of these shortcuts actually point to the &lt;code&gt;__latest\program.exe&lt;/code&gt; path. As a bonus, my PGUI folder is one of the few folders to enjoy the honor of being on my PATH, which means I can just start them from the command line or Win+R — that's all possible without a gui launcher of course, but it's a great symbiosis.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/master_of_my_domain/latest_junction_1.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/master_of_my_domain/latest_junction_2.png" /&gt;&lt;/p&gt;
&lt;h2 id="reserve_path_for_nobility_only"&gt;Reserve PATH for nobility only&lt;a class="header_anchor_link" href="#reserve_path_for_nobility_only"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The entire contents of my PATH are:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;C:\Windows
C:\Windows\system32
D:\cmd
D:\git\cmd
D:\git\cmd\PGUI&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two folders for system executables, and three folders owned by &lt;strong&gt;me&lt;/strong&gt;, because this is a monarchy and I'll appoint whoever I want. No application, under any circumstance, gets to put its own install directory on the PATH. If I need global commandline access to that program, I'll put an .lnk or symlink in \cmd.&lt;/p&gt;
&lt;p&gt;At one point, I had some issues with programs that I wanted to subprocess from Python. &lt;code&gt;subprocess.run(shutil.which('ffmpeg'))&lt;/code&gt; was breaking because &lt;code&gt;subprocess.run&lt;/code&gt; wants to receive executable files and of course the only thing on my path was an .lnk. So, I wrote &lt;a href="https://git.voussoir.net/voussoir/voussoirkit/src/branch/master/voussoirkit/winwhich.py"&gt;winwhich.py&lt;/a&gt; and now that problem is solved. The software bends to my will, not the other way around.&lt;/p&gt;
&lt;h2 id="use_junctions_to_reign_in_appdata"&gt;Use junctions to reign in appdata&lt;a class="header_anchor_link" href="#use_junctions_to_reign_in_appdata"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I've mentioned that even portable software has a tendency to leave a few traces in &lt;code&gt;%appdata%&lt;/code&gt;. Sometimes it's inconsequential stuff like log files, but sometimes it's config, and that I want to keep in the program folder.&lt;/p&gt;
&lt;p&gt;The solution here is in three steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Move &lt;code&gt;%appdata%\Program&lt;/code&gt; into &lt;code&gt;D:\Software\Program&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Rename that folder to e.g. "appdata" so you don't have Program\Program like some kind of Adobe.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mklink /j "%appdata%\Program" appdata&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now you are closer to portable enlightenment and can zip up the program folder without losing your appdata files.&lt;/p&gt;
&lt;h2 id="back_up_your_software"&gt;Back up your software&lt;a class="header_anchor_link" href="#back_up_your_software"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although I run regular backups, I don't include my whole Software folder in the backup routine because I already keep all the portable zips and installers backed up separately. The only items of value in the install directory are config files, most of which are not highly personalized and I don't mind losing either.&lt;/p&gt;
&lt;p&gt;But, there are a few programs which I've heavily configured and I'd hate to start from scratch with them. Sublime, Putty, and WinSCP for example. For those I wrote a wrapper around WinRAR, &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/rarpar.py"&gt;rarpar.py&lt;/a&gt;, which I use to create highly compressed archives with a datestamp in the filename. Because the &lt;code&gt;__latest&lt;/code&gt; files will be included in duplicate, you might think it'd waste a lot of space, but with a Solid archive and a very high dictionary size, that duplication causes no extra disk usage.&lt;/p&gt;
&lt;h2 id="dealing_with_uncooperative_software"&gt;Dealing with uncooperative software&lt;a class="header_anchor_link" href="#dealing_with_uncooperative_software"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you find that one of your programs isn't cooperating with the above techniques, consider these more delicate approaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Say in a loud, commanding, and controlled voice, "&lt;strong&gt;&lt;em&gt;YOU WORK FOR ME&lt;/em&gt;&lt;/strong&gt;" (requires microphone).&lt;/li&gt;
&lt;li&gt;Spawn several child processes. Kill them.&lt;/li&gt;
&lt;li&gt;Reduce process priority to Below Normal and insist, "You can have your cycles back after you've cleaned up your act".&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/master_of_my_domain/master_of_my_domain.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/3475cb0abf63172e6392487ffaf41755f71a18e3"&gt;&lt;time datetime="2023-09-18T21:01:09-07:00"&gt;2023-09-18&lt;/time&gt; Replace github links with git.voussoir.net.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/0f40c9dce17921ce4d8143f72ab16230254a9408"&gt;&lt;time datetime="2021-10-12T19:06:40-07:00"&gt;2021-10-12&lt;/time&gt; Replace allcaps with bold, remove backup_folder.py link.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/7aef0a00716f251e4025944778ae2fb727f5d5ef"&gt;&lt;time datetime="2021-10-01T23:12:14-07:00"&gt;2021-10-01&lt;/time&gt; Simplify wording of bulleted list.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/0ec6a69e432caf2b24c5a79563548dd53379df1e"&gt;&lt;time datetime="2021-08-07T17:49:41-07:00"&gt;2021-08-07&lt;/time&gt; Replace "back up with confidence" with "back up and restore".&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/9cce9f9ef055a5e268a9b913871ff8d0473cf3eb"&gt;&lt;time datetime="2021-06-07T19:08:19-07:00"&gt;2021-06-07&lt;/time&gt; Move S3 images to my domain.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/fc9aaf092fa367968b206069620bdcc6e91adc92"&gt;&lt;time datetime="2021-01-02T23:40:13-08:00"&gt;2021-01-02&lt;/time&gt; Fix typo "instead of computer's".&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/9fa4a251759f049e1fe5e09dd7948f9872c71b2e"&gt;&lt;time datetime="2020-12-02T00:15:01-08:00"&gt;2020-12-02&lt;/time&gt; Add master_of_my_domain.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Wed, 02 Dec 2020 10:15:01 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/master_of_my_domain</guid></item><item><title>2020–12–02: Fixing fallout from the new WiFi driver</title><link>https://xnux.eu/log/#027</link><author>megi's PinePhone Development Log</author><pubDate>Wed, 02 Dec 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#027</guid></item><item><title>RSS Feed written in HTML + JavaScript</title><link>https://web.navan.dev/posts/2020-12-1-HTML-JS-RSS-Feed.html</link><description>Short code-snippet for an RSS feed, written in HTML and JavaScript</description><author>Navan's Archive</author><pubDate>Tue, 01 Dec 2020 22:52:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-12-1-HTML-JS-RSS-Feed.html</guid></item><item><title>Please promote ODF with these posters!</title><link>https://stop.zona-m.net/2020/12/please-promote-odf-with-these-posters/</link><description>&lt;p&gt;You really have no more excuse to not use and PROMOTE ODF.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 01 Dec 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/12/please-promote-odf-with-these-posters/</guid></item><item><title>A complete guide to preprocess Instagram post data</title><link>https://geo.rocks/post/preprocessing-instagram-data/</link><description>&lt;p&gt;&lt;img alt="Quick visualization of location ID coordinates in QGIS" src="https://geo.rocks/img/bonn-locations.jpg" title="Quick visualization of location ID coordinates in QGIS" /&gt;
Scripts and tricks to preprocess Instagram data mined with Fast-Instagram-Scraper. Get it on a map!&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Tue, 01 Dec 2020 18:14:42 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/preprocessing-instagram-data/</guid></item><item><title>AoC day1</title><link>https://evilcookie.de/aoc-day1.html</link><description/><author>blog</author><pubDate>Tue, 01 Dec 2020 14:03:45 GMT</pubDate><guid isPermaLink="true">https://evilcookie.de/aoc-day1.html</guid></item><item><title>Guidelines for Deploying React</title><link>https://maxrozen.com/guidelines-for-deploying-react</link><description>These days there are a heck of a lot of options for deploying React. It can be a bit overwhelming. This article simplifies your choices.</description><author>Max Rozen</author><pubDate>Tue, 01 Dec 2020 11:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/guidelines-for-deploying-react</guid></item><item><title>How to tag data in Redis</title><link>https://www.alexanderlolis.com/how-to-tag-data-in-redis</link><description>What are Sets and how to use them as secondary indexes</description><author>Alexander's Blog Blog</author><pubDate>Tue, 01 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.alexanderlolis.com/how-to-tag-data-in-redis</guid></item><item><title>Direct democracy features of the Swiss kind</title><link>https://nutcroft.mataroa.blog/blog/direct-democracy-features-of-the-swiss-kind/</link><description>&lt;p&gt;There is some colloquy in political discussions that Switzerland has the best kind of democracy.&lt;/p&gt;
&lt;h2 id="introducing-the-confederation"&gt;Introducing the Confederation&lt;/h2&gt;
&lt;p&gt;Officially the Swiss &lt;em&gt;Confederation&lt;/em&gt;, Switzerland is a federal democracy, theoretically, resembling that of the United States&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Instead of states, there are cantons. However, Switzerland, as a semi-direct democracy, also has a lot of mechanisms that enable direct democracy. Even though I have often invoked the Swiss democracy as worth copying, I was in the dark—until recently—about specific details of how the political system works. Except, only, for the famous high frequency of their referenda.&lt;/p&gt;
&lt;p&gt;Three of the main voting mechanisms in Switzerland that enable directness are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mandatory referenda, for important changes, eg. in the constitution.&lt;/li&gt;
&lt;li&gt;Legislative referenda, optional, for changing laws passed by the parliament.&lt;/li&gt;
&lt;li&gt;Popular initiatives, which are initiated by the people to change the constitution in any way.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It would be great for other western countries to have a higher quality democracy, like the Swiss. But, it seems infeasible. Something that would require an unimaginable amount of change both in policies and in perception of politics by the people.&lt;/p&gt;
&lt;h2 id="assumptions"&gt;Assumptions&lt;/h2&gt;
&lt;p&gt;I’d love to try it, though. Nowadays, I'm under the impression that the vast majority of the world’s democracies are spiralling down rather swiftly. But, technology is booming, so what’s wrong? It would seem it's not a case of humanity being out of luck and experiencing a one-off event. Rather, something is wrong at a foundational level. Is technology not enough to solve all of humanities problems?&lt;/p&gt;
&lt;p&gt;In addition, by enabling more directness in a democracy, the power is more divided among the people, which—in case of dangerous people—makes direct democracy more dangerous, not more desirable!&lt;/p&gt;
&lt;p&gt;Both the importance of technology and the case of freedom versus safety are philosophical discussions out of the scope of this text. Thus, let’s assume:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Technology is of supreme importance.&lt;/li&gt;
&lt;li&gt;We prefer not to distribute power if that means people with an education of lesser quality get it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="educating-voters"&gt;Educating voters&lt;/h2&gt;
&lt;p&gt;Under these assumptions, education and knowledge are the foundational stones of direct democracy. For the common people to decide about policies, they need to know about policies. Are Swiss people more educated than, say, other western countries? Even so, how much more educated?&lt;/p&gt;
&lt;p&gt;I would guess not by that much, that it would justify a complete overturn of who holds the political power. To counter for the lack of education and specific knowledge about each referendum, in Switzerland, each ballot is accompanied with a handbook. The handbook explains in great detail what each vote means. For instance, what cost would each option incur, how would it be covered, what is the recommended vote by each level of authority (canton, parliament, municipality), what is the minority’s opinion and, of course, why.&lt;/p&gt;
&lt;p&gt;An acceptable way to educate the public on what they vote for, but also an imperfect way. It raises many questions. Namely one, how many people do actually bother to vote, given the handbook's overhead? &lt;a href="https://en.wikipedia.org/wiki/Voting_in_Switzerland"&gt;According to Wikipedia&lt;/a&gt;, the number has varied since the 1970s between 42% and 50%, with few extreme cases going over 60%, such as the matter of Switzerland joining the EU.&lt;/p&gt;
&lt;p&gt;Those numbers do sound close to an average election turnout in many western countries, &lt;a href="https://en.wikipedia.org/wiki/Voter_turnout#Trends_of_decreasing_turnout_since_the_1980s"&gt;if not worse&lt;/a&gt;. Which raises another interesting question: how do they manage to maintain their direct democracy quality (and do they?) given these meagre voter turnouts&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;?&lt;/p&gt;
&lt;h2 id="other-features-of-the-system"&gt;Other features of the system&lt;/h2&gt;
&lt;p&gt;If we examine the example of a Swiss citizen, who has been living in Zurich since 2000, they have had the opportunity to vote in 548 referenda in the last 21 years. With an average of ~1 referenda every two weeks, that sounds unreal. How could this work?&lt;/p&gt;
&lt;p&gt;They vote in bulk. They may hold bulk referenda four times every year, voting for ~6 issues each time. It makes one wonder how many tricks like that they have devised in order to scale direct democracy to 8+ million people&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Among other interesting properties of the Swiss political system is the fact that Switzerland has no constitutional court. The power of interpreting the constitution lies again only with the people.&lt;/p&gt;
&lt;p&gt;But, the most interesting one is probably that there is no single human that is the face and embodies the represented power of the Swiss government. There is a Federal Council that is represented by seven members, each having one vote. There is also a Federal Chancellor, but they are not important at all as they hold no vote of those seven.&lt;/p&gt;
&lt;p&gt;I'm inclined to argue that this property of dividing a country’s top executive by seven, doesn't even need that much of a perception shift to happen—it's only a policy to be voted for, with no (?) negative side effects yet with the distribution-of-power positive main effect.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As I'm reading more and more about all the various mechanics the Swiss have, each one solving and improving on the drawback of the previous, my realisation is this: there is no perfect system, of course; the decision is which fundamental ideas we want to adopt and build upon.&lt;/p&gt;
&lt;p&gt;At the end of the day, the foremost inquiry is: do we want to try something new or is this indeed &lt;a href="https://en.wikipedia.org/wiki/The_End_of_History_and_the_Last_Man"&gt;the end of history&lt;/a&gt;? I understand the need to remain with the devil we know, yet, I'm excited to discover the one we don't. Only because the fundamental idea of power distribution sounds better than the lack of it.&lt;/p&gt;
&lt;h2 id="epilogue"&gt;Epilogue&lt;/h2&gt;
&lt;p&gt;Martin Sústrik's blog posts at &lt;a href="https://250bpm.com/"&gt;250bpm&lt;/a&gt; is where most of the above findings were found. They were extremely interesting to read, and I recommend them especially for the parts that I did not mention. Examples include how the number of popular initiatives soared in the 1970s (before that they hadn't figured out how to do them productively!), how they dealt and are dealing with their serious problem of immigration, how to face dangerous referenda (read Brexit), and one that could be a book of its own: concordance versus competitive democracy (it's in Part 3).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://250bpm.com/blog:161/"&gt;Swiss Political System: More than You ever Wanted to Know (I.)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://250bpm.com/blog:162/"&gt;Swiss Political System: More than You ever Wanted to Know (II.)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://250bpm.com/blog:163/"&gt;Swiss Political System: More than You ever Wanted to Know (III.)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other references include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;antenna.nl: &lt;a href="http://www.athene.antenna.nl/MEDIATHEEK/KOBACH-1.html"&gt;The history of direct democracy in Switzerland&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;houseofswitzerland.org: &lt;a href="https://www.houseofswitzerland.org/swissstories/history/way-modern-direct-democracy-switzerland"&gt;The way to modern direct democracy in Switzerland&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;admin.ch: &lt;a href="https://www.admin.ch/gov/en/start/documentation/media-releases.msg-id-5829.html"&gt;Switzerland and its Democracy – a view from inside&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;SWI swissinfo.ch: &lt;a href="https://www.swissinfo.ch/eng/directdemocracy/swiss-us-democracy_standing-at-the-forefront-of-swiss-federalism-were-the-iroquois/43645216"&gt;Swiss and US democracy: twins separated at birth?&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;In the last paragraph of &lt;a href="https://250bpm.com/blog:163/"&gt;Part 3&lt;/a&gt;, Martin reveals something interesting: &lt;em&gt;"It turns out that about a quarter votes almost every time, a quarter almost never, and the rest votes occasionally. That being said, 90% of people have voted at least once in the past five years. This suggests that people vote selectively."&lt;/em&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Here, one could argue, they have actually scaled to 5.2m people (rather than 8.5m), because that's the amount of Swiss people eligible to vote. Which is yet another interesting problem: how much of a democracy is it, if only ~61% of the population take part? &lt;em&gt;N.B. that in addition to expats, I have included ignorant children in this number, too.&lt;/em&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>nutcroft</author><pubDate>Tue, 01 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/direct-democracy-features-of-the-swiss-kind/</guid></item><item><title>My stack will outlive yours</title><link>https://blog.steren.fr/2020/my-stack-will-outlive-yours/</link><author>Steren's essays</author><pubDate>Tue, 01 Dec 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.steren.fr/2020/my-stack-will-outlive-yours/</guid></item><item><title>Using Topology to Classify Labelled Graphs</title><link>https://bastian.rieck.me/blog/2020/topology_graphs/</link><description>&lt;p&gt;I have written at lengths about certain aspects of topological data
analysis, but I have neglected to discuss one of its main applications,
i.e. the classification of graphs. In this post, I will therefore take
you on a quick tour of our ICML paper &lt;a href="http://proceedings.mlr.press/v97/rieck19a/rieck19a.pdf"&gt;A Persistent Weisfeiler&amp;ndash;Lehman Procedure for Graph Classification&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let us assume that we are given a graph with node label information. The
graph could, for instance, be a molecule, whose nodes are atoms such as
carbon or oxygen, and whose edges indicate chemical bonds. The goal
could now be to classify a given molecule into a set of classes, such as
&amp;rsquo;toxic&amp;rsquo;, &amp;lsquo;carcinogen&amp;rsquo;, etc. How can we achieve such a classification?
One of the simplest techniques dates back to the 1960s and involves
calculating an &lt;em&gt;iterative fingerprint&lt;/em&gt; of the graph! This procedure was
suggested by &lt;a href="https://en.wikipedia.org/wiki/Boris_Weisfeiler"&gt;Boris Weisfeiler&lt;/a&gt;
and Andrei Lehman (sometimes also transliterated as &amp;lsquo;Leman&amp;rsquo;) in
their seminal article &lt;a href="https://www.iti.zcu.cz/wl2018/pdf/wl_paper_translation.pdf"&gt;The reduction of a graph to canonical form and the
algebra which appears therein&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At its core, the algorithm is an iteration scheme that works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For a node $v$, collect its label and the labels of adjacent nodes in
a multiset.&lt;/li&gt;
&lt;li&gt;Assign this multiset a new label by hashing it&amp;mdash;with the proviso
that the hashing function is &lt;a href="https://en.wikipedia.org/wiki/Perfect_hash_function"&gt;&lt;em&gt;perfect&lt;/em&gt;&lt;/a&gt;, i.e.
it maps distinct labels to distinct values with no collisions.&lt;/li&gt;
&lt;li&gt;Replace all node labels by their multiset hashes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Intuitively, each step of the algorithm accumulates more information
from nodes that are further removed from the current node. The hashed
multiset label is thus an expression of the neighbourhood around
a node&amp;mdash;and after a sufficiently large number of iterations, the
hashed labels will not change any more.&lt;/p&gt;
&lt;p&gt;For example, suppose you are dealing with this simple graph (to
prevent confusion of node labels and node IDs, I used &lt;em&gt;colours&lt;/em&gt; to
indicate node labels in this example):&lt;/p&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Weisfeiler--Lehman example graph" height="128" src="https://bastian.rieck.me/images/weisfeiler_lehman_graph.svg" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;Tabulating the neighbourhood of each node then results in the following
table:&lt;/p&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Weisfeiler--Lehman multiset example (before hashing)" height="128" src="https://bastian.rieck.me/images/weisfeiler_lehman_table_1.svg" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;Now for the hashing step. In this example, &lt;em&gt;perfect hashing&lt;/em&gt; means
choosing a set of colours that is distinct for every distinct
combination of neighbourhood labels and vertex labels:&lt;/p&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Weisfeiler--Lehman multiset example (after hashing)" height="128" src="https://bastian.rieck.me/images/weisfeiler_lehman_table_2.svg" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;Notice how nodes A, B, and G are hashed to the same colour&amp;mdash;because
in the first iteration of the algorithm, they cannot be distinguished.
How can we use the information about the hashed labels in a subsequent
comparison task? The answer is lies in &lt;em&gt;counting&lt;/em&gt; them in a histogram
vector, which is indexed by the unique labels&amp;mdash;this is where our
requirement of the perfect hashing function is helpful. For the
previously-shown graph, it looks like this:&lt;/p&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Weisfeiler--Lehman subtree feature vector" height="128" src="https://bastian.rieck.me/images/weisfeiler_lehman_feature_vector.svg" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;fingerprint&lt;/em&gt; of this graph, according to the first iteration of the
Weisfeiler&amp;ndash;Lehman scheme is therefore $(3, 1, 2, 1)$. Further iterations
just make the feature vector longer (technically, the initial
labels already give rise to a feature vector of counts). This procedure
can now be repeated for higher-order iterations and the resulting
feature vectors can be compared across graphs by evaluating, for
example, their dot product. More formalisations of this idea have
resulted in the very successful &lt;a href="https://www.jmlr.org/papers/volume12/shervashidze11a/shervashidze11a.pdf"&gt;Weisfeiler&amp;ndash;Lehman Graph
Kernels&lt;/a&gt;
publication. This method arguably constitutes the basis for graph neural
networks&amp;mdash;in fact, these networks can be seen as a parametrised
version of the Weisfeiler&amp;ndash;Lehman iteration scheme. But I digress&amp;mdash;if
you are interested in these aspects, please read &lt;a href="https://towardsdatascience.com/beyond-weisfeiler-lehman-approximate-isomorphisms-and-metric-embeddings-f7b816b75751"&gt;Michael Bronstein&amp;rsquo;s
article on going beyond graph
isomorphism&lt;/a&gt;
for more details.&lt;/p&gt;
&lt;p&gt;Now, despite its great practical utility, this feature vector is lacking
some &lt;em&gt;structural&lt;/em&gt; information about the graph. It does not know whether
a certain label contributes much to the topological structure of
a graph&amp;mdash;such as a ring of carbon atoms would in molecule&amp;mdash;or not. To
this end, we introduced a notion of topological relevance for each node
label! Briefly put, we first developed a distance metric that would
permit us turn any &lt;em&gt;labelled&lt;/em&gt; graph into a &lt;em&gt;weighted&lt;/em&gt; graph. We then
calculate a persistence barcode, a topological descriptor of the graph.
This descriptor assesses the relevance of a topological feature created
by some node label. We use the topological relevance of each feature as
an additional &lt;em&gt;weight&lt;/em&gt; for the previously-shown feature vector. In
essence, labels that contribute a large amount of topological structure
in a graph are assigned a higher weight than labels that only contribute
a meagre amount!&lt;/p&gt;
&lt;p&gt;Here is a graphical depiction of our process:&lt;/p&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Persistent Weisfeiler--Lehman pipeline" height="128" src="https://bastian.rieck.me/images/p_wl_pipeline.svg" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;If you want to brush up your understanding of the barcode calculation,
head on over to &lt;a href="https://christian.bock.ml"&gt;Christian&amp;rsquo;s website&lt;/a&gt;; he has
an &lt;a href="https://christian.bock.ml/posts/persistent_homology"&gt;excellent article on persistent
homology&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The neat thing about our approach is that we can easily integrate
information about &lt;em&gt;cycles&lt;/em&gt; into the feature vector&amp;mdash;this is
a functionality that the original Weisfeiler&amp;ndash;Lehman Graph Kernels
Framework lacks. Moreover, these cycles turn out to be crucial in
improving classification performance&amp;mdash;we get an increase of more than
3% in classification accuracy by considering them in some data sets!&lt;/p&gt;
&lt;p&gt;If this has whet your appetite, I invite you to &lt;a href="http://proceedings.mlr.press/v97/rieck19a/rieck19a.pdf"&gt;read our
paper&lt;/a&gt; or &lt;a href="https://github.com/BorgwardtLab/P-WL"&gt;take
a look at the code&lt;/a&gt;. If you want
to learn more about graph classification using graph kernels, take
a look at our &lt;a href="https://arxiv.org/abs/2011.03854"&gt;recent survey on graph kernels&lt;/a&gt;,
which will hopefully be officially announced in time for NeurIPS 2020.
In the best tradition of Fermat, I would very much like to cover the
content of the survey here, but this blog is too small to contain all of
it&amp;mdash;maybe for a subsequent post?&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Mon, 30 Nov 2020 22:00:00 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/topology_graphs/</guid></item><item><title>Books and Links: November</title><link>http://evantravers.com/articles/2020/11/30/books-and-links-november/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/office.jpg" /&gt;&lt;/p&gt;&lt;p&gt;Hard to believe that tomorrow starts December of 2020. The years are short and the days are long.&lt;/p&gt;
&lt;p&gt;Grateful to be chasing my toddler around the house with matching magnifying glasses, solving &amp;quot;mysteries&amp;quot; that I've scrawled on scrap paper. God is good.&lt;/p&gt;
&lt;p&gt;I wrote a fair amount of code this month, mostly around the simple markdown zettelkasten work that I &lt;em&gt;finally&lt;/em&gt; unblocked.&lt;/p&gt;
&lt;p&gt;&lt;img alt="contributions on github" src="https://images.evantravers.com/articles/2020/11/contributions.png" /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;p&gt;I actually read some books this month! Still trying to get my booknotes straightened out, but this month's progress emboldened me.&lt;/p&gt;
&lt;p&gt;On deck: Design Systems, Knowing God, The 12 Week Year, and maybe that new Brandon Sanderson action.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#whiskey-tango-foxtrot-by-lynne-m-black-jr" id="whiskey-tango-foxtrot-by-lynne-m-black-jr"&gt;&lt;/a&gt;Whiskey Tango Foxtrot by Lynne M. Black, Jr.&lt;/h3&gt;
&lt;p&gt;Content warning: Some language and discussion of the sins of soldiers.&lt;/p&gt;
&lt;p&gt;I heard about this on a podcast... and it's a wild ride. It's very hard to believe that all that happened to one person. The aggressive and decisive decision making under fire is really inspiring.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-pastel-city-by-michael-john-harrison" id="the-pastel-city-by-michael-john-harrison"&gt;&lt;/a&gt;The Pastel City by Michael John Harrison&lt;/h3&gt;
&lt;p&gt;I'm a fan of &amp;quot;The New Weird,&amp;quot; so I had this on the queue to revisit some of the &amp;quot;weird fiction&amp;quot; that inspired some of the books I've enjoyed.&lt;/p&gt;
&lt;p&gt;Kind of crazy that this book was in 1971. I can see its echos in Star Wars, Brandon Sanderson, and of course New Weird like the Southern Reach trilogy.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#children-of-time-by-adrian-tchaikovsky" id="children-of-time-by-adrian-tchaikovsky"&gt;&lt;/a&gt;Children of Time by Adrian Tchaikovsky&lt;/h3&gt;
&lt;p&gt;This book &lt;em&gt;devoured&lt;/em&gt; my time until it was done. I don't think I've read it before, but I am fairly certain that I had it explained to me by someone at some point. (Looking at you Robert H.!)&lt;/p&gt;
&lt;p&gt;If you like high-concept scifi and haven't read this one, this is a good one to visit. It deserves the accolades it got.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#i-spent-11-years-working-on-this-line-rider-track--by-david-lu--medium" id="i-spent-11-years-working-on-this-line-rider-track--by-david-lu--medium"&gt;&lt;/a&gt;I Spent 11 Years Working on This Line Rider Track | by David Lu | Medium&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I remember when I first discovered Line Rider, that Flash game from 2006 with the simple premise of drawing a track for a sledder to ride on. I was immediately sucked into it, doing things like devising elaborate tracks for the rider to overcome, building worlds for the rider to explore, and manipulating the rider to perform stunts.&lt;/p&gt;
&lt;p&gt;[…]&lt;/p&gt;
&lt;p&gt;Eleven years later, after I reversed engineered and recreated Line Rider, after I developed as an artist and explored all types of creative mediums, I finally completed the project and even went beyond my original vision, reclaiming the project to tell a new story.
I present to you, Omniverse II.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;😱😱😱&lt;/p&gt;
&lt;p&gt;&lt;a href="https://delu.medium.com/i-spent-11-years-working-on-this-line-rider-track-96742fc0b709"&gt;I Spent 11 Years Working on This Line Rider Track | by David Lu | Medium&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#copying-is-the-way-design-works--matthew-ström-designer--developer" id="copying-is-the-way-design-works--matthew-ström-designer--developer"&gt;&lt;/a&gt;Copying is the way design works || Matthew Ström: designer &amp;amp; developer&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;There’s another word in Chinese for a copy: shanzhai (山寨). It’s translated to English as “fake,” but as with most Chinese words, the translation is lacking. Shanzhai literally means “mountain stronghold;” the word is a neologism, a recent invention, inspired by a famous novel in which the protagonists hide in a mountain stronghold to fight against a corrupt regime. Shanzhai products are playful, drawing attention to the fact that they aren’t original, putting their makers’ creativity on display.&lt;/p&gt;
&lt;p&gt;Take the popular shanzhai novel Harry Potter and the Porcelain Doll; in it, Harry goes to China to stop Voldemort and Voldemort’s Chinese counterpart. It doesn’t pretend to be an original. It plays on its fake-ness: Harry speaks Chinese fluently, but he has trouble eating with chopsticks.&lt;/p&gt;
&lt;p&gt;It’s easy to think of shanzhai as a Chinese quirk, but there are parallels in Western culture. One in particular, is a staple of the design community: the unsolicited redesign.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Wonderful essay.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://matthewstrom.com/writing/copying/"&gt;Copying is the way design works || Matthew Ström: designer &amp;amp; developer&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-truth-about-expressive-individualism" id="the-truth-about-expressive-individualism"&gt;&lt;/a&gt;The Truth about Expressive Individualism&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;expressive individualism is simply this idea that the most authentic individual, the most real person, is the person who expresses or performs outwardly that which they are inwardly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I found this to be very helpful… it's a philosophy that spans across our entire culture these days… &amp;quot;that person is so real&amp;quot; is a common refrain.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of the big differences between what we might call Christian expressive individualism and secular expressive individualism is that Christian expressive individualism acknowledges that there may be a problem with that which is inside.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://www.crossway.org/articles/the-truth-about-expressive-individualism/"&gt;The Truth about Expressive Individualism&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#how-to-think-for-yourself" id="how-to-think-for-yourself"&gt;&lt;/a&gt;How to Think for Yourself&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I wish someone had told me about this distinction when I was a kid, because it's one of the most important things to think about when you're deciding what kind of work you want to do. Do you want to do the kind of work where you can only win by thinking differently from everyone else? I suspect most people's unconscious mind will answer that question before their conscious mind has a chance to. I know mine does.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To try and avoid conventional thinking is an interesting idea… it's particularly weird since people on both sides of the aisle consider the other side to be the convention.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;More generally your goal should be not to let anything into your head unexamined, and things don't always enter your head in the form of statements. Some of the most powerful influences are implicit. How do you even notice these? By standing back and watching how other people get their ideas.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This sounds like choosing to develop your worldview more than anything else. I can agree with that.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.paulgraham.com/think.html"&gt;How to Think for Yourself&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-rise-and-triumph-of-the-modern-self--tim-challies" id="the-rise-and-triumph-of-the-modern-self--tim-challies"&gt;&lt;/a&gt;The Rise and Triumph of the Modern Self | Tim Challies&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;It turns finally to the world-changing ideas of Friedrich Nietzsche, Karl Marx, and Charles Darwin who each “in their different ways provided conceptual justification for rejecting the notion of human nature and thus paved the way for the plausibility of the idea that human beings are plastic creatures with no fixed identity founded on an intrinsic and ineradicable essence.” It is through these men that society’s notion of the self became psychologized.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://www.challies.com/book-reviews/the-rise-and-triumph-of-the-modern-self/"&gt;The Rise and Triumph of the Modern Self | Tim Challies&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#youre-all-just-jealous-of-my-jetpack" id="youre-all-just-jealous-of-my-jetpack"&gt;&lt;/a&gt;YOU'RE ALL JUST JEALOUS OF MY JETPACK&lt;/h3&gt;
&lt;p&gt;I love this artist.&lt;/p&gt;
&lt;p&gt;&lt;img alt="cartoon" src="https://64.media.tumblr.com/91554541232522d3cd17d02b4260d5c9/77bdcdb34837f880-a9/s500x750/5f6549dc4f880701fb43f1662c8d2f6ed9bb6035.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://myjetpack.tumblr.com/post/634935022132051968/my-latest-cartoon-for-new-scientist-see-more-of-my"&gt;YOU'RE ALL JUST JEALOUS OF MY JETPACK | My latest cartoon for New Scientist See more of my...&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#jeffrey-paul-your-computer-isnt-yours" id="jeffrey-paul-your-computer-isnt-yours"&gt;&lt;/a&gt;Jeffrey Paul: Your Computer Isn't Yours&lt;/h3&gt;
&lt;p&gt;We were all super confused when this happened mid November… but now I'm just concerned. It probably wasn't a malicious design originally, but this sounds like something that &lt;a href="https://www.apple.com/apples-commitment-to-customer-privacy/"&gt;a company truly committed to privacy&lt;/a&gt; should address.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On modern versions of macOS, you simply can’t power on your computer, launch a text editor or eBook reader, and write or read, without a log of your activity being transmitted and stored.&lt;/p&gt;
&lt;p&gt;It turns out that in the current version of the macOS, the OS sends to Apple a hash (unique identifier) of each and every program you run, when you run it. Lots of people didn’t realize this, because it’s silent and invisible and it fails instantly and gracefully when you’re offline, but today the server got really slow and it didn’t hit the fail-fast code path, and everyone’s apps failed to open if they were connected to the internet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://sneak.berlin/20201112/your-computer-isnt-yours/"&gt;Jeffrey Paul: Your Computer Isn't Yours&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Mon, 30 Nov 2020 20:28:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/11/30/books-and-links-november/</guid></item><item><title>A small problem with e-voting in Italy</title><link>https://stop.zona-m.net/2020/11/a-small-problem-with-e-voting-in-italy/</link><description>&lt;p&gt;Some Italians may e-vote soon. Says WHO?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 30 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/a-small-problem-with-e-voting-in-italy/</guid></item><item><title>Will we ever get solid systems?</title><link>https://utf9k.net/blog/solid-systems/</link><description>Is software reliable? Probably not</description><author>utf9k</author><pubDate>Mon, 30 Nov 2020 13:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/solid-systems/</guid></item><item><title>Setting up a cross-platform SDL project</title><link>https://riv.dev/setting-up-a-cross-platform-sdl-project/</link><description>A look at how to set up SDL everywhere.</description><author>River Gillis [riv.dev]</author><pubDate>Mon, 30 Nov 2020 05:15:00 GMT</pubDate><guid isPermaLink="true">https://riv.dev/setting-up-a-cross-platform-sdl-project/</guid></item><item><title>Focus Is the Most Important Thing</title><link>https://bytesizetheories.com/posts/focus-is-the-most-important-thing/</link><description>In the present world we live in, most products compete on the same market and for the same resource: our attention.
The usual suspects are facebook, twitter, reddit on your phone, netflix, hulu &amp;amp; friends on your other devices.
In the &amp;ldquo;more tolerated&amp;rdquo; category we have personal messaging: imessage, signal, whatsapp &amp;amp; messenger (hey again facebook).
The competition has recently extended to &amp;ldquo;workplace productivity&amp;rdquo;. This is a sneaky way of saying &amp;ldquo;social media, but at work&amp;rdquo;: slack, teams, email.</description><author>Byte Size Theories</author><pubDate>Mon, 30 Nov 2020 03:58:56 GMT</pubDate><guid isPermaLink="true">https://bytesizetheories.com/posts/focus-is-the-most-important-thing/</guid></item><item><title>A simple neural network</title><link>https://explog.in/notes/funnn.html</link><description>&lt;p&gt;
    Belatedly realizing that it's surprisingly simple to implement a
    neural network from scratch, particularly if you don't care about
    using it in production -- some developer notes and a snapshot of a
    basic net in roughly ~150 lines of Rust with minimal dependencies.
    &lt;/p&gt;

    &lt;p&gt;
    (Unrelated aside: &lt;a href="https://www.youtube.com/watch?v=gFvKvdznUdc"&gt;A Notebook Style Guide&lt;/a&gt; (&lt;a href="https://github.com/kunalb/nbstyle/blob/master/ANotebookStyleGuide.ipynb"&gt;Slides&lt;/a&gt;) -- a short talk I
    gave at JupyterCon 2020 was released on YouTube. It started &lt;a href="https://explog.in/notes/nbstyle.html"&gt;as a blog
    post&lt;/a&gt; here earlier this year.)
    &lt;/p&gt;</description><author>RSS</author><pubDate>Mon, 30 Nov 2020 02:20:00 GMT</pubDate><guid isPermaLink="true">https://explog.in/notes/funnn.html</guid></item><item><title>Goodbye Google Play Music</title><link>https://blog.imraniqbal.org/goodbye-google-play-music/</link><description>&lt;p&gt;This weekend I spent some time migrating my music off Google Play Music to Spotify.&lt;/p&gt;
&lt;p&gt;I am going to miss its auto generated radio stations which helped introduce me to a lot of new music.&lt;/p&gt;
&lt;p&gt;The last Google product that I actually enjoyed was Google Inbox, which was subsequently also killed.
With this I am probably not going to be buying into any new Google products.&lt;/p&gt;
&lt;p&gt;The lesson learnt is that do not pay for a service that is not the primary income
for that company. Otherwise you do not have any garauntees that they wont kill
the service off once they're bored with it.&lt;/p&gt;
&lt;p&gt;Here's to hoping Spotify won't shut down in the immediate future.&lt;/p&gt;</description><author>Imran's Blog</author><pubDate>Mon, 30 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.imraniqbal.org/goodbye-google-play-music/</guid></item><item><title>2020–11–30: Improved ANX7688 driver and increased I2C speed</title><link>https://xnux.eu/log/#026</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 30 Nov 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#026</guid></item><item><title>Test emails with Symfony</title><link>https://swag.industries/test-emails-with-symfony/</link><description>Let's see together how to test Symfony emails with PHPUnit, but also with Behat.</description><author>Swag Industries</author><pubDate>Sun, 29 Nov 2020 16:09:47 GMT</pubDate><guid isPermaLink="true">https://swag.industries/test-emails-with-symfony/</guid></item><item><title>My objective function will blow it up</title><link>https://dorotac.eu/posts/objective/</link><description>&lt;h1&gt;My objective function will blow it up&lt;/h1&gt;
&lt;p&gt;I have a preference for playing god. Build a system, observe, disrupt, see what new equilibrium it reaches. This manifests in weirdest places: gardening, cleaning, feeding the birds, computer games. Here's the story of how it turned me into a loss function and how you could become one too.&lt;/p&gt;
&lt;p&gt;Computer games define the main thread today. It all played out in the span of mere weeks before publishing the post.&lt;/p&gt;
&lt;h2&gt;Fuel&lt;/h2&gt;
&lt;p&gt;It started from an unexpected angle this time: not &lt;em&gt;Black and White&lt;/em&gt;, where you literally play god to your people, nor &lt;em&gt;Civilization&lt;/em&gt; where your actions determine the prosperity of a city. Instead, what set me on the path to explosion was &lt;em&gt;Crimsonland&lt;/em&gt;, namely &lt;a href="http://phoenix.ee/old-crimsonland-1-02-1-3-0-1-4-0/"&gt;the freeware 2002 version&lt;/a&gt;. As I mourned that it's not playable under Linux, I considered making a Libre clone. However, after succumbing to a few more waves of monsters, I also concluded that it's perfect at what it does, therefore any potential attempt to replicate it would end up a great disappointment. No point trying. I let my attention wander.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Crimsonland in action, credit Phoenix.ee" src="http://phoenix.ee/wp-content/uploads/2012/04/cl1-1024x788.png" /&gt;&lt;/p&gt;
&lt;h2&gt;Oxidizer&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Creatures&lt;/em&gt; is be a name you might have heard in the '90s and early '00s. A series of games that could be as sophisticated tamagotchi, they put you in charge of the well-being of humanoid creatures called Norns. I stumbled across a &lt;a href="https://www.youtube.com/watch?v=mxperoO4Kd8"&gt;gameplay video&lt;/a&gt;, which showed some gameplay, including sharing tips about punishing and rewarding Norns for their behaviour, breeding them, showing the contents of the neural network that makes their brains, and analyzing the chemicals flowing through their bodies. Turns out they have genes too!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Norns splashing in the water. The pink one is about to jump off a pier, another is diving deep among the fishes. Credit: Wikipedia" src="Creatures_2_Norns.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;To me, that moved the game from "being a parent" to "playing god" territory. I immediately tried it out. Turns out that playing a nurturing god is only exciting when there's something going on, and the Norns learn and explore rather slowly. As I let them be, as they walked back and forth on a second screen, my attention went astray again…&lt;/p&gt;
&lt;h2&gt;Detonator&lt;/h2&gt;
&lt;p&gt;My next chance encounter was the &lt;a href="https://news.ycombinator.com/item?id=24983956"&gt;link&lt;/a&gt; to Bevy, the game engine written in Rust. Nice, I've been wanting to learn to use an Entity Component System for a while, and I'm unwilling to deal with C. I never made games because of how tedious basic graphics are, but if I had anything to use it for, I would give it a try.&lt;/p&gt;
&lt;h2&gt;Fire in the hole!&lt;/h2&gt;
&lt;p&gt;And then it all clicked.&lt;/p&gt;
&lt;p&gt;What if I took Crimsonland and gave the monsters a set of genes – simple enough to let them sense the enemy and walk – and culled them using the protagonist's weapons, it would be artificial selection!&lt;/p&gt;
&lt;h2&gt;Selection by gun&lt;/h2&gt;
&lt;p&gt;What's so cool about that? It's that the programmer is no longer directly in control. A well executed evolutionary algorithm may take you to unexpected places. It may be undesired when it subverts your goals and &lt;a href="https://deepmind.com/blog/article/Specification-gaming-the-flip-side-of-AI-ingenuity"&gt;do something you didn't want it to&lt;/a&gt; – there was a group who tried to teach a simulated human to throw a ball, but ended up with one &lt;em&gt;running with it&lt;/em&gt; instead (sadly, I lost the link). It may be neutral when the shape of its solution is &lt;a href="https://en.wikipedia.org/wiki/Evolved_antenna"&gt;just weird&lt;/a&gt;, or, like I hope to see here, it may bring surprise and variety into the game. That's on top of the fact that &lt;em&gt;I don't really know&lt;/em&gt; how to program a smart AI for a monster myself.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Evolved antenna looking like a randomly bent wire" src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/St_5-xband-antenna.jpg/220px-St_5-xband-antenna.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Now that we know what evolution is good for, what are the pieces it requires to take off?&lt;/p&gt;
&lt;p&gt;First, we need a bunch of creatures: the gene pool. That's a given both in the virtual world and on farms. Evolution does not work on individuals, but on groups, and it's the group of individuals that keeps improving.&lt;/p&gt;
&lt;p&gt;Next, in order for the group to improve, there needs to be a way to know the "better" ones from "worse" ones. For a farmer, this may be the number of laid eggs. For a shooter, let's start with the rule that every creature (genome) that manages to score a bite gets a "goodness" point. That's also called the "objective function".&lt;/p&gt;
&lt;p&gt;It's no use knowing what is better if we don't do something about. We want improvement in our gene pool, so genomes scoring higher will more often be the source of newly spawned creatures, and those less bitey will be underrepresented. That keeps the balance on the high side.&lt;/p&gt;
&lt;p&gt;But those spawned creatures will not just be genetic copies of their ancestors. If they were, our gene pool would only be able to lose genetic variety: some heritage lines (the unsuccessful ones) would die off forever, leaving emptiness in its place. So we need to restore some of that variety. Instead of spawning exact clones, we give them a chance to mutate! Less bitey mutations rarely score high, and so they rarely reproduce. Little harm done. However, better monsters score high often, and they will spawn copies more often – gene pool improvement!&lt;/p&gt;
&lt;p&gt;We end up with a dominating loop: creature -&amp;gt; bite -&amp;gt; mutate -&amp;gt; better creature -&amp;gt; bite -&amp;gt; mutate. There are other paths which arrive at a dead end, like: creature -&amp;gt; bite -&amp;gt; mutate -&amp;gt; worse creature -&amp;gt; fail, or bad creature -&amp;gt; fail -&amp;gt; not breed. As long as the loop dominates, however, we're improving.&lt;/p&gt;
&lt;p&gt;There, now we are on the path to breed ultimate killing machines, and I can play god with an entire species of virtual beings.&lt;/p&gt;
&lt;h2&gt;Breedmatic&lt;/h2&gt;
&lt;p&gt;The result of that all of thinking is a prototype game &lt;a href="https://github.com/dcz-self/breedmatic"&gt;Breedmatic&lt;/a&gt;. Adhering to my principle of starting in the middle, from the most interesting part, I went on to create a bunch of genetically modifiable monsters. They are very simple: sense, turn, walk. The genes describe how they turn relative to their target: their "brain". There's one hidden part of the story though: breeding and maintaining a healthy population.&lt;/p&gt;
&lt;p&gt;It turns out that implementing a good genetic algorithm takes a lot of time. There are considerations regarding the size of gene pools, the rates of mutation of different parts of the genome, the selection of the best objective function, and even the strategy for preserving diversity: should reproduction be asexual? Diploid? How many sexes? That is a lot of sessions of shooting monsters. Hands get tired, progress is slow. In a moment of inspiration, I decided to sidestep the problem with… an evolutionary algorithm. As of version 0.2, the shooter itself is driven by evolution, in much similar way as the monsters.&lt;/p&gt;
&lt;p&gt;But they start blank, so you can watch the shooters over hundreds of attempts going from barely moving through phases of spinning randomly to somewhat competent, and even sometimes coming up with weird moves which end up scattering the otherwise accurate laser, which end up being nonsensically effective against the incoming hordes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://porcupinefactory.org/data/breed3.mkv"&gt;A video of an evolved shooter that actually kinda gets it. Seizures help when shooting lasers, apparently.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Playing god has never been so comfy: no need to even move a finger.&lt;/p&gt;
&lt;h2&gt;Is this fun tho?&lt;/h2&gt;
&lt;p&gt;Sure it is. Watching the struggle of each and every shooter, I can't help but pray to the random number generator gods for luck in the next draw. "May it be 55's offspring next! It was turning the right way, just opposite!". The chance of hitting gold with the brain connections keeps me on the edge of the seat, and I lose track of time. Every session, there's a chance that a previously unseen combination appears – and the brain is only made of 7 neurons!&lt;/p&gt;
&lt;h2&gt;But you promised I could be the objective function!&lt;/h2&gt;
&lt;p&gt;And so you can! The most recent version from git lets you take over control. The monsters are not bred for variety, and the gameplay is basic though, so it's rather boring. At least compared to watching evolution go, so I have a better idea going in that direction.&lt;/p&gt;
&lt;p&gt;Did you play &lt;a href="http://www.massivechalice.com/"&gt;Massive Chalice&lt;/a&gt;? It combines a tactical game with the management of a royal lineage. There are not many games of this sort, and the premise is effectively the same as mine here: to end up with a genetically superior population. Following the inspiration, future versions of Breedmatic will aim to put the player – not the algorithm – in the role of the gene pool manager. Hopefully that's more fun than shooting questionably intelligent monsters.&lt;/p&gt;
&lt;h2&gt;Evolve&lt;/h2&gt;
&lt;p&gt;Breedmatic is open, so if you are dismayed with the intelligence or shape of the creatures, feel free to fork it or contribute. Perhaps we can share ideas regarding the actual gameplay. The prototype could still evolve in many directions!&lt;/p&gt;
&lt;p&gt;Otherwise, watch this space. While the next post may not be about evolution, I always have some crazy project in progress.&lt;/p&gt;</description><author>dcz's posts</author><pubDate>Sun, 29 Nov 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/objective/</guid></item><item><title>Unlimited free WiFi on flights with T-Mobile</title><link>https://jonlu.ca/posts/tmobile-wifi</link><description>Investigating an airline Wi-Fi authentication flow that granted T-Mobile connectivity.</description><author>JonLuca's Blog</author><pubDate>Sun, 29 Nov 2020 14:12:29 GMT</pubDate><guid isPermaLink="true">https://jonlu.ca/posts/tmobile-wifi</guid></item><item><title>Create Ebay Scraper in Python using Scraper API  Learn how to create an eBay data scraper in Python to fetch item details and price.</title><link>https://blog.adnansiddiqi.me/create-ebay-scraper-in-python-using-scraper-api/</link><description>&lt;p&gt;In this post of ScrapingTheFamous, I am going o write a scraper that will scrape data from eBay. eBay is an online auction site where people put their listing up for selling stuff based on an auction. Like before, we will be writing the two scripts, one to fetch listing URs and store in a text file and the other to parse those links. The data will be stored in JSON format for further processing. I will be using Scraper API service for parsing purposes which makes me free from all worries blocking and rendering dynamic sites since it takes care of everything. The first script is to fetching listings of a category. So let’s do it! import requests from bs4 import BeautifulSoup if __name__ == '__main__': API_KEY = None links_file = 'links.txt' links = [] with open('API_KEY.txt', encoding='utf8') as f: API_KEY = f.read() URL_TO_SCRAPE = 'https://www.ebay.com/b/Computer-Components-Parts/175673/bn_1643095' payload = {'api_key': API_KEY, 'url': URL_TO_SCRAPE, 'render': 'false'} r = requests.get('http://api.scraperapi.com', params=payload, timeout=60) if r.status_code == 200: html = r.text.strip() soup = BeautifulSoup(html, 'lxml') entries = soup.select('.s-item a') for entry in entries: if 'p/' in entry['href']: listing_url = entry['href'].replace('&amp;#38;rt=nc#UserReviews', '') links.append(listing_url) if len(links) &amp;#62; 0: with open(links_file, 'a+', encoding='utf8') as f: f.write('\n'.join(links)) print('Links stored successfully.') Now let&amp;#8217;s write the parse script for parsing individual listing information. Do remember that I am not here to write the entire script and each and everything. I already made many tutorials about it and you can check it all here. SO below is the parse script: import requests from bs4 import BeautifulSoup if __name__ == '__main__': record = {} price = title = seller = image = None with open('API_KEY.txt', encoding='utf8') as f: API_KEY = f.read() URL_TO_SCRAPE = 'https://www.ebay.com/p/5034585650?iid=202781903791' payload = {'api_key': API_KEY, 'url': URL_TO_SCRAPE, 'render': 'false'} r = requests.get('http://api.scraperapi.com', params=payload, timeout=60) if r.status_code == 200: html = r.text soup = BeautifulSoup(html, 'lxml') title_section = soup.select('.product-title') if title_section: title = title_section[0].text.strip() selleer_section = soup.select('.seller-persona') if selleer_section: seller = selleer_section[0].text.replace('Sold by', '').replace('Positive feedbackContact seller', '') selller = seller[:-6] price_section = soup.select('.display-price') if price_section: price = price_section[0].text image_section = soup.select('.vi-image-gallery__enlarge-link img') if image_section: image = image_section[0]['src'] record = { 'title': title, 'price': price, 'seller': seller, 'image': image, } print(record) When I run the script it prints the following: { 'title': 'AMD Ryzen 3 3200G - 3.6GHz Quad Core (YD3200C5FHBOX) Processor', 'price': '$99.99', 'seller': 'best_buy\xa0(698388)97.2% ', 'image': 'https://i.ebayimg.com/images/g/ss8AAOSwsbhdmy2e/s-l640.jpg' } Pretty straight forward. Conclusion In this post, you learned how you can scrape eBay data easily by using Scraper API in Python. You can enhance this script as per your need like writing a price monitoring script. Writing scrapers is an interesting journey but you can hit the wall if the site blocks your IP. As an individual, you can’t afford expensive proxies either. Scraper API provides you an affordable and easy to use API that will let you scrape websites without any hassle. You do not need to worry about getting blocked because Scraper API by default uses proxies to access websites. On top of it, you do not need to worry about Selenium either since Scraper API provides the facility of a headless browser too. I also have written a post about how to use it. Click here to signup with my referral link or enter promo code adnan10, you will get a 10% discount on it. In case you do not get the discount then just let me know via email on my site and I’d sure help you out. If you like this post then you should subscribe to my blog for future updates. * indicates required Email Address *&lt;/p&gt;
The post &lt;a href="https://blog.adnansiddiqi.me/create-ebay-scraper-in-python-using-scraper-api/"&gt;Create Ebay Scraper in Python using Scraper API &lt;br /&gt; &lt;span style="color: grey; font-size: 25px; font-weight: 300;"&gt;Learn how to create an eBay data scraper in Python to fetch item details and price.&lt;/span&gt;&lt;/a&gt; first appeared on &lt;a href="https://blog.adnansiddiqi.me"&gt;Adnan's Random bytes&lt;/a&gt;.</description><author>Adnan's Random bytes</author><pubDate>Sun, 29 Nov 2020 11:56:52 GMT</pubDate><guid isPermaLink="true">https://blog.adnansiddiqi.me/create-ebay-scraper-in-python-using-scraper-api/</guid></item><item><title>Emacs: Clone git repo from clipboard</title><link>https://xenodium.com/emacs-clone-git-repo-from-clipboard</link><description>&lt;p&gt;Cloning git repositories is a pretty common task. For me, it typically goes something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Copy git repo URL from browser.&lt;/li&gt;
&lt;li&gt;Drop to Emacs eshell.&lt;/li&gt;
&lt;li&gt;Change current directory.&lt;/li&gt;
&lt;li&gt;Type &amp;quot;git clone &amp;quot;.&lt;/li&gt;
&lt;li&gt;Paste git repo URL.&lt;/li&gt;
&lt;li&gt;Run git command.&lt;/li&gt;
&lt;li&gt;Change directory to cloned repo.&lt;/li&gt;
&lt;li&gt;Open dired.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No biggie, but why go through the same steps every time? We can do better. We have a hyper malleable editor, so let's get it to grab the URL from clipboard and do its thing.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;shell-command&lt;/em&gt; or &lt;em&gt;async-shell-command&lt;/em&gt; can help in this space, but require additional work: change location, re-type command, what if directory already exists… This is Emacs, so we can craft the exact experience we want. I did take inspiration from &lt;em&gt;shell-command&lt;/em&gt; to display the process buffer correctly (git progress, control codes, etc.) and landed on the following experience:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-clone-git-repo-from-clipboard/git_clone_dired.gif" /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;;; -*- lexical-binding: t -*-

(defun ar/git-clone-clipboard-url ()
  &amp;quot;Clone git URL in clipboard asynchronously and open in dired when finished.&amp;quot;
  (interactive)
  (cl-assert (string-match-p &amp;quot;^\\(http\\|https\\|ssh\\)://&amp;quot; (current-kill 0)) nil &amp;quot;No URL in clipboard&amp;quot;)
  (let* ((url (current-kill 0))
         (download-dir (expand-file-name &amp;quot;~/Downloads/&amp;quot;))
         (project-dir (concat (file-name-as-directory download-dir)
                              (file-name-base url)))
         (default-directory download-dir)
         (command (format &amp;quot;git clone %s&amp;quot; url))
         (buffer (generate-new-buffer (format &amp;quot;*%s*&amp;quot; command)))
         (proc))
    (when (file-exists-p project-dir)
      (if (y-or-n-p (format &amp;quot;%s exists. delete?&amp;quot; (file-name-base url)))
          (delete-directory project-dir t)
        (user-error &amp;quot;Bailed&amp;quot;)))
    (switch-to-buffer buffer)
    (setq proc (start-process-shell-command (nth 0 (split-string command)) buffer command))
    (with-current-buffer buffer
      (setq default-directory download-dir)
      (shell-command-save-pos-or-erase)
      (require 'shell)
      (shell-mode)
      (view-mode +1))
    (set-process-sentinel proc (lambda (process state)
                                 (let ((output (with-current-buffer (process-buffer process)
                                                 (buffer-string))))
                                   (kill-buffer (process-buffer process))
                                   (if (= (process-exit-status process) 0)
                                       (progn
                                         (message &amp;quot;finished: %s&amp;quot; command)
                                         (dired project-dir))
                                     (user-error (format &amp;quot;%s\n%s&amp;quot; command output))))))
    (set-process-filter proc #'comint-output-filter)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Comment on &lt;a href="https://www.reddit.com/r/emacs/comments/k3iter/simplequick_git_repo_clone_from_browser_to_emacs/"&gt;reddit&lt;/a&gt; or &lt;a href="https://twitter.com/xenodium/status/1333111043791458309"&gt;twitter&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Updates&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Added lexical binding.&lt;/li&gt;
&lt;li&gt;Checks clipboard for ssh urls also.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 29 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-clone-git-repo-from-clipboard</guid></item><item><title>Moving my blog to zola</title><link>https://blog.imraniqbal.org/moving-to-zola/</link><description>&lt;p&gt;I decided to move my blog to &lt;a href="https://www.getzola.org/" rel="external"&gt;Zola&lt;/a&gt; instead of Docusaurus.
They are both static site generators, but Zola is much faster.&lt;/p&gt;
&lt;p&gt;Heres a Docusaurus build:&lt;/p&gt;
&lt;p&gt;&lt;img alt="yarn build" src="https://blog.imraniqbal.org/img/yarn_build.png" /&gt;&lt;/p&gt;
&lt;p&gt;And heres a Zola build:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Zola build" src="https://blog.imraniqbal.org/img/zola_build.png" /&gt;&lt;/p&gt;</description><author>Imran's Blog</author><pubDate>Sun, 29 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.imraniqbal.org/moving-to-zola/</guid></item><item><title>Writing on books - Fantastic Beasts and Where to Find Them</title><link>https://captnemo.in/blog/2020/11/29/fantastic-beasts-graffiti/</link><description>&lt;p&gt;“Fantastic Beasts and Where to Find Them” is a curious book:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The in-universe book is written by Newt Scamander and was published in 1927.&lt;/li&gt;
  &lt;li&gt;The first edition of the companion book was published in 2001. This is apparently the 52nd in-universe edition with a foreword from Dumbledore and was released to the muggle world for charity.&lt;/li&gt;
  &lt;li&gt;The 2001 edition pretends to be Harry’s copy of the book as of the end of Harry’s 4th year at Hogwarts. As such it includes hand-written comments from the trio. (Yes, Hermione writes on books!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, with the release of the film of the same name in 2016 - a new edition was released with lots of changes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;6 new beasts that made an appearance in the film were added to the book&lt;sup id="fnref:1"&gt;&lt;a class="footnote" href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;:
    &lt;ul&gt;
      &lt;li&gt;Hidebehind&lt;/li&gt;
      &lt;li&gt;Hodag&lt;/li&gt;
      &lt;li&gt;Horned Serpent&lt;/li&gt;
      &lt;li&gt;Snallygaster&lt;/li&gt;
      &lt;li&gt;Thunderbird&lt;/li&gt;
      &lt;li&gt;Wampus cat&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The hand-lettering was removed.&lt;/li&gt;
  &lt;li&gt;Dumbledore’s foreword is removed from the book, in favor of a in-universe foreword from Newt Scamander.&lt;/li&gt;
  &lt;li&gt;“About the Author” section changes Newt’s background. He &lt;a href="https://old.reddit.com/r/harrypotter/comments/5z8ozu/new_edition_of_fantastic_beasts_removes_part/"&gt;no longer graduates from Hogwarts&lt;/a&gt;, just “leaves” it, as portrayed in the film.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these changes are meant to fix the inconsistencies in the book with the canon, however that also makes the book much less charming. I got myself a copy of the &lt;a href="https://amzn.to/39ni3vh"&gt;Hogwarts Library boxset&lt;/a&gt; a few years ago, which includes the newer edition of the book (Bloomsbury) - that means no witty comments from Ron.&lt;/p&gt;

&lt;p&gt;Since it didn’t have the hand-lettering, I took it upon myself to fix that mistake. Thankfully, lists of &lt;a href="https://harrypotter.fandom.com/wiki/Fantastic_Beasts_and_Where_to_Find_Them_(companion_book)#Comments_in_the_2001_edition"&gt;all the comments in 2001 edition&lt;/a&gt; are available &lt;a href="https://imgur.com/a/C2a1g"&gt;on the internet&lt;/a&gt;. The trickiest part was the “this book belongs to” page, which is missing from the newer edition. I ended up creating a faux-library card for that instead.&lt;/p&gt;

&lt;p&gt;Here is what it looks like:&lt;/p&gt;

&lt;div class="splide" id="image-slider" style="background-color: #efefef;"&gt;
  &lt;div class="splide__track"&gt;
    &lt;ul class="splide__list"&gt;
      &lt;li class="splide__slide"&gt;&lt;img src="/img/fbawtft/mine/1.jpg" title="Ron plays hangman and loses" /&gt;&lt;div&gt;Ron plays hangman and loses.&lt;/div&gt;&lt;/li&gt;
      &lt;li class="splide__slide"&gt;&lt;img src="/img/fbawtft/mine/3.jpg" title="The fake library card that says this book belongs to Harry Potter" /&gt;&lt;div&gt;Hermione writes on books!&lt;/div&gt;&lt;/li&gt;
      &lt;li class="splide__slide"&gt;&lt;img src="/img/fbawtft/mine/4.jpg" /&gt;&lt;/li&gt;
      &lt;li class="splide__slide"&gt;
        &lt;img src="/img/fbawtft/mine/2.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/5.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/6.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/7.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/8.jpg" /&gt;
      &lt;/li&gt;
      &lt;li class="splide__slide"&gt;
        &lt;img src="/img/fbawtft/mine/10.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/11.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/12.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/13.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/14.jpg" /&gt;
      &lt;/li&gt;
      &lt;li class="splide__slide"&gt;
        &lt;img src="/img/fbawtft/mine/16.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/17.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/18.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/19.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/20.jpg" /&gt;
      &lt;/li&gt;
      &lt;li class="splide__slide"&gt;
        &lt;img src="/img/fbawtft/mine/15.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/21.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/22.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/23.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/24.jpg" /&gt;
      &lt;/li&gt;
      &lt;li class="splide__slide"&gt;
        &lt;img src="/img/fbawtft/mine/25.jpg" /&gt;
        &lt;img src="/img/fbawtft/mine/26.jpg" /&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Thanks to &lt;a href="https://instagram.com/avyadraws/"&gt;Bhavya&lt;/a&gt; for helping with the troll illustration.&lt;/p&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;I didn’t like the new additions, they sound less like a textbook and more like a transcript of what happened in the film. &lt;a class="reversefootnote" href="#fnref:1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>Nemo's Home</author><pubDate>Sun, 29 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://captnemo.in/blog/2020/11/29/fantastic-beasts-graffiti/</guid></item><item><title>🍳 Vegetarian Bolognese</title><link>prashanth.world/squeaky-nail/prashanth.world/vegetarian-bolognese/</link><description>A simple mushroom based bolognese, with lots of depth.</description><author>Prashanth Sadasivan</author><pubDate>Sun, 29 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">prashanth.world/squeaky-nail/prashanth.world/vegetarian-bolognese/</guid></item><item><title>Measuring Java JVM thread activity in Linux with task state sampling</title><link>https://tanelpoder.com/posts/measuring-java-jvm-thread-level-activity-on-linux/</link><description>&lt;blockquote&gt;
&lt;p&gt;FYI: I will be speaking about similar topics at &lt;a href="https://www.p99conf.io"&gt;P99Conf&lt;/a&gt; in Oct 2023 (online, free event)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are plenty of JVM profilers out there, but before attaching with a profiler, you can get a high-level overview by just sampling the Linux &lt;code&gt;/proc/PID/comm&lt;/code&gt; and &lt;code&gt;/proc/PID/stat&lt;/code&gt; fields to see which JVMs threads are most active and whether they&amp;rsquo;re burning CPU or are blocked by some I/O.&lt;/p&gt;
&lt;p&gt;When creating threads in Java, you can name them using the following syntax: &lt;code&gt;Thread t = new Thread(&amp;quot;MyThread&amp;quot;)&lt;/code&gt; or &lt;code&gt;thread.setName(&amp;quot;Worker-123&amp;quot;)&lt;/code&gt;. This name will show up in the &lt;code&gt;comm&lt;/code&gt; fields in Linux &lt;code&gt;/proc&lt;/code&gt;. Some developers make good use of this &lt;em&gt;observability&lt;/em&gt; feature.&lt;/p&gt;</description><author>Tanel Poder Blog</author><pubDate>Sun, 29 Nov 2020 00:52:09 GMT</pubDate><guid isPermaLink="true">https://tanelpoder.com/posts/measuring-java-jvm-thread-level-activity-on-linux/</guid></item><item><title>The Problem Mindset</title><link>https://peterlyons.com/problog/2020/11/the-problem-mindset/</link><description>&lt;p&gt;Everywhere I look in the tech world, I see everything everyone does being framed as "solving problems". "What problem are you trying to solve?" is a question asked at the start of many project inception documents. It occupies an early slide in most presentations. Whole company missions are framed as solving a particular problem. Many engineers list problem solving as one of their core skills.&lt;/p&gt;
&lt;p&gt;My motivation for this post is to simply state that I don't think this mindset should be taken as a given and I personally don't think this way about everything. It's not that clearly defining a problem isn't a useful approach to planning/strategy. I just think about the word "problem" in a more specific way meaning something is broken, troublesome, or has gone wrong somehow. I think the world needs people and organizations doing things in addition to solving problems. It's perfectly valid to be refining something that is not problematic. It's fine to be creating a new capability from scratch without having to think of the "I don't have X capability" as the definition of the problem.&lt;/p&gt;
&lt;p&gt;OK let's go through some concrete examples.&lt;/p&gt;
&lt;p&gt;Are ride sharing apps like Lyft and Uber really solving a problem? I think of them as providing a particular kind of transportation. It's an update to a centuries-old core business in the world of smart phones, GPS, gig economy, etc. There's a raft of interesting changes in their financial models, approach to vehicle inventory, driver relations, driver compensation, driver competition, etc, but fundamentally I don't think of what they are doing of solving the problem of "I would rather use an app than a telephone to summon a taxicab". For that matter I don't think "transportation" when thought of as a problem has a science-fact solution. We can make it better, but not really solve it as a problem. Thus I would think about it more like a need.&lt;/p&gt;
&lt;p&gt;WTF problem is instagram solving? It's a thing that exists and has utility for some and is also problematic but I can't bend my brain to think of instagram as solving any particular problem. I guess if arch-capitalists think of "Advertising dollars are being spent with companies I do not own" as a problem, then Instagram solves for that I guess?&lt;/p&gt;
&lt;p&gt;Does AirBnB really solve the "It's hard for me to book short-term tenants into my guest room" problem? It makes a lot more sense to me to think of this as creating a marketplace facilitated by the web and smartphone apps.&lt;/p&gt;
&lt;p&gt;Here's a couple examples of companies/products that it seems logical to think about as solving a problem.&lt;/p&gt;
&lt;p&gt;Insurance comes to mind. Something rare and costly just went wrong and I otherwise would be in financial disaster, but insurance prevents that disaster for me. Roadside assistance. A flat tire is a problem that sometimes happens and while roadside service doesn't "solve" it as in prevent it from ever being a thing that happens, it reduces the impact significantly.&lt;/p&gt;
&lt;p&gt;An extension cord solves a problem. In some ways WiFi solves a similar problem for your network cable, but it seems weird to me to think about WiFi as a solution to the problem "my gigantic ethernet cable is annoying to manage while I carry my laptop around the house". It's just a new technology and I don't feel any need to frame it in relationship to a specific problem.&lt;/p&gt;
&lt;p&gt;If any of this resonates with you, please join me in rolling our eyes in our next strategic planning meeting.&lt;/p&gt;</description><author>Pete's Points</author><pubDate>Sat, 28 Nov 2020 20:32:03 GMT</pubDate><guid isPermaLink="true">https://peterlyons.com/problog/2020/11/the-problem-mindset/</guid></item><item><title>When you make digital archives in the wrong way...</title><link>https://stop.zona-m.net/2020/11/when-you-make-digital-archives-in-the-wrong-way.../</link><description>&lt;p&gt;Sooner or later they rot. But only in that case.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 28 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/when-you-make-digital-archives-in-the-wrong-way.../</guid></item><item><title>Quarkus and Testcontainers</title><link>https://www.morling.dev/blog/quarkus-and-testcontainers/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_bonus_schema_creation"&gt;Bonus: Schema Creation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The &lt;a href="https://www.testcontainers.org/"&gt;Testcontainers&lt;/a&gt; project is invaluable for spinning up containerized resources during your (JUnit) tests,
e.g. databases or Kafka clusters.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;For users of JUnit 5, the project provides the &lt;a href="https://www.testcontainers.org/quickstart/junit_5_quickstart/"&gt;&lt;code&gt;@Testcontainers&lt;/code&gt;&lt;/a&gt; extension, which controls the lifecycle of containers used by a test.
When testing a &lt;a href="https://quarkus.io/"&gt;Quarkus&lt;/a&gt; application though, this is at odds with Quarkus' own &lt;a href="https://quarkus.io/guides/getting-started-testing#recap-of-http-based-testing-in-jvm-mode"&gt;&lt;code&gt;@QuarkusTest&lt;/code&gt;&lt;/a&gt; extension;
it’s a recommended &lt;a href="https://bsideup.github.io/posts/testcontainers_fixed_ports/"&gt;best practice&lt;/a&gt; to avoid fixed ports for any containers started by Testcontainers.
Instead, you should rely on Docker to automatically allocate random free ports.
This avoids conflicts between concurrently running tests,
e.g. amongst multiple Postgres containers,
started up by several parallel job runs in a CI environment, all trying to allocate Postgres' default port 5432.
Obtaining the randomly assigned port and passing it into the Quarkus bootstrap process isn’t possible though when combining the two JUnit extensions.&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Sat, 28 Nov 2020 18:45:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/quarkus-and-testcontainers/</guid></item><item><title>Obsidian Fixed Unlinked Mentions for ZK IDs!</title><link>http://evantravers.com/articles/2020/11/28/obsidian-fixed-unlinked-mentions-for-zk-ids/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/graph.png" /&gt;&lt;/p&gt;&lt;p&gt;I have been working on the &lt;a href="https://github.com/evantravers/plaintext-migration"&gt;migration script&lt;/a&gt; to move my plaintext notes to a format that Obsidian and other applications will like.&lt;/p&gt;
&lt;p&gt;I determined that it seemed more applications had adopted YAML syntax for their frontmatter&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; Adopting this format would be as app-compatible as possible. With my previous recommendation of using multimarkdown-style frontmatter, you were locked to MMD, but by using YAML I could use multimarkdown, github-markdown, common mark, or just plain markdown.&lt;/p&gt;
&lt;p&gt;With the &lt;code&gt;#hashtag&lt;/code&gt; style tags and YAML markdown, pretty much everything in Obsidian worked 100% with SMZ style zettels &lt;em&gt;except&lt;/em&gt; the incredible useful &amp;quot;Unlinked Mentions.&amp;quot;&lt;/p&gt;
&lt;p&gt;Until yesterday. 🤷&lt;/p&gt;
&lt;p&gt;Obsidian is moving &lt;em&gt;very&lt;/em&gt; fast, and each new build update the team posts to Discord brings wonderful toys. I bought the Insider Access to try out the feature I was interested in… they rolled it out to the general public around four hours afterward. I am not sorry at all… they are making an amazing application.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://forum.obsidian.md/t/obsidian-release-v0-9-17/8862"&gt;Obsidian v0.9.16&lt;/a&gt; brought the ability to define an &lt;code&gt;aliases&lt;/code&gt; attribute in the frontmatter of a note. That means if you have a note named &amp;quot;Artificial Intelligence&amp;quot; with the file name &lt;code&gt;Artificial Intelligence.md&lt;/code&gt;, you can set up aliases like:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-plaintext" tabindex="0"&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;title: &amp;quot;Artificial Intelligence&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;aliases: ['AI', 'Expert Systems']
&lt;/div&gt;&lt;div class="line"&gt;tags: ['#futurism', '#technology']
&lt;/div&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;Artificial Intelligence broadly covers a number of technologies ranging from […]
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now… any time in your notes there is the string &amp;quot;AI&amp;quot;, &amp;quot;Artificial Intelligence&amp;quot;, or &amp;quot;Expert Systems,&amp;quot; Obsidian will show it as an unlinked mention, ready to be linked up.&lt;/p&gt;
&lt;p&gt;This works for filenames containing a Zettelkasten ID! If your filename is &lt;code&gt;202011280902-obsidian.md&lt;/code&gt; you can define your alias simply as:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-plaintext" tabindex="0"&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;title: &amp;quot;Obsidian&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;aliases: ['Obsidian']
&lt;/div&gt;&lt;div class="line"&gt;tags: ['#knowledge_management']
&lt;/div&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;I'm really starting to like Obsidian[…]
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Suddenly, Unlinked Mentions work perfectly! 🥳 This closes &lt;a href="https://forum.obsidian.md/t/display-a-list-of-current-notes-outgoing-unlinked-mentions/8830"&gt;a feature-request&lt;/a&gt; I that has been floating around for a &lt;em&gt;long&lt;/em&gt; while, and really excites me to get the last 10 years of notes into a place where Obsidian can find it. Suddenly I can be working on a note on &amp;quot;Leadership&amp;quot;, and find journal entries and project logs that cross reference &amp;quot;leadership&amp;quot; and draw new conclusions.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/unlinked.png" /&gt;&lt;/p&gt;
&lt;p&gt;I included this idea of &lt;code&gt;aliases&lt;/code&gt; in &lt;a href="https://github.com/evantravers/plaintext-migration/commit/923e914e506f1e6de8502f28bd241a8a23124e64"&gt;my migration script&lt;/a&gt;, and I am having a &lt;strong&gt;blast&lt;/strong&gt; re-discovering all my notes (&lt;em&gt;especially&lt;/em&gt; book notes!) and seeing all the new ways that they relate.&lt;/p&gt;
&lt;p&gt;The only hitch here is that when I create a new note, it would be nice for Obsidian to make it &lt;em&gt;really&lt;/em&gt; easy to have a note with the ZK ID and automatically add the title and alias. I have seen a templating system in Obsidian and I'll dig into it, but I don't think it has the simple syncing smarts that I'm looking for… so I may add Obsidian scripting to my todo list right after I finish fixing my Drafts workflows.&lt;/p&gt;
&lt;p&gt;Honestly thinking out loud… I'd probably be just as happy using Drafts to write all my zettel and use actions to send them to Obsidian, treating Obsidian as a research tool and Drafts as a capture tool… I think I will definitely prioritize my Drafts actions soon. 👍&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;I'll eventually fix the table in the original article and link it here. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Sat, 28 Nov 2020 18:16:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/11/28/obsidian-fixed-unlinked-mentions-for-zk-ids/</guid></item><item><title>Scotland: The Story of a Nation</title><link>https://macleodsawyer.com/books/scotland-the-story-of-a-nation/</link><description>&lt;p&gt;Hailed as a vast, superb history that relates Scotland’s past over a dozen millennia”, Magnusson draws on a great deal of modern scholarship to redefine a nation’s history. He charts the long struggle toward nationhood, explores the roots of the original Scots, and examines the extent to which Scotland was shaped by the Romans, the Picts, the Vikings, and the English. Encompassing everything from the first Mesolithic settlers in 7000 B.C. to the present movements for independence, Scotland: The Story of a Nation is history on an epic level, essential reading for anyone interested in the rich past of this captivating land.&lt;/p&gt;</description><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Sat, 28 Nov 2020 14:06:36 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/books/scotland-the-story-of-a-nation/</guid></item><item><title>Why Benford's Law is Obvious</title><link>http://alanbernstein.github.io/posts/benford/</link><description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Benford%27s_law" target="_blank"&gt;Benford&amp;rsquo;s Law&lt;/a&gt; states that in many naturally occurring collections of numbers, the leading digit is likely to be small. I love math factoids like this, and I remember how deeply unintuitive this seemed when I first learned it. Now, I find myself looking for a way to explain how intuitive it really is.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Ok, Benford&amp;rsquo;s law isn&amp;rsquo;t obvious. But what would the world look like if it were?&lt;/p&gt;
&lt;p&gt;Benford&amp;rsquo;s law follows unavoidably from a certain type of probability distribution (uniform in the logarithmic domain), which happens to be common in real-world data. I can draw some charts that &amp;ndash; to me &amp;ndash; make this perfectly clear. Somehow, that doesn&amp;rsquo;t make it any less surprising to learn. Go figure.&lt;/p&gt;
&lt;p&gt;I contend that the surprise comes from a lack of familiarity with the log-uniform distribution. What if we, as a society, internalized that distribution &lt;em&gt;instead&lt;/em&gt; of the &amp;ldquo;usual&amp;rdquo; linear-uniform one? In this post, I explain what the counterpart of Benford&amp;rsquo;s law would be in that case. It turns out, it&amp;rsquo;s almost too obvious to mention. Which is the point.&lt;/p&gt;
&lt;h2 id="benfords-law"&gt;Benford&amp;rsquo;s Law&lt;/h2&gt;
&lt;p&gt;When you first hear of it, the thinking might go something like this: if you choose a number randomly, shouldn&amp;rsquo;t the first digit be uniformly distributed? Even if the original distribution isn&amp;rsquo;t uniform, as long as it covers a wide enough range, why would the &lt;em&gt;first digit&lt;/em&gt; have any bias?&lt;/p&gt;
&lt;p&gt;Explanations abound, but I find that they often miss the crucial point (like this otherwise fantastic &lt;a href="https://youtu.be/etx0k1nLn78" target="_blank"&gt;video&lt;/a&gt; for example). Simply put, it is a direct consequence of the &lt;a href="https://en.wikipedia.org/wiki/Reciprocal_distribution" target="_blank"&gt;log-uniform distribution&lt;/a&gt;, which governs these &amp;ldquo;naturally occurring collections of numbers&amp;rdquo;, e.g. measurements, population counts, etc. If you can accept that these natural collections tend to be log-normal distributed, Benford&amp;rsquo;s Law is &amp;ldquo;obvious&amp;rdquo;, that is, an unavoidable consequence. Some simply explain this empirically, giving examples. But I think there is more to it.&lt;/p&gt;
&lt;p&gt;Why do some collections of numbers have this tendency? I like to think of it like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The logarithmic scale is &lt;em&gt;at least&lt;/em&gt; as natural a way to look at the world as the linear scale is.&lt;/li&gt;
&lt;li&gt;In a given scale (linear, log, or otherwise), a uniform distribution is the &amp;ldquo;simplest&amp;rdquo; option. It&amp;rsquo;s sort of a default distribution, perhaps in part due to being the maximum entropy distribution for a bounded domain.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;m aware that this is an academic viewpoint - I&amp;rsquo;m using &amp;ldquo;obvious&amp;rdquo; facetiously here. While the log-uniform distribution may be more &amp;ldquo;natural&amp;rdquo; in some sense, the linear-uniform distribution is certainly not unusual. Roll a die, draw a card, pick a ball from an urn - these are all basic processes, easily understood, and obviously uniform. While they may be more common in the built environment rather than in nature, they are still regular occurrences to a human child living in society, helping to reify the linear scale in her mind.&lt;/p&gt;
&lt;p&gt;The linked video also presents a counterexample to Benford&amp;rsquo;s law, plus a counterpart law with its corresponding counterexample. Paraphrased:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Benford&amp;rsquo;s Law: most-significant digits are expected to be biased toward lower values with a logarithmic trend, &lt;em&gt;if&lt;/em&gt; the range of values spans multiple orders of magnitude.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Benford Counterexample (Biden votes): If the data spans just a single order of magnitude (specifically [10^n, 10^(n+1)) so the number of digits is constant, then the first-digit distribution just reflects the data distribution itself. Benford&amp;rsquo;s law is not &lt;em&gt;violated&lt;/em&gt;, it is rather &lt;em&gt;not applicable&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Last-digit test: least-significant digits are expected to be distributed uniformly, &lt;em&gt;if&lt;/em&gt; the range of values is wide enough, relative to the precision of the values.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Last-digit counterexample (incumbent votes): If the data spans just a single, &lt;strong&gt;low&lt;/strong&gt;, order of magnitude, e.g. [10, 100), then the last two digits are just &lt;em&gt;the digits&lt;/em&gt;, so the last-digits distribution just reflects the data distribution itself. The last-digit test is not &lt;em&gt;violated&lt;/em&gt;, it is rather &lt;em&gt;not applicable&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;There&amp;rsquo;s a pleasing sort of duality here, and illustrating each of these with the two political parties&amp;rsquo; vote counts is pretty cute.&lt;/p&gt;
&lt;h2 id="another-counterpart"&gt;Another counterpart&lt;/h2&gt;
&lt;p&gt;Although these are interesting lines of thought, they prompted another question, the real motivation for writing this: is there &lt;em&gt;another&lt;/em&gt; counterpart to Benford&amp;rsquo;s Law, which might be equally surprising to a culture that thinks in the logarithmic scale by default? Of course, human sensory perception is logarithmic, as is our natural perception of integers. But early education beats that out of us, and our culture generally encourages us to consider the linear scale as the default way of thinking about numbers - the Way Numbers Really Are.&lt;/p&gt;
&lt;p&gt;If, instead, we were trained from a young age to think about the logarithmic scale as the default, then what sort of distribution would lead to a similarly surprising result, and what would that result be?&lt;/p&gt;
&lt;p&gt;After ruminating on this topic over the years, and a concerted hour or two of trying to answer this question, I found a candidate. I&amp;rsquo;ll restate Benford&amp;rsquo;s again for comparison:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Benford&amp;rsquo;s Law: When accustomed to the linear scale, a log-uniform distribution results in a suprising bias in first-digits, logarithmically decreasing from 1 to 9.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And the linear counterpart:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Drofben&amp;rsquo;s Law: When accustomed to the logarithmic scale, a linear-uniform distribution results in a surprising bias in number-of-digits, exponentially increasing from 1 (to N).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These charts illustrate both laws, as described above &amp;ndash; but I&amp;rsquo;ll elaborate.&lt;/p&gt;
&lt;h3 id="graphical-explanation-benfords-law"&gt;Graphical explanation, Benford&amp;rsquo;s Law&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Figure 1: Log-uniform random data" src="https://alanbernstein.net/blog-static/img
/benford/figure1.png" /&gt;
&lt;em&gt;Figure 1: Log-uniform random data&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a set of three views of the same random data set, following a log-uniform distribution.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1a shows that log-uniform data follows a logarithmically-decreasing trend, &lt;em&gt;when viewed in the linear domain&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;1b shows that log-uniform data follows a constant trend, when viewed in the (arguably more appropriate) logarithmic domain.&lt;/li&gt;
&lt;li&gt;1c shows Benford&amp;rsquo;s law directly, with bar heights corresponding to first-digit bias. Note that this shape closely resembles the shape of the distribution in 1a &amp;ndash; it isn&amp;rsquo;t identical, because 1c kind of &amp;ldquo;layers&amp;rdquo; the histograms from each level of magnitude in 1a, into a new form that examines only first digits instead of all values.&lt;/li&gt;
&lt;li&gt;1d (aside from being kind of busy because I&amp;rsquo;m a bad graphic designer) shows where these &amp;ldquo;layers&amp;rdquo; come from. The black trace represents the determinstic values of the function first_digit(x) for all values of x in [1, 10000]. The green regions cover all numbers that start with 1, and they&amp;rsquo;re widest &amp;ndash; that cumulative width corresponds to the height of the bar for digit 1 in figure 1c. Red regions correspond to numbers that start with 2, with a more moderate cumulative width. Purple corresponds to 5, with a much smaller width, and similarly for all other digits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;This figure explains why Benford&amp;rsquo;s Law is &amp;ldquo;obvious&amp;rdquo;. It may be more clear to explain the logical progression of thought:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;This data follows a natural distribution &amp;ndash; log-uniform &amp;ndash; illustrated by the constant trend in the logarithmic domain (1b).&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;This necessitates a logarithmic-decreasing trend in the linear domain (1a).&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;This necessitates a logarithmic-decreasing trend in the first digits (1c, 1d).&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="graphical-explanation-drofbens-law"&gt;Graphical explanation, Drofben&amp;rsquo;s Law&lt;/h3&gt;
&lt;p&gt;And here are the corresponding charts for Drofben&amp;rsquo;s law:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure 2: Linear-uniform random data" src="https://alanbernstein.net/blog-static/img
/benford/figure2.png" /&gt;
&lt;em&gt;Figure 2: Linear-uniform random data&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a set of three views of another random data set, following a linear-uniform distribution.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2a shows that linear-uniform data follows a constant trend, when viewed in the linear domain.&lt;/li&gt;
&lt;li&gt;2b shows that linear-uniform data follows an exponentially-increasing trend, when viewed in the logarithmic domain.&lt;/li&gt;
&lt;li&gt;2c shows Drofben&amp;rsquo;s law directly, with bar heights corresponding to number-of-digits bias. Note that this shape closely resembles the shape of the distribution in 2b.&lt;/li&gt;
&lt;li&gt;2d shows the analogous &amp;ldquo;layers&amp;rdquo; of Drofben&amp;rsquo;s law &amp;ndash; these layers just represent magnitude. The gray region, representing numbers with five digits, takes up 90% of the total width. Pink, for four digits, takes 9%, and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the second case, these layers just reflect the counts of integers in ranges: |[1, 10)| = 9, |[10, 100)| = 90, |[100, 1000)| = 900, etc &amp;ndash; this seems almost too obvious to mention. But, that&amp;rsquo;s what I was looking for &amp;ndash; a result that&amp;rsquo;s surprising to an alien, logarithmic culture &lt;em&gt;should&lt;/em&gt; be obvious to our linear minds.&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://gist.github.com/alanbernstein/39cc97fc582cbb2cd30df59c40853129" target="_blank"&gt;code for charts&lt;/a&gt;)&lt;/p&gt;
&lt;h2 id="the-digits-are-not-the-value"&gt;The digits are not the value&lt;/h2&gt;
&lt;p&gt;&lt;img alt="The treachery of digits: an homage to Magritte&amp;rsquo;s The Treachery of Images, with &amp;ldquo;This is not a number&amp;rdquo; as a caption for the hexadecimal representation of the floating-point value NaN, &amp;ldquo;Not a Number&amp;rdquo;" src="https://alanbernstein.net/blog-static/img
/benford/treachery-of-digits-hex.png" /&gt;
&lt;em&gt;The treachery of digits, with apologies to &lt;a href="https://en.wikipedia.org/wiki/The_Treachery_of_Images" target="_blank"&gt;Magritte&lt;/a&gt;&amp;hellip; and &lt;a href="https://en.wikipedia.org/wiki/NaN" target="_blank"&gt;IEEE&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;div class="admonition warning" style="border-left: 4px solid #cd5f3c; padding-left: 2em; font-size: 16px; margin: 2em 0;"&gt;
    &lt;div class="title"&gt;Warning&lt;/div&gt;
    &lt;div class="content"&gt;Philosophical rambling ahead&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;All of this might seem silly. Consider a linear-uniform distribution over [1, 100). Of course the range [10, 99] is 10x as likely as the range [1, 9] &amp;ndash; that&amp;rsquo;s just the relative size of the intervals. But it&amp;rsquo;s the &lt;em&gt;arithmetic size&lt;/em&gt;, the linear size. If you were conditioned to think first of the &lt;em&gt;geometric size&lt;/em&gt;, the logarithmic size, you would instinctively see these two intervals as having (nearly) the same size. You wouldn&amp;rsquo;t expect the linear-uniform distribution, and this behavior would indeed be surprising. Perhaps it&amp;rsquo;s hard to imagine this, because &lt;em&gt;the digits themselves&lt;/em&gt; make it obvious: for Benford&amp;rsquo;s Law, it is not obvious that 1234 is any more likely to occur than 5678. In contrast, you can&amp;rsquo;t help but notice that 5 has only one digit, while 5678 has four digits. However, considering non-integer values allows us to make a more illustrative comparison between 5.678 and 5678. Try to imagine perceiving numbers through their &lt;em&gt;magnitude&lt;/em&gt; instead of their &lt;em&gt;digits&lt;/em&gt;. Perhaps growing up using a slide rule is the best way to internalize the logarithmic scale. I missed that boat by a few years.&lt;/p&gt;
&lt;p&gt;My point is, the digits are only a representation of the number&amp;rsquo;s value. Despite being a perfectly complete representation, the &lt;em&gt;digit string&lt;/em&gt; is not an innate property of the &lt;em&gt;value&lt;/em&gt;, but rather an artifact of the representation system. It&amp;rsquo;s like looking for information in the pixel boundaries of a photograph: anything you find might be explained by the sampling grid, and disappear under a different sampling. Any properties of the digit string of a number might be explained by the choice of base, and disappear under a different base.&lt;/p&gt;
&lt;p&gt;Of course, the number of digits is a crude approximation of the magnitude (regardless of the choice of base), whereas the first digit is more reasonably described as a &amp;ldquo;random&amp;rdquo; artifact of the representation. I&amp;rsquo;ll concede that the number of digits is not &lt;em&gt;just&lt;/em&gt; an artifact, and therefore Drofben&amp;rsquo;s Law is more obvious &amp;ndash; &lt;em&gt;if&lt;/em&gt; you think about numbers primarily in terms of their non-fractional digits.&lt;/p&gt;
&lt;div class="admonition note" style="border-left: 4px solid #3c5f8d; padding-left: 2em; font-size: 16px; margin: 2em 0;"&gt;
    &lt;div class="title"&gt;Tangent&lt;/div&gt;
    &lt;div class="content"&gt;I&amp;rsquo;m a former mathlete, I love recreational math problems/puzzles. These sometimes concern properties of the base-10 representation of numbers (Project Euler often uses the &lt;a href="https://projecteuler.net/problem=20" target="_blank"&gt;digit sum&lt;/a&gt;, etc., similarly, the Putnam exam usually includes a problem where the current year is used as an &lt;a href="https://kskedlaya.org/putnam-archive/2019.pdf" target="_blank"&gt;upper limit&lt;/a&gt; or the like), and I&amp;rsquo;ve always thought of these as sort of &amp;ldquo;impure&amp;rdquo; problems which aren&amp;rsquo;t as deeply interesting. On the other hand, there is some deep math involved in &lt;a href="https://en.wikipedia.org/wiki/Goodstein%27s_theorem" target="_blank"&gt;Goodstein sequences&lt;/a&gt;, based on fiddling around with hereditary base-N notation. Although, it comes specifically from &lt;em&gt;not&lt;/em&gt; constraining N.&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="base-effects"&gt;Base effects&lt;/h3&gt;
&lt;p&gt;When working with numbers, we have to pick some representation system; base 10 is fine, but it might be interesting to think about how these artifacts change when using different systems. While Benford&amp;rsquo;s Law occurs regardless of the base, there is some interesting behavior at the extremes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;base 2: Benford&amp;rsquo;s Law doesn&amp;rsquo;t mean as much in this case &amp;ndash; all first bits are 1! The generalization still applies to first-N-bits, but this is still an interesting comparison. In contrast, number-of-bits is now a closer approximation to the magnitude of the number.&lt;/li&gt;
&lt;li&gt;base infinity: each numeral is represented by a different symbol. Now, number-of-digits is always 1! Most of the questions become meaningless, because we&amp;rsquo;ve abandoned the concept of place-value digits, without abandoning the values. The concept of &amp;ldquo;first digit bias&amp;rdquo; isn&amp;rsquo;t even tautological as in the base-2 case. The distribution of digit occurrences still contains some information, however.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Aside from these extremes, there is the zero-padded representation of base-N. Now, regardless of the the value of N, first-digit is uniform, and number-of-digits is constant. As lazy humans, we don&amp;rsquo;t bother writing out all these leading zeros, but that&amp;rsquo;s how computers work! I suppose a child raised by computers would think all of the zero-pad-counterparts of these laws are perfectly obvious and devoid of value.&lt;/p&gt;</description><author>Micro-optimist</author><pubDate>Sat, 28 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://alanbernstein.github.io/posts/benford/</guid></item><item><title>Un an avec SailfishOS</title><link>/post/2020/11/28/un-an-avec-sailfishos/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;figure&gt;&lt;img src="/images/sailfishOS/sailfishos.png" width="750" /&gt;
&lt;/figure&gt;

&lt;p&gt;&lt;a href="https://sailfishos.org/"&gt;SailfishOS&lt;/a&gt; est un système d&amp;rsquo;exploitation mobile basé sur Linux. C&amp;rsquo;est aujourd&amp;rsquo;hui l&amp;rsquo;une des rares alternatives à Android et iOS sur le marché des smartphones.&lt;/p&gt;
&lt;p&gt;Cet article est un retour d&amp;rsquo;expérience d&amp;rsquo;un Sony Xperia X sous SailfishOS que j&amp;rsquo;ai utilisé comme smartphone principal pendant l&amp;rsquo;année 2019.&lt;/p&gt;
&lt;p&gt;Le Sony Xperia X n&amp;rsquo;a pas été choisi par hasard, puisqu&amp;rsquo;il s&amp;rsquo;agit de l&amp;rsquo;un des smartphones officiellement supportés par &lt;a href="https://sailfishos.org/"&gt;SailfishOS&lt;/a&gt;. Il est disponible aux alentours de 70€ sur internet en occasion (j&amp;rsquo;ai acheté le mien sur aliexpress pour 90€ début 2019).&lt;/p&gt;</description><author>Accueil on dbeley</author><pubDate>Sat, 28 Nov 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">/post/2020/11/28/un-an-avec-sailfishos/</guid></item><item><title>Don't boycott Amazon. Free it, instead.</title><link>https://stop.zona-m.net/2020/11/dont-boycott-amazon.-free-it-instead./</link><description>&lt;p&gt;Something to think about, on this and all future Black Fridays.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 27 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/dont-boycott-amazon.-free-it-instead./</guid></item><item><title>A weirdness with tinydns</title><link>https://rjp.is/blogging/posts/2020/11/tinydns-snafu/</link><description>In which tinydns needs better logging.</description><author>infrequent oscillations</author><pubDate>Fri, 27 Nov 2020 18:36:33 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/11/tinydns-snafu/</guid></item><item><title>My Favorite New Podcasts in 2020</title><link>https://www.swyx.io/fave-podcasts-2020</link><description>An update to my favorite podcasts list with the ones I have found this year</description><author>swyx's site RSS Feed</author><pubDate>Fri, 27 Nov 2020 18:18:14 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/fave-podcasts-2020</guid></item><item><title>John Oliver Thirst Bot</title><link>https://rjp.is/blogging/posts/2020/11/27-joliver-thirst/</link><description>In which John Oliver is Thirsty.</description><author>infrequent oscillations</author><pubDate>Fri, 27 Nov 2020 11:31:08 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/11/27-joliver-thirst/</guid></item><item><title>PostgreSQL autogenerated interval</title><link>https://b.agilob.net/programming/sql/postgresql-generated-interval/</link><description>Using postgres specific SQL syntax we can create autogenerated column which subtracts two dates and stores them as interval.
The age function is also null-safe, so if time_ended or time_started it will not crash.
ALTER TABLE session ADD COLUMN duration interval GENERATED ALWAYS AS (age(time_ended, time_started)) STORED;</description><author>Random Notes by agilob</author><pubDate>Fri, 27 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://b.agilob.net/programming/sql/postgresql-generated-interval/</guid></item><item><title>RMS Does Not See the Future of Emacs</title><link>https://lambdaland.org/posts/2020-11-future-of-emacs/</link><description>&lt;p&gt;I am an avid &lt;a class="link-external" href="https://emacs.org" rel="external"&gt;Emacs&lt;/a&gt; user. I’m using it right now to compose this post. I use it every single day for everything from work to school to personal notes. Most of my activity on GitHub comes from me tweaking little things in my configuration files. I now have an editor that perfectly fits my hands. Emacs is a big part of my life.&lt;/p&gt;
&lt;p&gt;I’m afraid it’s dying.&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Fri, 27 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-11-future-of-emacs/</guid></item><item><title>Racially biased pulsimeters</title><link>https://stop.zona-m.net/2020/11/racially-biased-pulsimeters/</link><description>&lt;p&gt;More of the depressing same.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 26 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/racially-biased-pulsimeters/</guid></item><item><title>Emulating linux/AMD64 userland: interpreting an ELF binary</title><link>http://notes.eatonphil.com/emulating-amd64-starting-with-elf.html</link><description>&lt;p&gt;In this post we'll stumble toward a working emulator for a barebones C
program compiled for linux/AMD64. The approach will be slightly more
so based on observation than by following a spec; a great way
to quickly become familiar with a topic, and a bad way to guarantee
correctness.&lt;/p&gt;
&lt;p&gt;The goal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;tests/simple.c
int&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;tests/simple.c
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="m"&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This may look ridiculously simple but when you don't know how to deal
with a binary or how instructions are encoded, it will take a few
hours to write an emulator that can generally handle this program!&lt;/p&gt;
&lt;p&gt;Code for this project is &lt;a href="https://github.com/eatonphil/go-amd64-emulator"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="background"&gt;Background&lt;/h3&gt;&lt;p&gt;AMD64, x86_64 or x64 are different names for AMD's widely adopted
64-bit extension to Intel's x86 instruction set (i.e. the encoding and
semantics of x86 binaries). AMD64 is a superset of x86 (introducing
64-bit registers and operations) and thus backwards compatible with
x86 programs.&lt;/p&gt;
&lt;p class="note"&gt;
  A year and a half ago I first got into emulation with
  an &lt;a href="https://notes.eatonphil.com/emulator-basics-a-stack-and-register-machine.html"&gt;AMD64
  emulator in JavaScript&lt;/a&gt;. The JavaScript emulator interpreted the
  textual representation of AMD64 programs (e.g. &lt;code&gt;MOV RBP,
  RSP&lt;/code&gt;, Intel's assembly syntax). A C program had to be compiled
  with &lt;code&gt;-S&lt;/code&gt; to produce an assembly file that the JavaScript
  emulator could read (i.e. &lt;code&gt;gcc -S tests/simple.c&lt;/code&gt;) This
  was a great way to get started with emulation by ignoring the
  complexity of encoded instructions and executable formats.
&lt;/p&gt;&lt;p&gt;If we dig into the binary file produced by gcc on Linux we learn that
it is an &lt;a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format"&gt;ELF
file&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;test/simple.c
$&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;a.out
a.out:&lt;span class="w"&gt; &lt;/span&gt;ELF&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;64&lt;/span&gt;-bit&lt;span class="w"&gt; &lt;/span&gt;LSB&lt;span class="w"&gt; &lt;/span&gt;executable,&lt;span class="w"&gt; &lt;/span&gt;x86-64,&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;SYSV&lt;span class="o"&gt;)&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;dynamically&lt;span class="w"&gt; &lt;/span&gt;linked,&lt;span class="w"&gt; &lt;/span&gt;interpreter&lt;span class="w"&gt; &lt;/span&gt;/lib64/ld-linux-x86-64.so.2,&lt;span class="w"&gt; &lt;/span&gt;BuildID&lt;span class="o"&gt;[&lt;/span&gt;sha1&lt;span class="o"&gt;]=&lt;/span&gt;d0b5c742b9fbcbcca4dfa9438a8437a8478a51bb,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;GNU/Linux&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.2.0,&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;stripped
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ELF is responsible for surrounding the actual binary-encoded program
instructions with metadata on exported and imported C identifiers and
program entrypoint. But for simple programs like this initial
emulator, we can ignore export/imports. We'll only use the ELF
metadata to find out where the instructions for our &lt;code&gt;main&lt;/code&gt;
function start.&lt;/p&gt;
&lt;h3 id="where-is-main?"&gt;Where is main?&lt;/h3&gt;&lt;p&gt;If we use an ELF reader+disassembler on the binary generated by gcc
and search for &lt;code&gt;main&lt;/code&gt; we can find its address.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-A10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;main&amp;gt;'&lt;/span&gt;
&lt;span class="m"&gt;0000000000401106&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;main&amp;gt;:
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401106&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rbp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401107&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e5&lt;span class="w"&gt;                &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;%rsp,%rbp
&lt;span class="w"&gt;  &lt;/span&gt;40110a:&lt;span class="w"&gt;       &lt;/span&gt;b8&lt;span class="w"&gt; &lt;/span&gt;fe&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;xfe,%eax
&lt;span class="w"&gt;  &lt;/span&gt;40110f:&lt;span class="w"&gt;       &lt;/span&gt;5d&lt;span class="w"&gt;                      &lt;/span&gt;pop&lt;span class="w"&gt;    &lt;/span&gt;%rbp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401110&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;c3&lt;span class="w"&gt;                      &lt;/span&gt;retq
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401111&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;66&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;2e&lt;span class="w"&gt; &lt;/span&gt;0f&lt;span class="w"&gt; &lt;/span&gt;1f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;nopw&lt;span class="w"&gt;   &lt;/span&gt;%cs:0x0&lt;span class="o"&gt;(&lt;/span&gt;%rax,%rax,1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401118&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;40111b:&lt;span class="w"&gt;       &lt;/span&gt;0f&lt;span class="w"&gt; &lt;/span&gt;1f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;44&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;nopl&lt;span class="w"&gt;   &lt;/span&gt;0x0&lt;span class="o"&gt;(&lt;/span&gt;%rax,%rax,1&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="m"&gt;0000000000401120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;__libc_csu_init&amp;gt;:
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This means that the function, &lt;code&gt;main&lt;/code&gt;, starts at
address &lt;code&gt;0x401106&lt;/code&gt; in memory. Furthermore, this implies
that the binary must be loaded into CPU memory such that the CPU can
jump here to execute our program.&lt;/p&gt;
&lt;p&gt;In truth, &lt;code&gt;main&lt;/code&gt; is not this program's entrypoint. If we
run &lt;code&gt;objdump -x a.out&lt;/code&gt; we can see that the ELF entrypoint
is &lt;code&gt;0x401020&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-x&lt;span class="w"&gt; &lt;/span&gt;a.out
a.out:&lt;span class="w"&gt;     &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;format&lt;span class="w"&gt; &lt;/span&gt;elf64-x86-64
a.out
architecture:&lt;span class="w"&gt; &lt;/span&gt;i386:x86-64,&lt;span class="w"&gt; &lt;/span&gt;flags&lt;span class="w"&gt; &lt;/span&gt;0x00000112:
EXEC_P,&lt;span class="w"&gt; &lt;/span&gt;HAS_SYMS,&lt;span class="w"&gt; &lt;/span&gt;D_PAGED
start&lt;span class="w"&gt; &lt;/span&gt;address&lt;span class="w"&gt; &lt;/span&gt;0x0000000000401020

Program&lt;span class="w"&gt; &lt;/span&gt;Header:
&lt;span class="w"&gt;    &lt;/span&gt;PHDR&lt;span class="w"&gt; &lt;/span&gt;off&lt;span class="w"&gt;    &lt;/span&gt;0x0000000000000040&lt;span class="w"&gt; &lt;/span&gt;vaddr&lt;span class="w"&gt; &lt;/span&gt;0x0000000000400040&lt;span class="w"&gt; &lt;/span&gt;paddr&lt;span class="w"&gt; &lt;/span&gt;0x0000000000400040&lt;span class="w"&gt; &lt;/span&gt;align&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;**3
&lt;span class="w"&gt;             &lt;/span&gt;filesz&lt;span class="w"&gt; &lt;/span&gt;0x00000000000002d8&lt;span class="w"&gt; &lt;/span&gt;memsz&lt;span class="w"&gt; &lt;/span&gt;0x00000000000002d8&lt;span class="w"&gt; &lt;/span&gt;flags&lt;span class="w"&gt; &lt;/span&gt;r--
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is because the actual entrypoint gcc sets up is a function called
&lt;code&gt;_start&lt;/code&gt;. The libc prelude beginning
with &lt;code&gt;_start&lt;/code&gt; is responsible for initializing the libc
runtime, calling our &lt;code&gt;main&lt;/code&gt; function and executing the exit
syscall with the return value of &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-A10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;_start&amp;gt;'&lt;/span&gt;
&lt;span class="m"&gt;0000000000401020&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;_start&amp;gt;:
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401020&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;f3&lt;span class="w"&gt; &lt;/span&gt;0f&lt;span class="w"&gt; &lt;/span&gt;1e&lt;span class="w"&gt; &lt;/span&gt;fa&lt;span class="w"&gt;             &lt;/span&gt;endbr64
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401024&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ed&lt;span class="w"&gt;                   &lt;/span&gt;xor&lt;span class="w"&gt;    &lt;/span&gt;%ebp,%ebp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401026&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;d1&lt;span class="w"&gt;                &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;%rdx,%r9
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401029&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;5e&lt;span class="w"&gt;                      &lt;/span&gt;pop&lt;span class="w"&gt;    &lt;/span&gt;%rsi
&lt;span class="w"&gt;  &lt;/span&gt;40102a:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e2&lt;span class="w"&gt;                &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;%rsp,%rdx
&lt;span class="w"&gt;  &lt;/span&gt;40102d:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;83&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e4&lt;span class="w"&gt; &lt;/span&gt;f0&lt;span class="w"&gt;             &lt;/span&gt;and&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;xfffffffffffffff0,%rsp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401031&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rax
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401032&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;54&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rsp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401033&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;49&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;c7&lt;span class="w"&gt; &lt;/span&gt;c0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;x401190,%r8
&lt;span class="w"&gt;  &lt;/span&gt;40103a:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;c7&lt;span class="w"&gt; &lt;/span&gt;c1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;x401120,%rcx
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;But because all this libc initialization is relatively complicated
we're just going to skip the actual ELF entrypoint for now. Our
emulator will locate &lt;code&gt;main&lt;/code&gt;, load the binary into memory,
jump to the start of &lt;code&gt;main&lt;/code&gt;, and set the exit code of the
emulator to the result of main.&lt;/p&gt;
&lt;p class="note"&gt;
  As you can see, this ELF binary has its own hard-coded view of where
  it will be in memory. What if our CPU were to run multiple process
  at once? We might give each process its own virtual memory space
  and map back to a real memory space so each process (and by
  extension, compilers) doesn't have to think about how they fit into
  memory relative to other processes.
&lt;/p&gt;&lt;p&gt;The last question to figure out is where to load the ELF binary into
emulator memory so that addresses in memory are where the program
expects.&lt;/p&gt;
&lt;p&gt;As it turns out, there is a piece of metadata called section
headers that contain an address and a offset from the start of the ELF
file. By subtracting this we can get the location the file expects to
be in memory.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-x&lt;span class="w"&gt; &lt;/span&gt;a.out
a.out:&lt;span class="w"&gt;     &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;format&lt;span class="w"&gt; &lt;/span&gt;elf64-x86-64
a.out
architecture:&lt;span class="w"&gt; &lt;/span&gt;i386:x86-64,&lt;span class="w"&gt; &lt;/span&gt;flags&lt;span class="w"&gt; &lt;/span&gt;0x00000112:
EXEC_P,&lt;span class="w"&gt; &lt;/span&gt;HAS_SYMS,&lt;span class="w"&gt; &lt;/span&gt;D_PAGED
start&lt;span class="w"&gt; &lt;/span&gt;address&lt;span class="w"&gt; &lt;/span&gt;0x0000000000401020

Program&lt;span class="w"&gt; &lt;/span&gt;Header:
&lt;span class="w"&gt;    &lt;/span&gt;PHDR&lt;span class="w"&gt; &lt;/span&gt;off&lt;span class="w"&gt;    &lt;/span&gt;0x0000000000000040&lt;span class="w"&gt; &lt;/span&gt;vaddr&lt;span class="w"&gt; &lt;/span&gt;0x0000000000400040&lt;span class="w"&gt; &lt;/span&gt;paddr&lt;span class="w"&gt; &lt;/span&gt;0x0000000000400040&lt;span class="w"&gt; &lt;/span&gt;align&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;**3
&lt;span class="w"&gt;             &lt;/span&gt;filesz&lt;span class="w"&gt; &lt;/span&gt;0x00000000000002d8&lt;span class="w"&gt; &lt;/span&gt;memsz&lt;span class="w"&gt; &lt;/span&gt;0x00000000000002d8&lt;span class="w"&gt; &lt;/span&gt;flags&lt;span class="w"&gt; &lt;/span&gt;r--
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That is: &lt;code&gt;0x400040 (vaddr) - 0x40 (off) = 0x400000&lt;/code&gt;.
Judging from a Google search this seems to be a pretty common address
where ELF binaries are loaded into memory.&lt;/p&gt;
&lt;h3 id="elf-and-go"&gt;ELF and Go&lt;/h3&gt;&lt;p&gt;Binary file formats tend to be a pain to work with because, to enable
greater compression, everything ends up being a pointer to something
else. So you end up jumping all around the file just to stitch
information back together.&lt;/p&gt;
&lt;p&gt;So the one third-party-ish library we'll use is Go's builtin
&lt;code&gt;debug/elf&lt;/code&gt; package. With this library we can load an ELF
binary and iterate over symbols and sections to discover the location
of &lt;code&gt;main&lt;/code&gt; and the start address for the binary in memory.&lt;/p&gt;
&lt;p&gt;Editing in &lt;code&gt;main.go&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bytes&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;debug/elf&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;io/ioutil&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;os&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readELF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entrySymbol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ioutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ReadFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;elffile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elffile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Symbols&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sym&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;symbols&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entrySymbol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STT_FUNC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ST_TYPE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STB_GLOBAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ST_BIND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sym&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not find entrypoint symbol: %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entrySymbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elffile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SHT_NULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Addr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Offset&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Could not determine start address&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Binary not provided&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readELF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Start: 0x%x\nEntry: 0x%x\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can test on a basic compiled C program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;tests/simple.c
int&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;tests/simple.c
$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out
Start:&lt;span class="w"&gt; &lt;/span&gt;0x400000
Entry:&lt;span class="w"&gt; &lt;/span&gt;0x401106
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And verify against &lt;code&gt;objdump&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-A10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;main&amp;gt;'&lt;/span&gt;
&lt;span class="m"&gt;0000000000401106&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;main&amp;gt;:
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401106&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rbp&lt;span class="s1"&gt;'&amp;gt;'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that's it for dealing with ELF. Now we can sketch out a virtual
CPU and how we deal with interpreting instructions starting at this
address.&lt;/p&gt;
&lt;h3 id="the-cpu"&gt;The CPU&lt;/h3&gt;&lt;p&gt;AMD64 counts on being able to store values in registers and memory,
sometimes through direct addressing and sometimes indirectly using
stack operations (push and pop). And userland processes count on being
loaded into CPU memory so the CPU can jump to the process entrypoint
and process.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;registerFile&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newCPU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;registerFile&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;tick&lt;/code&gt; channel is so that later on we can wrap the
emulator in a terminal debugger. But by default we'll just set up a
goroutine to tick forever.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// TODO&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Binary not provided&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readELF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--debug&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fallthrough&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 10 MB&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newCPU&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x400000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="registers"&gt;Registers&lt;/h3&gt;&lt;p&gt;To emulate a simple program like our &lt;code&gt;tests/simple.c&lt;/code&gt;,
we'll only need to support a few common registers. The order is
important so that we can use the Go identifiers when we want to refer
to the &lt;a href="https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers"&gt;encoded integer value of the
register&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// These are in order of encoding value (i.e. rbp is 5)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rax&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;iota&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rcx&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rdx&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rbx&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rbp&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rsi&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rdi&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r8&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r9&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r10&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r11&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r12&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r13&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r14&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r15&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rflags&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;registerMap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rax&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rcx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rcx&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rdx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rdx&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rbx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rbx&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rsp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rbp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rbp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rsi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rsi&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rdi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rdi&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r9&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r10&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r11&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r12&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r12&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r13&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r14&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r14&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r15&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r15&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rip&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;rflags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rflags&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;registerFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;registerFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;registerFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Of immediate importance will be &lt;code&gt;rip&lt;/code&gt;, &lt;code&gt;rsp&lt;/code&gt;,
and &lt;code&gt;rax&lt;/code&gt; registers. &lt;code&gt;rip&lt;/code&gt; is used to track the
current instruction to process. It will generally be incremented
except for when dealing with function calls and
returns. &lt;code&gt;rsp&lt;/code&gt; is used as a pointer to the top of a stack
in memory. It is incremented and decremented as values are pushed and
popped on this stack. Finally, &lt;code&gt;rax&lt;/code&gt; is used to pass
function return values.&lt;/p&gt;
&lt;h3 id="loading-a-program"&gt;Loading a program&lt;/h3&gt;&lt;p&gt;Running a program is a matter of loading the program into memory,
setting the stack pointer to the last address of memory (in x86 the
stack grows down), pointing &lt;code&gt;rip&lt;/code&gt; at the entrypoint, and
looping until the entrypoint function returns.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;writeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xFF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// TODO: deal with instructions&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// move to next instruction&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startAddress&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;))],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entryPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;initialStackPointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;writeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;initialStackPointer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;initialStackPointer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;initialStackPointer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialStackPointer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rax&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We write the initial stack pointer address into the stack so that when
the program final returns, it will return to this address at which
pointer we can exit the program.&lt;/p&gt;
&lt;p&gt;And now we're ready to start interpreting instructions.&lt;/p&gt;
&lt;h3 id="instruction-decoding"&gt;Instruction decoding&lt;/h3&gt;&lt;p&gt;Using &lt;code&gt;objdump&lt;/code&gt; we get a sense for what the program decodes
to.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-A10&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;main&amp;gt;'&lt;/span&gt;
&lt;span class="m"&gt;0000000000401106&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;main&amp;gt;:
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401106&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rbp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401107&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e5&lt;span class="w"&gt;                &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;%rsp,%rbp
&lt;span class="w"&gt;  &lt;/span&gt;40110a:&lt;span class="w"&gt;       &lt;/span&gt;b8&lt;span class="w"&gt; &lt;/span&gt;fe&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;xfe,%eax
&lt;span class="w"&gt;  &lt;/span&gt;40110f:&lt;span class="w"&gt;       &lt;/span&gt;5d&lt;span class="w"&gt;                      &lt;/span&gt;pop&lt;span class="w"&gt;    &lt;/span&gt;%rbp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401110&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;c3&lt;span class="w"&gt;                      &lt;/span&gt;retq
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401111&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;66&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;2e&lt;span class="w"&gt; &lt;/span&gt;0f&lt;span class="w"&gt; &lt;/span&gt;1f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;nopw&lt;span class="w"&gt;   &lt;/span&gt;%cs:0x0&lt;span class="o"&gt;(&lt;/span&gt;%rax,%rax,1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401118&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;40111b:&lt;span class="w"&gt;       &lt;/span&gt;0f&lt;span class="w"&gt; &lt;/span&gt;1f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;44&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;nopl&lt;span class="w"&gt;   &lt;/span&gt;0x0&lt;span class="o"&gt;(&lt;/span&gt;%rax,%rax,1&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="m"&gt;0000000000401120&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;__libc_csu_init&amp;gt;:
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We see that &lt;code&gt;0x55&lt;/code&gt; means &lt;code&gt;push
%rbp&lt;/code&gt;. And we also see that instructions aren't a fixed number
of bytes. Some are one byte, some are seven. Some (not shown) are &lt;a href="https://stackoverflow.com/questions/14698350/x86-64-asm-maximum-bytes-for-an-instruction"&gt;even
longer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thankfully instructions follow some fairly simple patterns. There are
a set of prefix instructions and a set of real instructions. So far we
should be able to tell on the first byte whether the instruction is a
prefix instruction and, if not, how many bytes the instruction will
take up on the whole.&lt;/p&gt;
&lt;h4 id="push"&gt;push&lt;/h4&gt;&lt;p&gt;To support a new instruction, we'll look up &lt;code&gt;0x55&lt;/code&gt; in an
opcode table like &lt;a href="http://ref.x86asm.net/coder64.html"&gt;this&lt;/a&gt;. Clicking
on &lt;a href="http://ref.x86asm.net/coder64.html#x50"&gt;55&lt;/a&gt; in the opcode index we
see that this is indeed a push instruction. &lt;code&gt;50+r&lt;/code&gt; means
that we have to subtract &lt;code&gt;0x50&lt;/code&gt; from the opcode to
determine the register we should push.&lt;/p&gt;
&lt;p&gt;The register will be &lt;code&gt;0x55 - 0x50 = 5&lt;/code&gt; which if we look up
in a &lt;a href="https://wiki.osdev.org/X86-64_Instruction_Encoding#Registers"&gt;register
table&lt;/a&gt;
is &lt;code&gt;rbp&lt;/code&gt;. Since we set up our register enum in code in this
order, we'll be able to just use the constant &lt;code&gt;rbp&lt;/code&gt; in Go
code.&lt;/p&gt;
&lt;p&gt;Finally, since the next instruction numerically is &lt;code&gt;0x58&lt;/code&gt;
we know that this instruction is identified by being between
&lt;code&gt;0x50&lt;/code&gt; and &lt;code&gt;0x57&lt;/code&gt; inclusive. This is all the
info we need to handle this instruction.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// helper for dumping byte arrays as hex&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hbdebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s:&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; %x&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x58&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// push&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;regvalue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;writeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;regvalue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;hbdebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;prog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown instruction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we try this out now we should expect it to panic on the second
byte, &lt;code&gt;0x48&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out
prog:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e5&lt;span class="w"&gt; &lt;/span&gt;b8&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;5d&lt;span class="w"&gt; &lt;/span&gt;c3
panic:&lt;span class="w"&gt; &lt;/span&gt;Unknown&lt;span class="w"&gt; &lt;/span&gt;instruction

goroutine&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;19&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;running&lt;span class="o"&gt;]&lt;/span&gt;:
main.&lt;span class="o"&gt;(&lt;/span&gt;*cpu&lt;span class="o"&gt;)&lt;/span&gt;.loop&lt;span class="o"&gt;(&lt;/span&gt;0xc000086c30,&lt;span class="w"&gt; &lt;/span&gt;0x2800000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:168&lt;span class="w"&gt; &lt;/span&gt;+0x16d
main.&lt;span class="o"&gt;(&lt;/span&gt;*cpu&lt;span class="o"&gt;)&lt;/span&gt;.run&lt;span class="o"&gt;(&lt;/span&gt;0xc000086c30,&lt;span class="w"&gt; &lt;/span&gt;0xc000086c00&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:180&lt;span class="w"&gt; &lt;/span&gt;+0xac
created&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;main.main
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:211&lt;span class="w"&gt; &lt;/span&gt;+0x286
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looking good.&lt;/p&gt;
&lt;h4 id="mov"&gt;mov&lt;/h4&gt;&lt;p&gt;Taking a look at the next two instructions with &lt;code&gt;objdump&lt;/code&gt;
we see &lt;code&gt;mov&lt;/code&gt; encoded two different ways.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;objdump&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-A4&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;main&amp;gt;'&lt;/span&gt;
&lt;span class="m"&gt;0000000000401106&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;main&amp;gt;:
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401106&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;push&lt;span class="w"&gt;   &lt;/span&gt;%rbp
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;401107&lt;/span&gt;:&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e5&lt;span class="w"&gt;                &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;%rsp,%rbp
&lt;span class="w"&gt;  &lt;/span&gt;40110a:&lt;span class="w"&gt;       &lt;/span&gt;b8&lt;span class="w"&gt; &lt;/span&gt;fe&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;00&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;mov&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;xfe,%eax
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looking up &lt;a href="http://ref.x86asm.net/coder64.html#x48"&gt;0x48&lt;/a&gt; we see that
this is a prefix instruction that turns on 64-bit mode for the
instruction. Some instructions like &lt;code&gt;pop&lt;/code&gt; and
&lt;code&gt;push&lt;/code&gt; don't need this prefix to be in 64-bit mode. In any
case, this just means we'll have to have a size flag that switches
from 32-bit to 64-bit mode on seeing this instruction. This flag will
be reset each time we start reading an instruction.&lt;/p&gt;
&lt;p&gt;To deal with prefixes in general we'll loop through bytes when
processing an instruction until we no longer see a prefix bytes. As we
see prefix bytes we'll handle them accordingly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefixBytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mh"&gt;0x48&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;widthPrefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;isPrefixByte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefixByte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefixBytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prefixByte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;isPrefixByte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isPrefixByte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;// 64 bit prefix signifier&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;widthPrefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;hbdebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;prog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown prefix instruction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x58&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// push&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Moving past this prefix we get to
&lt;a href="http://ref.x86asm.net/coder64.html#x89"&gt;0x89&lt;/a&gt;. This instruction is
for copying one register into another. The register operands are
&lt;a href="http://www.c-jump.com/CIS77/CPU/x86/X77_0270_modrm_byte.htm"&gt;encoded in the second
byte&lt;/a&gt;,
&lt;code&gt;0xe5&lt;/code&gt;, called the ModR/M byte. Pulling out the two
registers is just a matter of shifting and bitmasking the right 3 bits
for each.&lt;/p&gt;
&lt;p&gt;With this knowledge we can expand the instruction handling code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x58&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// push&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;regvalue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;writeBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;regvalue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// mov r/m16/32/64, r/m16/32/64&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;inb2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;rhs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;inb2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;b00111000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;lhs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inb2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;b111&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lhs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;hbdebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;prog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Unknown instruction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Try emulating &lt;code&gt;a.out&lt;/code&gt; again now. It will panic on the next
unknown instruction, &lt;code&gt;0xb8&lt;/code&gt;. From &lt;code&gt;objdump&lt;/code&gt;
disassembly we see this is another &lt;code&gt;mov&lt;/code&gt; instruction.&lt;/p&gt;
&lt;p&gt;Hurray! There are apparently multiple ways the same instruction can be
encoded. Looking it up in the opcode table, we see
&lt;a href="http://ref.x86asm.net/coder64.html#xB8"&gt;0xB8&lt;/a&gt; is for when the value
to be copied is a literal number. The operand will be 32-bits, or four
bytes, presumably because it doesn't have the &lt;code&gt;0x48&lt;/code&gt;
prefix.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// helper for converting up to 8 bytes into a single integer&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xB8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xC0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// mov r16/32/64, imm16/32/64&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;lreg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xB8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;widthPrefix&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;widthPrefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lreg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Two more instructions to go: &lt;code&gt;pop&lt;/code&gt; and &lt;code&gt;ret&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="a-terminal-debugger"&gt;A terminal debugger&lt;/h3&gt;&lt;p&gt;Taking a break for a moment, our system is already too complex to
understand. It would be helpful to have a REPL so we can step through
instructions and print register and memory values.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;resolveDebuggerValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;registerMap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dval&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0x&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dval&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ParseUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dval&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strconv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ParseUint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;repl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;go-amd64-emulator REPL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;help&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`commands:&lt;/span&gt;
&lt;span class="s"&gt;    s/step:             continue to next instruction&lt;/span&gt;
&lt;span class="s"&gt;    r/registers [$reg]:     print all register values or just $reg&lt;/span&gt;
&lt;span class="s"&gt;    d/decimal:          toggle hex/decimal printing&lt;/span&gt;
&lt;span class="s"&gt;    m/memory $from $count:      print memory values starting at $from until $from+$count&lt;/span&gt;
&lt;span class="s"&gt;    h/help:             print this`&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;help&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bufio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewScanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;intFormat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;gt; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;h&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fallthrough&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;help&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fallthrough&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;memory&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Invalid arguments: m/memory $from $to; use hex (0x10), decimal (10), or register name (rsp)&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolveDebuggerValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolveDebuggerValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;hbdebug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;memory[&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;intFormat&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;intFormat&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;d&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fallthrough&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;decimal&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;intFormat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;intFormat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0x%x&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Numbers displayed as hex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;intFormat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%d&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Numbers displayed as decimal&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fallthrough&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;registers&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;registerMap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;registerMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%s:\t&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;intFormat&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;fallthrough&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;step&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let's try it out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;--debug
go-amd64-emulator&lt;span class="w"&gt; &lt;/span&gt;REPL
commands:
&lt;span class="w"&gt;        &lt;/span&gt;s/step:&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;next&lt;span class="w"&gt; &lt;/span&gt;instruction
&lt;span class="w"&gt;        &lt;/span&gt;r/registers&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$reg&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt;             &lt;/span&gt;print&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;register&lt;span class="w"&gt; &lt;/span&gt;values&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;just&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$reg&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;d/decimal:&lt;span class="w"&gt;                      &lt;/span&gt;toggle&lt;span class="w"&gt; &lt;/span&gt;hex/decimal&lt;span class="w"&gt; &lt;/span&gt;printing
&lt;span class="w"&gt;        &lt;/span&gt;m/memory&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$count&lt;/span&gt;:&lt;span class="w"&gt;          &lt;/span&gt;print&lt;span class="w"&gt; &lt;/span&gt;memory&lt;span class="w"&gt; &lt;/span&gt;values&lt;span class="w"&gt; &lt;/span&gt;starting&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;until&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$from&lt;/span&gt;+&lt;span class="nv"&gt;$count&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;h/help:&lt;span class="w"&gt;                         &lt;/span&gt;print&lt;span class="w"&gt; &lt;/span&gt;this
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;r
rax:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rcx:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rdx:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rbx:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rsp:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;41943040&lt;/span&gt;
rbp:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rsi:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rdi:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r8:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r9:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r10:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r11:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r12:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r13:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r14:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r15:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rip:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;4198662&lt;/span&gt;
rflags:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;m&lt;span class="w"&gt; &lt;/span&gt;rip&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;
memory&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4198662&lt;/span&gt;:4198672&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e5&lt;span class="w"&gt; &lt;/span&gt;b8&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;5d
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;s
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;m&lt;span class="w"&gt; &lt;/span&gt;rip&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;
memory&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="m"&gt;4198663&lt;/span&gt;:4198673&lt;span class="o"&gt;]&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;48&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;89&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;e5&lt;span class="w"&gt; &lt;/span&gt;b8&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;5d&lt;span class="w"&gt; &lt;/span&gt;c3
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;r
rax:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rcx:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rdx:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rbx:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rsp:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;41943032&lt;/span&gt;
rbp:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rsi:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rdi:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r8:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r9:&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r10:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r11:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r12:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r13:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r14:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
r15:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
rip:&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;4198663&lt;/span&gt;
rflags:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;^D
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can inspect the system interactively.&lt;/p&gt;
&lt;h3 id="pop"&gt;pop&lt;/h3&gt;&lt;p&gt;Reemersing in the state of things, we now panic on &lt;code&gt;0x5D&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out
prog:&lt;span class="w"&gt; &lt;/span&gt;5d&lt;span class="w"&gt; &lt;/span&gt;c3&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;66&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;2e&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt; &lt;/span&gt;1f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
panic:&lt;span class="w"&gt; &lt;/span&gt;Unknown&lt;span class="w"&gt; &lt;/span&gt;instruction

goroutine&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;running&lt;span class="o"&gt;]&lt;/span&gt;:
main.&lt;span class="o"&gt;(&lt;/span&gt;*cpu&lt;span class="o"&gt;)&lt;/span&gt;.loop&lt;span class="o"&gt;(&lt;/span&gt;0xc000098ae0,&lt;span class="w"&gt; &lt;/span&gt;0x2800000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:219&lt;span class="w"&gt; &lt;/span&gt;+0x2c5
main.&lt;span class="o"&gt;(&lt;/span&gt;*cpu&lt;span class="o"&gt;)&lt;/span&gt;.run&lt;span class="o"&gt;(&lt;/span&gt;0xc000098ae0,&lt;span class="w"&gt; &lt;/span&gt;0xc000098ab0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:231&lt;span class="w"&gt; &lt;/span&gt;+0xac
created&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;main.main
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:358&lt;span class="w"&gt; &lt;/span&gt;+0x286
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looking &lt;a href="http://ref.x86asm.net/coder64.html#x5D"&gt;this up&lt;/a&gt; we see this
is part of &lt;code&gt;58+r&lt;/code&gt;, &lt;code&gt;pop&lt;/code&gt;. Similar to
&lt;code&gt;push&lt;/code&gt; we subtract &lt;code&gt;0x58&lt;/code&gt; from the byte to get
the register to pop onto. The stack operation is the reverse of
&lt;code&gt;push&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryReturnAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x58&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// pop&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;lhs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x58&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lhs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Build and run for the final panic:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out
prog:&lt;span class="w"&gt; &lt;/span&gt;c3&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;66&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;2e&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt; &lt;/span&gt;1f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;84&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
panic:&lt;span class="w"&gt; &lt;/span&gt;Unknown&lt;span class="w"&gt; &lt;/span&gt;instruction

goroutine&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;running&lt;span class="o"&gt;]&lt;/span&gt;:
main.&lt;span class="o"&gt;(&lt;/span&gt;*cpu&lt;span class="o"&gt;)&lt;/span&gt;.loop&lt;span class="o"&gt;(&lt;/span&gt;0xc000060c30,&lt;span class="w"&gt; &lt;/span&gt;0x2800000&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:224&lt;span class="w"&gt; &lt;/span&gt;+0x345
main.&lt;span class="o"&gt;(&lt;/span&gt;*cpu&lt;span class="o"&gt;)&lt;/span&gt;.run&lt;span class="o"&gt;(&lt;/span&gt;0xc000060c30,&lt;span class="w"&gt; &lt;/span&gt;0xc000060c00&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:236&lt;span class="w"&gt; &lt;/span&gt;+0xac
created&lt;span class="w"&gt; &lt;/span&gt;by&lt;span class="w"&gt; &lt;/span&gt;main.main
&lt;span class="w"&gt;        &lt;/span&gt;/home/phil/tmp/goamd/main.go:363&lt;span class="w"&gt; &lt;/span&gt;+0x286
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="ret"&gt;ret&lt;/h3&gt;&lt;p&gt;Looking up &lt;a href="http://ref.x86asm.net/coder64.html#xC3"&gt;0xC3&lt;/a&gt; we see that
it is indeed &lt;code&gt;ret&lt;/code&gt;. This function's responsibilty is to pop
the stack onto rip, jumping back to caller.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;inb1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0xC3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ret&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;retAddress&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rsp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;retAddress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Build and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="m"&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we modify &lt;code&gt;tests/simple.c&lt;/code&gt;?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;tests/simple.c
int&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;254&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;tests/simple.c
$&lt;span class="w"&gt; &lt;/span&gt;./main&lt;span class="w"&gt; &lt;/span&gt;a.out&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="m"&gt;254&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not bad!&lt;/p&gt;
&lt;h3 id="process-and-next-steps"&gt;Process and next steps&lt;/h3&gt;&lt;p&gt;Getting this far took a lot of trial and error, much of it hidden in
this post. Setting up the REPL was critical to debugging mistakes. But
aggressively unit testing would probably have been similarly
fruitful. In the end, the most bug-prone aspects are basic arithmetic
(off by one errors and converting bytes to/from integers). The part
that's not terribly hard is actually interpreting instructions! But
it's made easier by greatly simplifying the problem and ignoring
legion cases.&lt;/p&gt;
&lt;p&gt;Along the way it would have been helpful to also disassemble so that
instead of just dumping memory at the instruction pointer we print the
instructions we thought we were going to process. That may be a next
goal.&lt;/p&gt;
&lt;p&gt;Otherwise the typical goals are around getting syscall support,
function call support, and porting these simple examples to Windows
and macOS for the experience.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Here's take two on writing an emulator for linux/amd64 in Go.  This time we're starting with ELF binaries, but still ignoring libc and jumping straight to main.&lt;a href="https://t.co/A87r2RY21c"&gt;https://t.co/A87r2RY21c&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1332111601814691840?ref_src=twsrc%5Etfw"&gt;November 26, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Thu, 26 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/emulating-amd64-starting-with-elf.html</guid></item><item><title>What is more short-sighted? UBI, or certain critics of it?</title><link>https://stop.zona-m.net/2020/11/what-is-more-short-sighted-ubi-or-certain-critics-of-it/</link><description>&lt;p&gt;What is the PURPOSE of life, again?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 25 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/what-is-more-short-sighted-ubi-or-certain-critics-of-it/</guid></item><item><title>Reasons why SELECT * is bad for SQL performance</title><link>https://tanelpoder.com/posts/reasons-why-select-star-is-bad-for-sql-performance/</link><description>&lt;p&gt;Here&amp;rsquo;s a list of reasons why &lt;code&gt;SELECT *&lt;/code&gt; is bad for SQL performance, assuming that your application doesn&amp;rsquo;t actually need all the columns. When I write production code, I explicitly specify the columns of interest in the select-list (projection), not only for performance reasons, but also for application reliability reasons. For example, will your application&amp;rsquo;s data processing code suddenly break when a new column has been added or the column order has changed in a table?&lt;/p&gt;</description><author>Tanel Poder Blog</author><pubDate>Wed, 25 Nov 2020 05:14:58 GMT</pubDate><guid isPermaLink="true">https://tanelpoder.com/posts/reasons-why-select-star-is-bad-for-sql-performance/</guid></item><item><title>Mexico uses asymmetric encryption for university diplomas and taxes.</title><link>https://danielsada.tech/blog/mexico-technology/</link><description>I recently graduated, and in order to get my official graduation title I needed to get my private and public key from the government. That&amp;rsquo;s right, you go to the government&amp;rsquo;s office, certify that you are who you are, and you&amp;rsquo;ll get a private and public key in an USB key from the government which you can use to do all your bureaucracy.
You also get a TaxID which is comprised of</description><author>Daniel Sada Caraveo | Developer Productivity &amp;amp; Culture</author><pubDate>Wed, 25 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://danielsada.tech/blog/mexico-technology/</guid></item><item><title>2020–11–25: New multi-distro and p-boot released, WiFi power savings</title><link>https://xnux.eu/log/#025</link><author>megi's PinePhone Development Log</author><pubDate>Wed, 25 Nov 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#025</guid></item><item><title>Starlink? All will be well</title><link>https://stop.zona-m.net/2020/11/starlink-all-will-be-well/</link><description>&lt;p&gt;If they only answer SOME people.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 24 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/starlink-all-will-be-well/</guid></item><item><title>AoC</title><link>https://evilcookie.de/aoc.html</link><description/><author>blog</author><pubDate>Tue, 24 Nov 2020 14:09:39 GMT</pubDate><guid isPermaLink="true">https://evilcookie.de/aoc.html</guid></item><item><title>Fixing Race Conditions in React with useEffect</title><link>https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect</link><description>If you're using useEffect to fetch data, chances are you've either run into a race condition, or have one without realising it. Let's learn how to fix them in this article.</description><author>Max Rozen</author><pubDate>Tue, 24 Nov 2020 11:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect</guid></item><item><title>The Best Garlic Chilli Prawns 🌶🍤</title><link>https://blog.cetinich.net/content/food/2021-garlic-chilli-prawns/</link><description>These are mediterranean style garlic chilli prawns, normally I double
the garlic and chilli for this recipe and the oil is so good to dip with
warm fresh crusty bread.</description><author>Brent's Blog</author><pubDate>Tue, 24 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/food/2021-garlic-chilli-prawns/</guid></item><item><title>Zettelkasten Updates...</title><link>http://evantravers.com/articles/2020/11/23/zettelkasten-updates/</link><description>&lt;p&gt;Since I wrote my last post… there has been &lt;em&gt;so&lt;/em&gt; much motion in the knowledge-management / note-taking space, largely due to the exploding popularity of &lt;a href="https://roamresearch.com/"&gt;Roam Research&lt;/a&gt;. Many apps have adopted Roam-like features like &lt;a href="https://www.macstories.net/ios/note-linking-in-bear-expands-to-include-section-linking/"&gt;linking to blocks&lt;/a&gt;, &lt;a href="https://docs.getdrafts.com/docs/drafts/cross-linking.html"&gt;wiki links&lt;/a&gt;, or graph views.&lt;/p&gt;
&lt;p&gt;This has greatly excited me to learn and code more tooling for this kind of thinking … but it has also had a paralyzing effect. There's &lt;em&gt;so&lt;/em&gt; many more options out there for creating this kind of networked knowledge management, whether you call it a wiki, a zettelkasten, or whatever. Like many I don't know exactly where to turn.&lt;/p&gt;
&lt;p&gt;For the (three of you) that read this and care, here's what I'm looking for as I watch this next wave of note-taking apps. I'm attempting to balance convenient accessibility and complete ownership… on a budget. :P&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#i-still-want-to-own-my-content" id="i-still-want-to-own-my-content"&gt;&lt;/a&gt;I still want to own my content.&lt;/h2&gt;
&lt;p&gt;This is the main reason that Roam (however wonderful!) is not an option for me. I want to be able to own, export, transfer, and transform my content however I wish. Part of this is because I'm persnickety, part of it is because I'm a programmer. It would be foolish to give up my ability to program/script against the notes that I plan to spend a life on.&lt;/p&gt;
&lt;p&gt;I also want the file format to &amp;quot;work&amp;quot; as a Zettelkasten independent of a particular app. A helpful thought: my system should still be usable when printed.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#markdown" id="markdown"&gt;&lt;/a&gt;Markdown&lt;/h3&gt;
&lt;p&gt;Markdown continues to be the way I write and store content. While it is frustrating &lt;a href="https://xkcd.com/927/"&gt;how many standards there are&lt;/a&gt;, markdown still is the best option for writing that I know of (unless you are a LaTeX fan, I suppose. Latechie? Latexan?)&lt;/p&gt;
&lt;p&gt;Being a bare text file, Markdown does present the problem of &amp;quot;where do the images/files go?&amp;quot; But that doesn't worry me too much… as long as I have a service or server that supports URLs. Anything is automatable.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#metadata-within-the-content-of-the-file" id="metadata-within-the-content-of-the-file"&gt;&lt;/a&gt;Metadata within the content of the file.&lt;/h3&gt;
&lt;p&gt;I &lt;em&gt;still&lt;/em&gt; believe in having &lt;a href="https://neuron.zettel.page/id.html"&gt;a stable ZK style ID&lt;/a&gt;. If there is unique ID (or UID) we can rename/retitle the file with low risk of irrevocably broken links.&lt;/p&gt;
&lt;p&gt;For example: I started a zettel thought around a particular Bible verse, but over time the thought changed from simply this one verse to a discussion of the &amp;quot;fear of the Lord.&amp;quot; If the title of the thought changes, does the file name? If the file name changes, what happens to all the links?&lt;/p&gt;
&lt;p&gt;Most knowledge management software solutions handle this using their internal database to update all the links in all the other files if the linked-to title/file name changes.&lt;/p&gt;
&lt;p&gt;I also am in favor of all metadata existing within the &lt;em&gt;body&lt;/em&gt; of the file. This way if I were to print my knowledge base it would &lt;em&gt;still&lt;/em&gt; work.&lt;/p&gt;
&lt;p&gt;This is &lt;em&gt;the&lt;/em&gt; sticky point for most of the solutions and applications that we are going to look at today.&lt;/p&gt;
&lt;p&gt;Trying to consider maximum future compatibility, there are the two changes from my original recommendation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use YAML style frontmatter instead of the multimarkdown spec.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;keywords&lt;/code&gt; instead of &lt;code&gt;tags&lt;/code&gt; to respect Pandoc.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(Optionally, you can change the filename structure to use spaces instead of &lt;a href="https://en.wikipedia.org/wiki/Letter_case#Special_case_styles"&gt;kebab-case&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Filename:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-plaintext" tabindex="0"&gt;&lt;div class="line"&gt;202011182014 Title of the note.md
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Content:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-plaintext" tabindex="0"&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;id: 202011182014
&lt;/div&gt;&lt;div class="line"&gt;title: Title of the note
&lt;/div&gt;&lt;div class="line"&gt;keywords:
&lt;/div&gt;&lt;div class="line"&gt;  - #still
&lt;/div&gt;&lt;div class="line"&gt;  - #use
&lt;/div&gt;&lt;div class="line"&gt;  - #hashtags
&lt;/div&gt;&lt;div class="line"&gt;---
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;Body of the note should be a single thought, complete and fully formed… but not too big.
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;References and links can come below.
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;- [baseline Zettelkasten](https://zettelkasten.de/posts/baseline-zettelkasten-software-reviews/)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;a class="anchor" href="#apps-and-projects-im-watching" id="apps-and-projects-im-watching"&gt;&lt;/a&gt;Apps and projects I'm watching…&lt;/h2&gt;
&lt;p&gt;For a bit there, I was trying to write my own system using &lt;a href="https://github.com/evantravers/smz"&gt;shell scripts&lt;/a&gt; and &lt;a href="https://github.com/evantravers/smz.vim"&gt;vim&lt;/a&gt;. I'm still messing with that, but I'm paying attention to a couple readily available projects that seem to align with my goals:&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#obsidian" id="obsidian"&gt;&lt;/a&gt;&lt;a href="https://obsidian.md/"&gt;Obsidian&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is been &lt;a href="https://joshwin.imprint.to/post/how-i-use-obsidian-to-manage-my-goals-tasks-notes-and-software-development-knowledge-base"&gt;a favorite of many&lt;/a&gt;, and I really &lt;em&gt;really&lt;/em&gt; like it. It checks &lt;strong&gt;nearly&lt;/strong&gt; all of the boxes: It's got a nice interface, graph view, ongoing development, and &lt;em&gt;markdown&lt;/em&gt;… and a growing plugin community that is &lt;em&gt;very&lt;/em&gt; strong. The &lt;a href="https://obsidian.md/community"&gt;discord&lt;/a&gt; is active and really helpful.&lt;/p&gt;
&lt;p&gt;Obsidian does have support for both markdown and YAML front-matter. It works for 100% of the things I need, but not 100% of its feature-set works for file names that include the ZK ID.&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;really&lt;/em&gt; shouldn't stop me from using it… it supports &lt;em&gt;everything&lt;/em&gt; I could hope to implement myself. I mostly have been holding out to see if a convention supporting stable Zettelkasten-style IDs will be settled on… but if you don't really care about this, you should probably just start using Obsidian.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#neuron" id="neuron"&gt;&lt;/a&gt;&lt;a href="https://neuron.zettel.page/"&gt;Neuron&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I &lt;em&gt;really&lt;/em&gt; like what I see in Neuron. It's &lt;a href="https://neuron.zettel.page/philosophy.html"&gt;philosophy&lt;/a&gt; matches up with what I would like and its shell-script approach allows there to be multiple editors like &lt;a href="https://github.com/felko/neuron-mode"&gt;emacs&lt;/a&gt;, &lt;a href="https://github.com/fiatjaf/neuron.vim"&gt;vim&lt;/a&gt;, and &lt;a href="https://github.com/svsool/vscode-memo#memo"&gt;VS Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I would &lt;em&gt;really&lt;/em&gt; like to try it out (it seems nearly perfect for me!), but it has a really strange install method that is prohibitively hard on OS X. It looks like there is some &lt;a href="https://github.com/srid/neuron/issues/307"&gt;recent motion&lt;/a&gt; on it though, so maybe I'll get to test-drive it soon.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#foam" id="foam"&gt;&lt;/a&gt;&lt;a href="https://github.com/foambubble/foam"&gt;Foam&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Foam is the most popular (that I can see) of the multitude of plugins for VS Code.&lt;/p&gt;
&lt;p&gt;If you use VS Code daily as your editor, something like this makes a lot of sense. I still am hoping for something cross-form, but whatever. It's an impressive plugin.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#logseq" id="logseq"&gt;&lt;/a&gt;&lt;a href="https://logseq.com/"&gt;Logseq&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Logseq is an interesting option… it's entirely web-based, but connects to your GitHub. This means you could interact with it using any desktop editor of your choice… but you could also work on it on a mobile device or iPad natively in the browser, as long as you have an internet connection.&lt;/p&gt;
&lt;p&gt;Basically, logseq is a roam research clone that stores the data as markdown files on your github. Pretty cool.&lt;/p&gt;
&lt;p&gt;Even if you don't use it as your primary editor, you could use this to work on a Simple Markdown Zettelkasten from mobile.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#vanilla-vim--emacs" id="vanilla-vim--emacs"&gt;&lt;/a&gt;Vanilla Vim / Emacs&lt;/h3&gt;
&lt;p&gt;There's nothing stopping you from doing this all by scratch. I've started down &lt;a href="https://github.com/evantravers/smz"&gt;this path a little bit with the help of much smarter people&lt;/a&gt;. At the moment I'm not actively pursuing it… I want to make sure my file format / data structure is more finalized. There are folks with similar but &lt;a href="https://github.com/sirupsen/zk"&gt;much more mature solutions&lt;/a&gt;. I fear I may not have the time to learn lua/vimscript fast enough. :P&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#where-does-that-leave-me" id="where-does-that-leave-me"&gt;&lt;/a&gt;Where does that leave me?&lt;/h2&gt;
&lt;p&gt;I'm in the middle of &lt;a href="https://github.com/evantravers/plaintext-migration/tree/13fb162a7718c1564b06b7e423661788844f6151"&gt;writing a transition script&lt;/a&gt; to transform my existing plaintext notes, book notes, and baby zettelkasten (V1!) into the &amp;quot;new&amp;quot; format with YAML metadata. I haven't given it the attention it deserves, so now I have the old zettelkasten, new notes, old untransformed plaintext notes… I put myself in a place where I have notes &lt;em&gt;everywhere&lt;/em&gt; in at least &lt;em&gt;six&lt;/em&gt; formats. It's a problem.&lt;/p&gt;
&lt;p&gt;Over the next few days, I'm probably going to resume the Sisyphean effort of working on my notes… (I last time I counted there's about 2k files in my untransformed folder!) but I thought I'd post what I'm thinking heading into it all.&lt;/p&gt;
&lt;p&gt;If anyone is further down this path, I'd love to hear about it. It's a great time to be refactoring and rethinking your note taking options... just don't get stuck mid-transition. 🤮&lt;/p&gt;</description><author>trv.rs</author><pubDate>Mon, 23 Nov 2020 22:31:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/11/23/zettelkasten-updates/</guid></item><item><title>Artificial Intelligence is like Jessica Rabbit</title><link>https://stop.zona-m.net/2020/11/artificial-intelligence-is-like-jessica-rabbit/</link><description>&lt;p&gt;It&amp;rsquo;s not bad. WE just draw it that way.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 23 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/artificial-intelligence-is-like-jessica-rabbit/</guid></item><item><title>EXWM on Chrome OS</title><link>https://reticulated.net/posts/exwmchrome/</link><description>How to use EXWM on Chrome OS</description><author>Reticulated</author><pubDate>Mon, 23 Nov 2020 02:08:33 GMT</pubDate><guid isPermaLink="true">https://reticulated.net/posts/exwmchrome/</guid></item><item><title>Pulled pork recipe</title><link>https://xenodium.com/pulled-pork-recipe</link><description>&lt;p&gt;Made pulled pork a couple of times. Freestyled a bit. No expert here, but result was yummie.&lt;/p&gt;
&lt;h2&gt;Grind/blend spices&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2 teaspoons smoked paprika&lt;/li&gt;
&lt;li&gt;2 teaspoons cumin seeds&lt;/li&gt;
&lt;li&gt;2 teaspoons whole pepper corn mix&lt;/li&gt;
&lt;li&gt;2 teaspoons chilly flakes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If spices are whole, grind or blend them. Set aside.&lt;/p&gt;
&lt;p&gt;Optionally: Substitute 1 teaspoon of paprika with chipotle pepper.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/pulled-pork-recipe/grind.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/pulled-pork-recipe/ground.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;Mix into a paste&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2 tablespoons honey&lt;/li&gt;
&lt;li&gt;1 teaspoon of dijon mustard&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mix the honey, mustard, and previous spices into a paste.&lt;/p&gt;
&lt;h2&gt;Rub the mix in&lt;/h2&gt;
&lt;p&gt;Rub mix thoroughly into the pork shoulder.&lt;/p&gt;
&lt;h2&gt;Bake (1 hour)&lt;/h2&gt;
&lt;p&gt;Place in a pot (lid off) and bake in the oven for 1 hour at 200 °C.&lt;/p&gt;
&lt;h2&gt;Add liquids&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1/2 cup of water.&lt;/li&gt;
&lt;li&gt;4 tablespoons of apple cider vinegar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add liquids to pot.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/pulled-pork-recipe/almost.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;Bake (3-5 hours)&lt;/h2&gt;
&lt;p&gt;Bake between 3 to 5 hours 150 °C. Check every hour or two. Does the meat fall easily when spread with two forks? If so, you're done.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/pulled-pork-recipe/out.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;Pull apart&lt;/h2&gt;
&lt;p&gt;Use two forks to pull the meat apart.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/pulled-pork-recipe/final.jpg" /&gt;&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Mon, 23 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/pulled-pork-recipe</guid></item><item><title>How to: Backup a Mastodon instance</title><link>https://nutcroft.mataroa.blog/blog/how-to-backup-a-mastodon-instance/</link><description>&lt;p&gt;I recently started a new Mastodon instance and went through the joy of setting up a Mastodon server. It was easier than expected, the process is very streamlined and detailed in the docs: &lt;a href="https://docs.joinmastodon.org/admin/prerequisites/"&gt;https://docs.joinmastodon.org/admin/prerequisites/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But, of course, the backup process depends on your setup. The docs here, too, are very helpful—in the sense of what you need to backup: &lt;a href="https://docs.joinmastodon.org/admin/backups/"&gt;https://docs.joinmastodon.org/admin/backups/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My setup is based on a simple VPS, with AWS S3 for backup storage, and &lt;a href="https://healthchecks.io/"&gt;Healthchecks.io&lt;/a&gt; for schedule monitoring. Except for the environment secrets, which is just a static file and easily backup-able, the others are postgres, redis, and uploaded files.&lt;/p&gt;
&lt;p&gt;This is the full &lt;code&gt;backup-mastodon.sh&lt;/code&gt; script:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;#!/bin/bash&lt;/span&gt;

&lt;span style="color: #93A1A1;"&gt;# postgres&lt;/span&gt;
&lt;span style="color: #268BD2;"&gt;echo&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;Postgres...&amp;quot;&lt;/span&gt;
runuser&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-l&lt;span style="color: #657B83;"&gt; &lt;/span&gt;mastodon&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-c&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;'cd ~ &amp;amp;&amp;amp; pg_dump -Fc mastodon_production -f postgres.dump'&lt;/span&gt;
aws&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3&lt;span style="color: #657B83;"&gt; &lt;/span&gt;cp&lt;span style="color: #657B83;"&gt; &lt;/span&gt;/home/mastodon/postgres.dump&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3://sirodohtbucket/backup-postgres/&lt;span style="color: #859900;"&gt;$(&lt;/span&gt;date&lt;span style="color: #657B83;"&gt; &lt;/span&gt;--iso-8601&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;seconds&lt;span style="color: #859900;"&gt;)&lt;/span&gt;/

&lt;span style="color: #93A1A1;"&gt;# redis&lt;/span&gt;
&lt;span style="color: #268BD2;"&gt;echo&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;Redis...&amp;quot;&lt;/span&gt;
aws&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3&lt;span style="color: #657B83;"&gt; &lt;/span&gt;cp&lt;span style="color: #657B83;"&gt; &lt;/span&gt;/var/lib/redis/dump.rdb&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3://sirodohtbucket/backup-redis/&lt;span style="color: #859900;"&gt;$(&lt;/span&gt;date&lt;span style="color: #657B83;"&gt; &lt;/span&gt;--iso-8601&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;seconds&lt;span style="color: #859900;"&gt;)&lt;/span&gt;/

&lt;span style="color: #93A1A1;"&gt;# uploads&lt;/span&gt;
&lt;span style="color: #268BD2;"&gt;echo&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;Uploads...&amp;quot;&lt;/span&gt;
&lt;span style="color: #268BD2;"&gt;now&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #859900;"&gt;$(&lt;/span&gt;date&lt;span style="color: #657B83;"&gt; &lt;/span&gt;--iso-8601&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;seconds&lt;span style="color: #859900;"&gt;)&lt;/span&gt;

runuser&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-l&lt;span style="color: #657B83;"&gt; &lt;/span&gt;mastodon&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-c&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;'cd ~ &amp;amp;&amp;amp; tar -czvf accounts.tar.gz /home/mastodon/live/public/system/accounts/'&lt;/span&gt;
aws&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3&lt;span style="color: #657B83;"&gt; &lt;/span&gt;cp&lt;span style="color: #657B83;"&gt; &lt;/span&gt;/home/mastodon/accounts.tar.gz&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3://sirodohtbucket/backup-uploads/&lt;span style="color: #268BD2;"&gt;$now&lt;/span&gt;/

runuser&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-l&lt;span style="color: #657B83;"&gt; &lt;/span&gt;mastodon&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-c&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;'cd ~ &amp;amp;&amp;amp; tar -czvf media_attachments.tar.gz /home/mastodon/live/public/system/media_attachments/'&lt;/span&gt;
aws&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3&lt;span style="color: #657B83;"&gt; &lt;/span&gt;cp&lt;span style="color: #657B83;"&gt; &lt;/span&gt;/home/mastodon/media_attachments.tar.gz&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3://sirodohtbucket/backup-uploads/&lt;span style="color: #268BD2;"&gt;$now&lt;/span&gt;/

runuser&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-l&lt;span style="color: #657B83;"&gt; &lt;/span&gt;mastodon&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-c&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;'cd ~ &amp;amp;&amp;amp; tar -czvf site_uploads.tar.gz /home/mastodon/live/public/system/site_uploads/'&lt;/span&gt;

aws&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3&lt;span style="color: #657B83;"&gt; &lt;/span&gt;cp&lt;span style="color: #657B83;"&gt; &lt;/span&gt;/home/mastodon/site_uploads.tar.gz&lt;span style="color: #657B83;"&gt; &lt;/span&gt;s3://sirodohtbucket/backup-uploads/&lt;span style="color: #268BD2;"&gt;$now&lt;/span&gt;/
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For postgres, we just use &lt;code&gt;pg_dump&lt;/code&gt; with the &lt;a href="https://www.postgresql.org/docs/9.6/app-pgdump.html"&gt;postgres custom format&lt;/a&gt; &lt;code&gt;-Fc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For redis, we just copy the periodically disk-written &lt;a href="https://redis.io/topics/persistence"&gt;database dump&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For the uploaded files, we archive three directories &lt;code&gt;accounts/&lt;/code&gt;, &lt;code&gt;media_attachments/&lt;/code&gt;, and &lt;code&gt;site_uploads/&lt;/code&gt; and then upload them to S3 with the &lt;code&gt;aws s3 copy&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;For all commands we use &lt;code&gt;runuser&lt;/code&gt; so that they run as if the &lt;code&gt;mastodon&lt;/code&gt; user is executing them.&lt;/li&gt;
&lt;li&gt;Also, we upload them into datetime directories nested in the bucket, with &lt;code&gt;date --iso-8601=seconds&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As for the crontab entry, we follow the &lt;a href="https://healthchecks.io/docs/bash/"&gt;Healthchecks docs&lt;/a&gt; on the dot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 3 * * * /home/sirodoht/backup-mastodon.sh &amp;amp;&amp;amp; curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/f880a11a-4cd8-4b64-98a2-20a510cd429f
&lt;/code&gt;&lt;/pre&gt;</description><author>nutcroft</author><pubDate>Mon, 23 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/how-to-backup-a-mastodon-instance/</guid></item><item><title>Does iOS 14 protect your privacy?</title><link>https://www.gingerlime.com/2020/does-ios-14-protect-your-privacy/</link><description>&lt;p&gt;A few months ago I wrote a post: Does Apple care about your privacy? In the post, I looked at Apple&amp;#8217;s IDFA &amp;#8211; ID For Advertising, and how it&amp;#8217;s abused by companies like Facebook and many more to track you. I believed then, and still believe now, that what Apple is doing is not ethical&amp;#8230;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://www.gingerlime.com/2020/does-ios-14-protect-your-privacy/"&gt;Does iOS 14 protect your privacy?&lt;/a&gt; appeared first on &lt;a href="https://www.gingerlime.com"&gt;Gingerlime&lt;/a&gt;.&lt;/p&gt;</description><author>Gingerlime</author><pubDate>Sun, 22 Nov 2020 20:12:24 GMT</pubDate><guid isPermaLink="true">https://www.gingerlime.com/2020/does-ios-14-protect-your-privacy/</guid></item><item><title>A quick look at Touch Handling APIs in Game Engines</title><link>https://ericonotes.blogspot.com/2020/11/a-quick-look-at-touch-handling-apis-in.html</link><description>&lt;p&gt;&lt;/p&gt;&lt;div style="text-align: left;"&gt;Since the iPhone happened in 2007, touch input has been at the forefront of human interaction with machines. But Game Engines have existed for a reasonable long life, preceding the mobile boom. Touch as a means of interaction with the game world in engines is provided in many ways. Below, we are going to look at different touch APIs to see how they have been provided to enable gaming on our phones. Tilt, camera, and other sensors are going to be ignored so we can focus on touch.&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div style="text-align: left;"&gt;&lt;hr /&gt;
&lt;h3&gt;&lt;/h3&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;h3&gt;Browser - Gold standard of Touch APIs&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch_events" rel="nofollow"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Touch_events&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent" rel="nofollow"&gt;https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Touch" rel="nofollow"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Touch&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The browser is not a "game engine" but there are games that run in browsers and it has solid handling of touch input that is used across devices every day in different ways. Mostly, though, they are handled through DOM elements and not directly. But let's look at how their direct handling can be done.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Browser handles 4 touch events:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;touch start: when the finger starts touching the browser content area&lt;/li&gt;&lt;li&gt;touch move: if the finger moves after touching the browser content area&lt;/li&gt;&lt;li&gt;touch end: whether the finger moved or not when it's released from the browser content area&lt;/li&gt;&lt;li&gt;touch cancel: when the browser tab changes, the finger goes to the browser UI or something else&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;In code, subscribing to these events requires passing the function 
that will handle them, and the boolean at the end gives information on how 
that event propagates. In the browser is also possible to specify the 
element that is susceptible to that event - these are not specifics for 
touch but give interesting functionalities.&lt;/p&gt;
&lt;div class="highlight highlight-source-js"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;function&lt;/span&gt; &lt;span class="pl-en"&gt;startup&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;var&lt;/span&gt; &lt;span class="pl-s1"&gt;el&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-smi"&gt;document&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;getElementById&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"canvas"&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-s1"&gt;el&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;addEventListener&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"touchstart"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;handleStart&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;false&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-s1"&gt;el&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;addEventListener&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"touchend"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;handleEnd&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;false&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-s1"&gt;el&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;addEventListener&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"touchcancel"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;handleCancel&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;false&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-s1"&gt;el&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-en"&gt;addEventListener&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;"touchmove"&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;handleMove&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-c1"&gt;false&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each event passes an array of &lt;code&gt;Touch&lt;/code&gt; elements, each with the following parameters: &lt;code&gt;identifier&lt;/code&gt;, &lt;code&gt;clientX&lt;/code&gt;, &lt;code&gt;clientY&lt;/code&gt;, &lt;code&gt;pageX&lt;/code&gt;, &lt;code&gt;pageY&lt;/code&gt;, &lt;code&gt;screenX&lt;/code&gt;, &lt;code&gt;screenY&lt;/code&gt;, &lt;code&gt;target&lt;/code&gt;.
 More elements are available experimentally depending on the browser. 
The identifier property is a unique integer for each touch and remains 
consistent for each event during the duration of each finger's contact 
with the surface.&lt;/p&gt;
&lt;p&gt;Desktop browsers, even when a touch screen is available, can disable these events. A different API for &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events" rel="nofollow"&gt;Pointer Events&lt;/a&gt; exists and is recommended to use instead, and mixes Mouse Input, Touch input, and Pen input in the same event type.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Unity - The most complete API&lt;br /&gt;&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://docs.unity3d.com/ScriptReference/Touch.html" rel="nofollow"&gt;https://docs.unity3d.com/ScriptReference/Touch.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;In Unity, you can check &lt;code&gt;Input.touchCount&lt;/code&gt; to figure out how many touchpoints are available at that frame, and retrieve each one using &lt;code&gt;Input.GetTouch(i)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Each touch will have the following properties: &lt;code&gt;fingerId&lt;/code&gt;, &lt;code&gt;phase&lt;/code&gt;, &lt;code&gt;position&lt;/code&gt;, &lt;code&gt;deltaTime&lt;/code&gt;, &lt;code&gt;radius&lt;/code&gt;, &lt;code&gt;pressure&lt;/code&gt;, &lt;code&gt;rawPosition&lt;/code&gt;, &lt;code&gt;deltaPosition&lt;/code&gt;, &lt;code&gt;azimuthAngle&lt;/code&gt;, &lt;code&gt;altitudeAngle&lt;/code&gt;, &lt;code&gt;maximumPossiblePressure&lt;/code&gt;, &lt;code&gt;radiusVariance&lt;/code&gt; and &lt;code&gt;type&lt;/code&gt; (whether a touch was of Direct, Indirect (or remote), or Stylus type).&lt;/p&gt;
&lt;p&gt;The following are the possible touch phases: &lt;code&gt;Began&lt;/code&gt; (A finger touched the screen), &lt;code&gt;Moved&lt;/code&gt; (A finger moved on the screen), &lt;code&gt;Stationary&lt;/code&gt; (A finger is touching the screen but hasn't moved), &lt;code&gt;Ended&lt;/code&gt; (A finger was lifted from the screen. This is the final phase of a touch) or &lt;code&gt;Canceled&lt;/code&gt; (The system cancelled tracking for the touch).&lt;/p&gt;&lt;p&gt;Because both the index &lt;code&gt;i&lt;/code&gt; used in &lt;code&gt;Input.GetTouch(i)&lt;/code&gt; and &lt;code&gt;fingerId&lt;/code&gt; are integers, in some touch APIs that require passing a integer is not obvious what to use. For example  &lt;code&gt;EventSystem.current.IsPointerOverGameObject(int)&lt;/code&gt; actually requires passing a &lt;code&gt;touch.fingerId&lt;/code&gt;.&amp;nbsp;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;GameMaker - Multiple mouses approach!&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://docs2.yoyogames.com/index.html?page=source%2F_build%2F3_scripting%2F4_gml_reference%2Fcontrols%2Fdevice%20input%2Findex.html" rel="nofollow"&gt;https://docs2.yoyogames.com/index.html?page=source%2F_build%2F3_scripting%2F4_gml_reference%2Fcontrols%2Fdevice%20input%2Findex.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://docs2.yoyogames.com/source/_build/2_interface/1_editors/events/gesture_events.html" rel="nofollow"&gt;https://docs2.yoyogames.com/source/_build/2_interface/1_editors/events/gesture_events.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Game Maker has two separate APIs for dealing with touch. One is the same used for mouse input, but &lt;em&gt;&lt;strong&gt;they work the same way a PC would work if it had multiple mice attached&lt;/strong&gt;&lt;/em&gt;,
 which makes it different from what we have seen so far. You pass
 a device number that goes from 0 to n, where the number of devices 
available appears to be 5 - but I can't find the function that retrieves 
this number. Then 0 is the first finger that touched the screen (or the 
mouse in a computer) and 1 is the second one and so on, and you can use a
 function like &lt;code&gt;device_mouse_check_button(device, button);&lt;/code&gt; 
for retrieving if either the finger is pressed (by checking left click) 
or the mouse is clicking, with the device being this number that ranges from
 0 to n.&lt;/p&gt;
&lt;p&gt;The following functions are available: &lt;code&gt;device_mouse_check_button&lt;/code&gt;, &lt;code&gt;device_mouse_check_button_pressed&lt;/code&gt;, &lt;code&gt;device_mouse_check_button_released&lt;/code&gt;, &lt;code&gt;device_mouse_x&lt;/code&gt;, &lt;code&gt;device_mouse_y&lt;/code&gt;, &lt;code&gt;device_mouse_raw_x&lt;/code&gt;, &lt;code&gt;device_mouse_raw_y&lt;/code&gt;, &lt;code&gt;device_mouse_x_to_gui&lt;/code&gt;, &lt;code&gt;device_mouse_y_to_gui&lt;/code&gt;,&amp;nbsp; and &lt;code&gt;device_mouse_dbclick_enable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An additional, second API is available that gives access to all 
common touch gestures and makes them easy to use them. These include tap, 
drag, flick, pinch, and rotate finger events.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Godot - A minimal approach&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://docs.godotengine.org/en/stable/classes/class_inputeventscreentouch.html" rel="nofollow"&gt;https://docs.godotengine.org/en/stable/classes/class_inputeventscreentouch.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://docs.godotengine.org/en/stable/classes/class_touchscreenbutton.html" rel="nofollow"&gt;https://docs.godotengine.org/en/stable/classes/class_touchscreenbutton.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Godot has very lean InputEvent for screen touch, with three parameters: &lt;code&gt;index&lt;/code&gt; (a number from 0 to n identifying a finger), &lt;code&gt;position&lt;/code&gt; (x and y point in the screen), and a boolean named &lt;code&gt;pressed&lt;/code&gt; that is false when the finger is released.&lt;/p&gt;
&lt;p&gt;At the same time, since it's an InputEvent, it's can propagate 
through the SceneTree similar to how the browser allows handling 
events in elements in the DOM. This makes this simple approach still very powerful.&lt;/p&gt;
&lt;p&gt;Additionally, Godot also provides TouchScreenButton to design buttons meant to receive the touch of multiple fingers.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Unreal - Traditional with a timestamp&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://docs.unrealengine.com/en-US/API/Runtime/Engine/GameFramework/APlayerController/InputTouch/index.html" rel="nofollow"&gt;https://docs.unrealengine.com/en-US/API/Runtime/Engine/GameFramework/APlayerController/InputTouch/index.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://docs.unrealengine.com/en-US/BlueprintAPI/Input/TouchInput/index.html" rel="nofollow"&gt;https://docs.unrealengine.com/en-US/BlueprintAPI/Input/TouchInput/index.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Unreal TouchEvents are similar to the ones we have seen so far, the touch has a unique &lt;code&gt;Handle&lt;/code&gt; per finger, it happens at a &lt;code&gt;TouchLocation&lt;/code&gt; (x,y position), it has a &lt;code&gt;Type&lt;/code&gt; (similar to previous seen phase), it has a float indicating a &lt;code&gt;Force&lt;/code&gt; and it has a &lt;code&gt;DeviceTimestamp&lt;/code&gt; so you can precisely know at which time the specific touch occurred.&lt;/p&gt;
&lt;p&gt;A touch Type can be one of the following enum values &lt;code&gt;Began&lt;/code&gt;, &lt;code&gt;Moved&lt;/code&gt;, &lt;code&gt;Stationary&lt;/code&gt;, &lt;code&gt;ForceChanged&lt;/code&gt;, &lt;code&gt;FirstMove&lt;/code&gt;, &lt;code&gt;Ended&lt;/code&gt;, &lt;code&gt;NumTypes&lt;/code&gt; (used when iterating across other types).&lt;/p&gt;
&lt;p&gt;Overall, it's a very standard API. Events are also available for &lt;code&gt;On Input Touch Begin&lt;/code&gt;, &lt;code&gt;On Input Touch End&lt;/code&gt; and others.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Ogre3D - Very similar to SDL2&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://ogrecave.github.io/ogre/api/latest/struct_ogre_bites_1_1_touch_finger_event.html" rel="nofollow"&gt;https://ogrecave.github.io/ogre/api/latest/struct_ogre_bites_1_1_touch_finger_event.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Ogre3D provides TouchFingerEvent where each finger has a unique integer &lt;code&gt;fingerId&lt;/code&gt;, a &lt;code&gt;type&lt;/code&gt;, an &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; position, and additionally a &lt;code&gt;dx&lt;/code&gt; and &lt;code&gt;dy&lt;/code&gt; is provided for the delta of that position.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Love 2D - Polling and events and Lua&lt;br /&gt;&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://love2d.org/wiki/love.touch" rel="nofollow"&gt;https://love2d.org/wiki/love.touch&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://love2d.org/wiki/love.touch.getPosition" rel="nofollow"&gt;https://love2d.org/wiki/love.touch.getPosition&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://love2d.org/wiki/love.touchpressed" rel="nofollow"&gt;https://love2d.org/wiki/love.touchpressed&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Love2D allows to both poll for the touch on an engine update or to use a function to work with touch events.&lt;/p&gt;
&lt;p&gt;When polling, &lt;code&gt;love.touch.getTouches()&lt;/code&gt; retrieves a table named &lt;code&gt;touches&lt;/code&gt;, which has a list of &lt;code&gt;id&lt;/code&gt;s for each touch. The position of a touch can then be retrieved by using &lt;code&gt;local x, y = love.touch.getPosition(id)&lt;/code&gt; for each id. Because Love2D uses Lua, polling is very fast.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;The events available are &lt;code&gt;love.touchpressed&lt;/code&gt;, &lt;code&gt;love.touchmoved&lt;/code&gt; and &lt;code&gt;love.touchreleased&lt;/code&gt;. In each of them, the passed parameters are &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, &lt;code&gt;dx&lt;/code&gt;, &lt;code&gt;dy&lt;/code&gt; and &lt;code&gt;pressure&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Ren'Py - Gestures&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.renpy.org/doc/html/gesture.html" rel="nofollow"&gt;https://www.renpy.org/doc/html/gesture.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Using gestures instead of handling the position of where a touch 
happens is a very different approach, Ren'Py docs explain this neatly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The gesture recognizer first classifies swipes into 8 compass directions, "&lt;code&gt;n&lt;/code&gt;", "&lt;code&gt;ne&lt;/code&gt;", "&lt;code&gt;e&lt;/code&gt;", "&lt;code&gt;se&lt;/code&gt;", "&lt;code&gt;s&lt;/code&gt;", "&lt;code&gt;sw&lt;/code&gt;", "&lt;code&gt;w&lt;/code&gt;", "&lt;code&gt;nw&lt;/code&gt;". North is considered to be towards the top of the screen. It then concatenates the swipes into a string using the "&lt;code&gt;_&lt;/code&gt;" as a delimiter. For example, if the player swipes down and to the right, the string "&lt;code&gt;s_e&lt;/code&gt;" will be produced.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This allows building gestures in string, &lt;code&gt;config.gestures&lt;/code&gt; is available as a dictionary of sorts where a string representing a gesture maps to a function (an action):  &lt;code&gt;define config.gestures = { "n_s_w_e_w_e" : "progress_screen" } .&lt;/code&gt;&lt;/p&gt;&lt;hr /&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;&lt;p&gt;When researching for this topic I looked into &lt;a href="https://haxeflixel.com/documentation/actions/"&gt;HaxeFlixel Actions&lt;/a&gt;,
 and while there's no obvious way of handling touch there other than the
 mouse, it has a very interesting system of matching input to a function
 that will execute its gameplay result and it seems similar to what is 
available in both Ren'Py and Game Maker premade gestures. Still, gesture handling in the engine seems to be a minority.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Looking at the touch APIs of most engines above, they seem decided to give you the meaningful data available that is as close as the user input and let you handle and interpret it as you wish. In the early days of multi-touch APIs I believe I saw even one x and y position per "pixel" touched which was very demanding to go through. By giving a position per finger per frame it's data that can be handled without as much effort and from the documentation it appears to be what is being made available in the current APIs. In some engines though, the position is a normalized float between 0 and 1 and you are on your own to convert this in your world coordinates.&lt;/p&gt;&lt;p&gt;Godot seem to work with the leanest at just an ID per finger, a position, and information so you can tell when the finger is down and when it leaves the screen. If you are looking to the minimal you can have to work with mobile devices when building your game, I believe it hits it.&amp;nbsp;&lt;/p&gt;</description><author>Erico Notes</author><pubDate>Sun, 22 Nov 2020 17:53:12 GMT</pubDate><guid isPermaLink="true">https://ericonotes.blogspot.com/2020/11/a-quick-look-at-touch-handling-apis-in.html</guid></item><item><title>Mining Instagram efficiently with Torpy - Fast Instagram Scraper</title><link>https://geo.rocks/post/fast-instagram-scraper/</link><description>&lt;p&gt;&lt;img alt="Fast Instagram Scraper" src="https://raw.githubusercontent.com/do-me/fast-instagram-scraper/main/fast-instagram-scraper-cli.gif" /&gt;
&lt;img alt="Fast Instagram Scraper" src="https://raw.githubusercontent.com/do-me/fast-instagram-scraper/main/Fast%20Instagram%20Scraper.gif" /&gt;&lt;/p&gt;
&lt;p&gt;A fast and efficient Instagram Scraper based on Torpy. Scrapes posts for multiple hashtags and &lt;a href="https://geo.rocks/post/mining-locations-ids/"&gt;location ids&lt;/a&gt;.&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Sun, 22 Nov 2020 14:42:15 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/fast-instagram-scraper/</guid></item><item><title>Tidying up towing data with Pandas</title><link>https://utf9k.net/blog/tidying-towing-data/</link><description>A step by step walkthrough on how I cleaned up some data as part of a side project</description><author>utf9k</author><pubDate>Sun, 22 Nov 2020 13:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/tidying-towing-data/</guid></item><item><title>Why TUI applications ?</title><link>https://dystroy.org/blog/terminal-appeal/</link><description>&lt;p&gt;Twenty years ago, most of us thought TUI applications were going to disappear.
TUI were just a vestige of low capabilities computers.
There was no reason for TUI not to die with the rise of the personal computer.&lt;/p&gt;
&lt;p&gt;This didn't happen. We still love to use TUI applications.&lt;/p&gt;
&lt;p&gt;Why can be kind of mysterious.&lt;/p&gt;</description><author>dystroy|Canop / blog</author><pubDate>Sun, 22 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://dystroy.org/blog/terminal-appeal/</guid></item><item><title>OSS logstash with AWS Opendistro for Elasticsearch</title><link>https://blog.cetinich.net/content/2020/2020-logstash-opendistro-elastic/</link><description>To get logstash talking to the Open Distro Elasticsearch the first thing
that should be understood is that open distro only works with the OSS
(Apache 2.0 Licensed) edition of the Elastic tools and not the Elastic
licensed edition (Xpack).</description><author>Brent's Blog</author><pubDate>Sun, 22 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-logstash-opendistro-elastic/</guid></item><item><title>Intercept HTTP/HTTPS TLS traffic</title><link>https://blog.cetinich.net/content/2020/2020-mitm-intercept/</link><description>Use open source project
mitmproxy and have visibility
into what iOS apps (or anything else) are sending back to their mother
ship.</description><author>Brent's Blog</author><pubDate>Sun, 22 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-mitm-intercept/</guid></item><item><title>Building a Sim Racing Wind Simulator</title><link>https://reticulated.net/posts/simfans/</link><description>I first started semi-seriously sim racing a few years ago after buying a cheap old Fanatec wheel/pedal/h-shifter combo on Craigslist for $60. I was looking for something new to get into, and had a previous obsession with the Gran Turismo games on PlayStation to guide me past the first hurdles.
Fast forward to today and I have heavilyinvested in my setup, with the main goal being realism and immersion.</description><author>Reticulated</author><pubDate>Sun, 22 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://reticulated.net/posts/simfans/</guid></item><item><title>My Perfect Task App</title><link>https://xavd.id/blog/post/my-perfect-task-app/</link><description>I have come to the sad realization that there is no perfect task app. Many are good and some are great, but nothing will ever be perfect. Nevertheless, I spec out my ideal app.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://xavd.id/blog/post/my-perfect-task-app/"&gt;Read the whole thing&lt;/a&gt;.</description><author>The David Brownman Blog</author><pubDate>Sun, 22 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xavd.id/blog/post/my-perfect-task-app/</guid></item><item><title>Not ALL COVID-related "state interventions" are the same</title><link>https://stop.zona-m.net/2020/11/not-all-covid-related-state-interventions-are-the-same/</link><description>&lt;p&gt;There are interventions, and then there are interventions&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 21 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/not-all-covid-related-state-interventions-are-the-same/</guid></item><item><title>Professionalism and the extra mile</title><link>https://ilearnt.com/blog/professionalismandtheextramile/</link><description>&lt;p&gt;We had been planning to have a large garden summerhouse built for a number of months and we were finally in a position to do so. After a lot of research we decided to engage a local company as we liked the style of building they produced and the price was also competitive.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sat, 21 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/professionalismandtheextramile/</guid></item><item><title>Devlog #4: entity activities</title><link>https://domwillia.ms/devlog4</link><description>A technical dive into how living entities do the things the brain tells them to do without crippling game performance.</description><author>Dom Williams</author><pubDate>Sat, 21 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://domwillia.ms/devlog4</guid></item><item><title>Novembre 2020 : Revue de mon matériel informatique</title><link>/post/2020/11/21/novembre-2020-revue-de-mon-mat%C3%A9riel-informatique/</link><description>&lt;p&gt;Voici une revue du matériel informatique en ma possession à la date du 21 novembre 2020.&lt;/p&gt;
&lt;h2 id="ordinateur-de-bureau"&gt;Ordinateur de bureau&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Processeur : AMD Ryzen 5 2600&lt;/li&gt;
&lt;li&gt;Watercooling AIO : Corsair H60 2019&lt;/li&gt;
&lt;li&gt;Carte mère : ASRock Fatal1ty B450 Gaming-ITX_ac&lt;/li&gt;
&lt;li&gt;Mémoire vive : 2x8 Go G.Skill RipJaws 5 3200MHz CL16&lt;/li&gt;
&lt;li&gt;Carte graphique : AMD Sapphire RX 580 Nitro+ 8Go&lt;/li&gt;
&lt;li&gt;Alimentation : Corsair HX 620W (achetée en 2010)&lt;/li&gt;
&lt;li&gt;Boîtier : Silverstone SG13&lt;/li&gt;
&lt;li&gt;Stockage : SSD Samsung 970 Evo NVMe 500 Go + 3 disques dur interne de 2 To, 500 Go et 500 Go&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ce système est ma machine de jeu principale, je joue exclusivement à des jeux Steam sous Linux (la liste des jeux auxquels je joue est disponible sur &lt;a href="https://steamcommunity.com/id/dbeley"&gt;mon profil Steam&lt;/a&gt;).&lt;/p&gt;</description><author>Accueil on dbeley</author><pubDate>Sat, 21 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">/post/2020/11/21/novembre-2020-revue-de-mon-mat%C3%A9riel-informatique/</guid></item><item><title>Moved blog to alabaster with Sphinx</title><link>https://blog.cetinich.net/content/2020/2020-sphynx-ablog-blog/</link><description>Mostly notes to self on how to deploy and architecture / setup. Inspired
by https://github.com/vincentbernat/vincent.bernat.ch</description><author>Brent's Blog</author><pubDate>Sat, 21 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-sphynx-ablog-blog/</guid></item><item><title>The political threat of WhatsApp</title><link>https://stop.zona-m.net/2020/11/the-political-threat-of-whatsapp/</link><description>&lt;p&gt;As if WhatsApp wasn&amp;rsquo;t already bad enough&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 20 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/the-political-threat-of-whatsapp/</guid></item><item><title>High System Load with Low CPU Utilization on Linux?</title><link>https://tanelpoder.com/posts/high-system-load-low-cpu-utilization-on-linux/</link><description>&lt;p&gt;In this post I will show you how to break down Linux &lt;strong&gt;system load&lt;/strong&gt; by the load contributor or reason. You can drill down into the &lt;em&gt;&amp;ldquo;linux system load in thousands&amp;rdquo;&lt;/em&gt; and &lt;em&gt;&amp;ldquo;high system load, but low CPU utilization&amp;rdquo;&lt;/em&gt; problem patterns too.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="#introduction---terminology"&gt;Introduction - terminology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#troubleshooting-high-system-load-on-linux"&gt;Troubleshooting high system load on Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#drilling-down-deeper---wchan"&gt;Drilling down deeper - WCHAN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#drilling-down-deeper---kernel-stack"&gt;Drilling down deeper - kernel stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#how-to-troubleshoot-past-problems"&gt;How to troubleshoot past problems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#summary"&gt;Summary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#further-reading"&gt;Further reading&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="introduction---terminology"&gt;Introduction - Terminology&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;system load&lt;/em&gt; metric aims to represent the system &amp;ldquo;resource demand&amp;rdquo; as just a single number. On classic Unixes, it only counts the demand for CPU (threads in Runnable state)&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;unit&lt;/em&gt; of system load metric is &amp;ldquo;number of processes/threads&amp;rdquo; (or &lt;em&gt;tasks&lt;/em&gt; as the scheduling unit is called on Linux). The load &lt;em&gt;average&lt;/em&gt; is an average number of threads over a time period (last 1,5,15 mins) that &lt;em&gt;&amp;ldquo;compete for CPU&amp;rdquo;&lt;/em&gt; on classic unixes or &lt;em&gt;&amp;ldquo;either compete for CPU or wait in an uninterruptible sleep state&amp;rdquo;&lt;/em&gt; on Linux&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runnable&lt;/strong&gt; state means &amp;ldquo;not blocked by anything&amp;rdquo;, ready to run on CPU. The thread is either currently running on CPU or waiting in the CPU runqueue for the OS scheduler to put it onto CPU&lt;/li&gt;
&lt;li&gt;On Linux, the system load includes threads &lt;em&gt;both&lt;/em&gt; in Runnable (R) &lt;em&gt;and&lt;/em&gt; in &lt;strong&gt;Uninterruptible&lt;/strong&gt; sleep (D) states (typically disk I/O, but not always)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, on Linux, an absurdly high load figure can be caused by having lots of threads in Uninterruptible sleep (D) state, in addition to CPU demand.&lt;/p&gt;</description><author>Tanel Poder Blog</author><pubDate>Fri, 20 Nov 2020 18:31:58 GMT</pubDate><guid isPermaLink="true">https://tanelpoder.com/posts/high-system-load-low-cpu-utilization-on-linux/</guid></item><item><title>Fix Virtualbox installation for Docker on macOS</title><link>https://bfontaine.net/2020/11/20/fix-virtualbox-macos/</link><description>&lt;p&gt;While following a &lt;a href="https://medium.com/crowdbotics/a-complete-one-by-one-guide-to-install-docker-on-your-mac-os-using-homebrew-e818eb4cfc3"&gt;tutorial&lt;/a&gt; to install Virtualbox in order to have &lt;code class="language-plaintext highlighter-rouge"&gt;docker&lt;/code&gt; working on macOS, I
hit an issue where the &lt;code class="language-plaintext highlighter-rouge"&gt;docker-machine create&lt;/code&gt; command fails with an error that looks like this:&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;VBoxManage: error: Failed to create the host-only adapter
VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component HostNetworkInterfaceWrap, interface IHostNetworkInterface
VBoxManage: error: Context: "RTEXITCODE handleCreate(HandlerArg *)" at line 95 of file VBoxManageHostonly.cpp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you search on the Web, everybody says you have to open the Security &amp;amp; Privacy settings window
and allow the Oracle kernel extensions to run. But I didn’t have it. I tried uninstalling
Virtualbox, re-installing through the official website, reboot, uninstall, re-install with
&lt;code class="language-plaintext highlighter-rouge"&gt;brew cask&lt;/code&gt; but I always had the issue. &lt;a href="http://biercoff.com/how-to-fix-docker-machine-installation-on-mac-os-x/"&gt;Some people&lt;/a&gt; reported having a failed Virtualbox
installation but mine seemed ok.&lt;/p&gt;

&lt;p&gt;I tried &lt;a href="https://forums.virtualbox.org/viewtopic.php?f=8&amp;amp;t=88142#p428629"&gt;the &lt;code class="language-plaintext highlighter-rouge"&gt;spctl&lt;/code&gt; solution&lt;/a&gt; but it didn’t change anything.&lt;/p&gt;

&lt;p&gt;In the end, I tried &lt;a href="https://stackoverflow.com/a/59961248/735926"&gt;this StackOverflow answer&lt;/a&gt;:&lt;/p&gt;

&lt;div class="language-bash highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="s2"&gt;"/Library/Application Support/VirtualBox/LaunchDaemons/VirtualBoxStartup.sh"&lt;/span&gt; restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It failed, but it told me to check the Security &amp;amp; Privacy setting window. I did, and I had the
button everyone was talking about. I enabled the kernel extension, rebooted, and it worked.&lt;/p&gt;

&lt;p&gt;Hope this can save some time to anyone having the same issue!&lt;/p&gt;</description><author>Baptiste Fontaine’s Blog</author><pubDate>Fri, 20 Nov 2020 18:08:00 GMT</pubDate><guid isPermaLink="true">https://bfontaine.net/2020/11/20/fix-virtualbox-macos/</guid></item><item><title>My Manic Pixie Dream Programming Language</title><link>https://blog.janissary.xyz/posts/dreamlang</link><author>janissary</author><pubDate>Fri, 20 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.janissary.xyz/posts/dreamlang</guid></item><item><title>Aider la science avec le projet BOINC</title><link>/post/2020/11/20/aider-la-science-avec-le-projet-boinc/</link><description>&lt;h2 id="le-projet-boinc"&gt;Le Projet BOINC&lt;/h2&gt;
&lt;p&gt;Le &lt;a href="https://boinc.berkeley.edu/"&gt;projet BOINC&lt;/a&gt; (Berkeley Open Infrastructure for Network Computing) est un projet de calcul distribué créé par l&amp;rsquo;université de Berkeley en 2002.&lt;/p&gt;
&lt;figure&gt;&lt;img src="/images/boinc_logo.png" /&gt;
&lt;/figure&gt;

&lt;p&gt;Il permet à des volontaires d&amp;rsquo;aider la recherche scientifique en faisant tourner des calculs scientifiques en arrière-plan sur leur ordinateur. Les volontaires n&amp;rsquo;ont qu&amp;rsquo;à télécharger le client BOINC et s&amp;rsquo;inscrire sur un ou plusieurs des projets utilisant BOINC.&lt;/p&gt;
&lt;p&gt;Chaque projet BOINC propose des unités de calcul plus ou moins gourmandes en ressources, qui lorsque terminées par les utilisateurs, les récompenseront d&amp;rsquo;un certain nombre de points. Tout un système autour de ces points a été mis en place, avec des équipes, des classements ou encore des badges.&lt;/p&gt;</description><author>Accueil on dbeley</author><pubDate>Fri, 20 Nov 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">/post/2020/11/20/aider-la-science-avec-le-projet-boinc/</guid></item><item><title>Resilient Git, Part 1: Hydra Hosting</title><link>https://seirdy.one/posts/2020/11/18/git-workflow-1/</link><description>Efficient redundancy via repository mirroring with nothing but git.</description><author>All content on Seirdy’s Home</author><pubDate>Thu, 19 Nov 2020 22:23:18 GMT</pubDate><guid isPermaLink="true">https://seirdy.one/posts/2020/11/18/git-workflow-1/</guid></item><item><title>Resilient Git, Part 0: Introduction</title><link>https://seirdy.one/posts/2020/11/17/git-workflow-0/</link><description>A seires on setting up resilient git-based project workflows, free of vendor lock-in.</description><author>All content on Seirdy’s Home</author><pubDate>Thu, 19 Nov 2020 22:23:18 GMT</pubDate><guid isPermaLink="true">https://seirdy.one/posts/2020/11/17/git-workflow-0/</guid></item><item><title>Write Errors That Don't Make Me Think</title><link>https://www.swyx.io/write-errors-that-don-t-make-me-think-24hg</link><description>How we plan to fail with Thoughtful Error Message Design at Temporal.</description><author>swyx's site RSS Feed</author><pubDate>Thu, 19 Nov 2020 21:33:35 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/write-errors-that-don-t-make-me-think-24hg</guid></item><item><title>Of Google, enforcing a false sense of democracy</title><link>https://stop.zona-m.net/2020/11/of-google-enforcing-a-false-sense-of-democracy/</link><description>&lt;p&gt;Because the web should not be steered by ANY single company.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 19 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/of-google-enforcing-a-false-sense-of-democracy/</guid></item><item><title>Configuration magic</title><link>https://utf9k.net/blog/configuration-magic/</link><description>Configuration is great! Magic... not so much!</description><author>utf9k</author><pubDate>Thu, 19 Nov 2020 13:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/configuration-magic/</guid></item><item><title>SES Email client for S3</title><link>https://blog.cetinich.net/content/2020/2020-ses-s3-mail-client/</link><description>You can conveniently browse the SES mail in S3 using this tool</description><author>Brent's Blog</author><pubDate>Thu, 19 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-ses-s3-mail-client/</guid></item><item><title>OpenStreetMap is now Too Big To Stay Pure</title><link>https://stop.zona-m.net/2020/11/openstreetmap-is-now-too-big-to-stay-pure/</link><description>&lt;p&gt;But is that a problem, or just a warning? And of what?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 18 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/openstreetmap-is-now-too-big-to-stay-pure/</guid></item><item><title>Capturing Alexa Errors with Sentry and GitLab</title><link>https://nathanfriend.com/2020/11/18/capturing-alexa-errors-with-sentry-and-gitlab.html</link><description>Diagnosing issues with a live Alexa skill can be tricky.</description><author>Nathan Friend</author><pubDate>Wed, 18 Nov 2020 16:22:10 GMT</pubDate><guid isPermaLink="true">https://nathanfriend.com/2020/11/18/capturing-alexa-errors-with-sentry-and-gitlab.html</guid></item><item><title>DevOps Team Charter</title><link>https://smcleod.net/2020/11/devops-team-charter/</link><description>&lt;p&gt;A template team charter for software and platform engineering teams.&lt;/p&gt;
&lt;p&gt;Research&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; shows there is great value in people embracing a shared vision and ideas that are bigger than themselves.&lt;/p&gt;
&lt;p&gt;When it comes to a team charter, it&amp;rsquo;s important to remember that it&amp;rsquo;s not a static document. It&amp;rsquo;s a living document that should be updated as the team evolves and grows.&lt;/p&gt;
&lt;p&gt;Keep in mind that&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One size doesn&amp;rsquo;t fit all.&lt;/li&gt;
&lt;li&gt;Consider your (teams) mission, cultural background and values.&lt;/li&gt;
&lt;li&gt;While not exhaustive - this is on the longer side, you may wish to distill as is practical, but I implore you not to only pick the easier items - that&amp;rsquo;s missing the point.&lt;/li&gt;
&lt;li&gt;These can give you talking points when performing postmortems, retros and during times of conflict.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;See also: &amp;lsquo;&lt;a href="https://itrevolution.com/antipattern-1-2-using-old-ways-of-thinking-to-apply-new-ways-of-working/"&gt;Using Old Ways of Thinking to Apply New Ways of Working&lt;/a&gt;&amp;rsquo; and &amp;lsquo;&lt;a href="https://itrevolution.com/bvssh-principles/"&gt;BVSSHJ Principles&lt;/a&gt;&amp;rsquo;&lt;/em&gt;.&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Wed, 18 Nov 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2020/11/devops-team-charter/</guid></item><item><title>CCEC 2020 Reg Friesen Competition [Video]</title><link>https://www.youtube.com/watch?v=ti-OMM9sBjE</link><description>Review of pre-print manuscripts on remote instruction since January 2020. How are students and instructors adapting the the global pandemic?</description><author>David Schlachter</author><pubDate>Wed, 18 Nov 2020 15:15:00 GMT</pubDate><guid isPermaLink="true">https://www.youtube.com/watch?v=ti-OMM9sBjE</guid></item><item><title>Building a J2EE app using IntelliJ Idea and deploying on Heroku</title><link>https://rajkumaar.co.in/posts/j2ee/</link><description/><author>Online Home of Rajkumar</author><pubDate>Wed, 18 Nov 2020 08:53:35 GMT</pubDate><guid isPermaLink="true">https://rajkumaar.co.in/posts/j2ee/</guid></item><item><title>Scala 3 Context Functions</title><link>http://justinhj.github.io/2020/11/18/scala-3-context-functions.html</link><description>&lt;div class="outline-2" id="outline-container-orgf6c3f62"&gt;
&lt;h2 id="orgf6c3f62"&gt;Some Scala 3 Things: Context functions, Enums and significant whitespace&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orgf6c3f62"&gt;
&lt;p&gt;
&lt;code&gt;Updated: for Scala 3.0.0-M3 `as` keyword was removed&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;
This is the companion blog for my first Functional Justin video which you can find here &lt;a href="https://youtu.be/J01u_Dmrx5U"&gt;https://youtu.be/J01u_Dmrx5U&lt;/a&gt;. I spend around 15 minutes adding some Scala 3 (formerly Dotty) features to an Scala 2 program.
&lt;/p&gt;

&lt;p&gt;
The program itself builds a simple Algebraic Data Type (ADT) to represent a simple arithmetic expressions. We can then build expressions in this &lt;code&gt;algebra&lt;/code&gt; and evaluate it using an eval function using pattern matching&amp;#x2026;
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #f78fe7;"&gt;sealed&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;trait&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
&lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;class&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Val&lt;/span&gt;(value&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
&lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;class&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Add&lt;/span&gt;(left&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;, right&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
&lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;class&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Mul&lt;/span&gt;(left&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;, right&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
&lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;class&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Var&lt;/span&gt;(identifier&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Now given an expression like &lt;code&gt;Mul(Var("z"), Add(Val(30), Mul(Var("x"), Var("y"))))&lt;/code&gt; I'd like to be able to recursively traverse it and calculate a final Int value at the end.
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;Val&lt;/code&gt; represents an Int value, whilst &lt;code&gt;Add&lt;/code&gt; and &lt;code&gt;Mul&lt;/code&gt; take care of addition and multiplication. You could go ahead and add more functions. &lt;code&gt;Var&lt;/code&gt; is interesting because it takes an a string identifier (i.e., a variable name) and will look it up in an environment. The environment is represented a Scala map of String to Int.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;type&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Env&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Map&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;String&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;Int&lt;/span&gt;]
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
For the eval function we just use a pattern match to dispatch to functions that handle each particular operation. These handler functions and eval are &lt;code&gt;mutally recursive&lt;/code&gt;, and note that every function has to have the &lt;code&gt;Env&lt;/code&gt; passed to it as an implicit parameter, yet only &lt;code&gt;Var&lt;/code&gt; needs it. This will be important later.
&lt;/p&gt;

&lt;p&gt;
Here's the eval function and handlers.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;eval&lt;/span&gt;(exp&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;)(&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; env &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; {
  exp &lt;span style="color: #b6a0ff;"&gt;match&lt;/span&gt; {
    &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Var&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;id&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; handleVar(id)
    &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Val&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;value&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; value
    &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Add&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;l&lt;/span&gt;,&lt;span style="color: #00d3d0;"&gt;r&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; handleAdd(l,r)
    &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Mul&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;l&lt;/span&gt;,&lt;span style="color: #00d3d0;"&gt;r&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; handleMul(l,r)
  }
}

&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;handleAdd&lt;/span&gt;(l&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;, r&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;)(&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; env &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; eval(l) + eval(r)
&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;handleMul&lt;/span&gt;(l&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;, r&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;)(&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; env &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; eval(l) * eval(r)
&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;handleVar&lt;/span&gt;(s&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;)(&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; env&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; env.getOrElse(s, &lt;span style="color: #00bcff;"&gt;0&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Note that we could have inlined these functions in eval, but it a larger example it's important to break things out to keep things managable.
&lt;/p&gt;

&lt;p&gt;
That is all the implementation we need, and all that remains is to create an expression, create an environment (declared implicit so Scala knows to include it as an implicit when eval is called) and print the result of evaluating the expression.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;exp1&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Mul&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;Var&lt;/span&gt;(&lt;span style="color: #79a8ff;"&gt;"z"&lt;/span&gt;), &lt;span style="color: #00bcff;"&gt;Add&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;Val&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;30&lt;/span&gt;), &lt;span style="color: #00bcff;"&gt;Mul&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;Var&lt;/span&gt;(&lt;span style="color: #79a8ff;"&gt;"x"&lt;/span&gt;), &lt;span style="color: #00bcff;"&gt;Var&lt;/span&gt;(&lt;span style="color: #79a8ff;"&gt;"y"&lt;/span&gt;))))

&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;env&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Map&lt;/span&gt;(&lt;span style="color: #79a8ff;"&gt;"x"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;17&lt;/span&gt;, &lt;span style="color: #79a8ff;"&gt;"y"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;10&lt;/span&gt;, &lt;span style="color: #79a8ff;"&gt;"z"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;2&lt;/span&gt;)
&lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;eval1&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; eval(exp1)

println(s&lt;span style="color: #79a8ff;"&gt;"Eval exp gives &lt;/span&gt;&lt;span style="color: #00d3d0;"&gt;$eval1&lt;/span&gt;&lt;span style="color: #79a8ff;"&gt;"&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You can compile and run the code to see this working. The code is here. &lt;a href="https://github.com/justinhj/evalexample/blob/master/src/main/scala/Scala2Eval.scala"&gt;https://github.com/justinhj/evalexample/blob/master/src/main/scala/Scala2Eval.scala&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-orgb5b329b"&gt;
&lt;h2 id="orgb5b329b"&gt;Fun with Enum&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orgb5b329b"&gt;
&lt;p&gt;
Scala enums have been improved greatly. For one they are very simple to create and use just as in other languages.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;enum &lt;span style="color: #00bcff;"&gt;StatusCode&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt;
   &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;OK&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;TimedOut&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;Error&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Here we've defined three enums that have ordinal values 0 to 2. You can access the ordinal value with the &lt;code&gt;.ordinal&lt;/code&gt; method, convert ordinal values to Enums using &lt;code&gt;.fromOrdinal&lt;/code&gt; and convert Strings to enums (assuming they match) with &lt;code&gt;.valueOf&lt;/code&gt;.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;println(s&lt;span style="color: #79a8ff;"&gt;"Ordinal value of StatusCode.Error is &lt;/span&gt;&lt;span style="color: #00d3d0;"&gt;${StatusCode.Error.ordinal}&lt;/span&gt;&lt;span style="color: #79a8ff;"&gt;"&lt;/span&gt;)
println(s&lt;span style="color: #79a8ff;"&gt;"StatusCode from ordinal 1 is &lt;/span&gt;&lt;span style="color: #00d3d0;"&gt;${StatusCode.fromOrdinal(1)}&lt;/span&gt;&lt;span style="color: #79a8ff;"&gt;"&lt;/span&gt;)
println(s&lt;span style="color: #79a8ff;"&gt;"StatusCode from string OK is &lt;/span&gt;&lt;span style="color: #00d3d0;"&gt;${StatusCode.valueOf("OK")}&lt;/span&gt;&lt;span style="color: #79a8ff;"&gt;"&lt;/span&gt;)

&lt;span style="color: #a8a8a8;"&gt;// &lt;/span&gt;&lt;span style="color: #a8a8a8;"&gt;Ordinal value of StatusCode.Error is 2&lt;/span&gt;
&lt;span style="color: #a8a8a8;"&gt;// &lt;/span&gt;&lt;span style="color: #a8a8a8;"&gt;StatusCode from ordinal 1 is TimedOut&lt;/span&gt;
&lt;span style="color: #a8a8a8;"&gt;// &lt;/span&gt;&lt;span style="color: #a8a8a8;"&gt;StatusCode from string OK is OK&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You can also add your own parameters and definitions to enums. The underlying ordinal values are still there. For example you could encode Http Status codes as follows.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;enum &lt;span style="color: #00bcff;"&gt;HttpStatusCode&lt;/span&gt;(code&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;) {
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;OK&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;HttpStatusCode&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;200&lt;/span&gt;)
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;NotModified&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;HttpStatusCode&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;304&lt;/span&gt;)
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Forbidden&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;HttpStatusCode&lt;/span&gt;(&lt;span style="color: #00bcff;"&gt;404&lt;/span&gt;)

  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;isSuccess&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; code &amp;gt;= &lt;span style="color: #00bcff;"&gt;200&lt;/span&gt; &amp;amp;&amp;amp; code &amp;lt; &lt;span style="color: #00bcff;"&gt;300&lt;/span&gt;
}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Scala 3 team also took the opportunity to make Enums &lt;code&gt;a more concise notation for ADTs and GADTs&lt;/code&gt;. For our purposes that means we can simply the definition of &lt;code&gt;Exp&lt;/code&gt; as follows.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;enum &lt;span style="color: #00bcff;"&gt;Exp&lt;/span&gt; {
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Val&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;value&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Add&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;left&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;, &lt;span style="color: #00d3d0;"&gt;right&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Var&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;identifier&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;
}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
In fact you can further simplify to the following (you could also remove the braces).
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;enum &lt;span style="color: #00bcff;"&gt;Exp&lt;/span&gt; {
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Val&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;value&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;)
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Add&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;left&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;, &lt;span style="color: #00d3d0;"&gt;right&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;)
  &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Var&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;identifier&lt;/span&gt;&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;)
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-orgf9c19ca"&gt;
&lt;h2 id="orgf9c19ca"&gt;Explicit implicits&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orgf9c19ca"&gt;
&lt;p&gt;
A focus of the Scala 3 team is to help beginners access the language and in particular simplifying implicits. There are many subtle changes here but two obvious ones are that you now have different keywords for implicit parameters and creating implicit instances. In our code this means that when we supply the implicit symbol table to eval we now use the new &lt;code&gt;given&lt;/code&gt; syntax instead of &lt;code&gt;implicit&lt;/code&gt;.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #f78fe7;"&gt;implicit&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;env&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Map&lt;/span&gt;(&lt;span style="color: #79a8ff;"&gt;"x"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;17&lt;/span&gt;, &lt;span style="color: #79a8ff;"&gt;"y"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;10&lt;/span&gt;, &lt;span style="color: #79a8ff;"&gt;"z"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;2&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
becomes&amp;#x2026;
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;given envMap&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Map&lt;/span&gt;(&lt;span style="color: #79a8ff;"&gt;"x"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;7&lt;/span&gt;, &lt;span style="color: #79a8ff;"&gt;"y"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;6&lt;/span&gt;, &lt;span style="color: #79a8ff;"&gt;"z"&lt;/span&gt; -&amp;gt; &lt;span style="color: #00bcff;"&gt;22&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Similarly, the method parameters now no longer use the implicit keyword and instead you prefix the parameter name with &lt;code&gt;using&lt;/code&gt;.
&lt;/p&gt;

&lt;pre class="example"&gt;
def eval(exp: Exp)(implicit env : Env): Int
&lt;/pre&gt;

&lt;p&gt;
becomes&amp;#x2026;
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;eval&lt;/span&gt;(exp&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;)(using env &lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Env&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You don't have to change your Scala 2 code at this point, it is still compatible, but for new code and in the long term you should gradually eliminate implicit.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-org08f0809"&gt;
&lt;h2 id="org08f0809"&gt;Context Functions&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org08f0809"&gt;
&lt;p&gt;
Last and not at all least are context functions. This gives us one more opportunity to remove boiler plate from the eval code. When you create a regular function value it has a type like &lt;code&gt;Function1[A,B]&lt;/code&gt;. In other words it is a function that takes a value A and returns vale of type B. Context Functions are a new function value type (this is synthesized by the compiler so you won't see it your code), with an input and an output type. The difference is that the input is understood to be provided implicitly.
&lt;/p&gt;

&lt;p&gt;
Let's make this more concrete. Assume you have a function that needs an &lt;code&gt;ExecutionContext&lt;/code&gt;. We can make a Context Function type that will take an implicit execution context and return some paramaterized type T.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;type&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Executable&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;ExecutionContext&lt;/span&gt; ?=&amp;gt; &lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
How would that be used in a real program? Let's say you have some deeply nested function (f4 in the code below) and it is only down at that level you need the implicit execution context. Without implicit parameters you'd add the ExecutionContext parameter to every single function call all the way down and then have to take care to pass it along. With Scala 2 implicits you still have to declare the parameter but you can make it implicit and avoid the burden of manually passing it along.
&lt;/p&gt;

&lt;p&gt;
With Scala 3 you can define the function to be of type &lt;code&gt;Executable[T]&lt;/code&gt; and then we don't need to even name the implicit parameter, we just know that it will be included automatically all the way down. Here is a complete example.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;import&lt;/span&gt; scala.concurrent.{&lt;span style="color: #00bcff;"&gt;Future&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;ExecutionContext&lt;/span&gt;, &lt;span style="color: #00bcff;"&gt;Await&lt;/span&gt;}
&lt;span style="color: #b6a0ff;"&gt;import&lt;/span&gt; scala.concurrent.duration.&lt;span style="color: #b6a0ff;"&gt;_&lt;/span&gt;
&lt;span style="color: #b6a0ff;"&gt;import&lt;/span&gt; scala.language.postfixOps

&lt;span style="color: #b6a0ff;"&gt;object&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Executable&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;extends&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;App&lt;/span&gt; {

  &lt;span style="color: #b6a0ff;"&gt;type&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Executable&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;ExecutionContext&lt;/span&gt; ?=&amp;gt; &lt;span style="color: #00bcff;"&gt;T&lt;/span&gt;

  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;f1&lt;/span&gt;(n&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Executable&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Future&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Int&lt;/span&gt;]] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; f2(n + &lt;span style="color: #00bcff;"&gt;1&lt;/span&gt;)
  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;f2&lt;/span&gt;(n&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Executable&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Future&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Int&lt;/span&gt;]] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; f3(n + &lt;span style="color: #00bcff;"&gt;1&lt;/span&gt;)
  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;f3&lt;/span&gt;(n&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Executable&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Future&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Int&lt;/span&gt;]] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; f4(n + &lt;span style="color: #00bcff;"&gt;1&lt;/span&gt;)
  &lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;f4&lt;/span&gt;(n&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Int&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Executable&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Future&lt;/span&gt;[&lt;span style="color: #00bcff;"&gt;Int&lt;/span&gt;]] &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; {
    &lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;ex&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; summon[&lt;span style="color: #00bcff;"&gt;ExecutionContext&lt;/span&gt;]
    &lt;span style="color: #00bcff;"&gt;Future&lt;/span&gt; {
      println(s&lt;span style="color: #79a8ff;"&gt;"Hi from the future! n is &lt;/span&gt;&lt;span style="color: #00d3d0;"&gt;$n&lt;/span&gt;&lt;span style="color: #79a8ff;"&gt;"&lt;/span&gt;)
      n
    }
  }

  {
    given ec&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;ExecutionContext&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; scala.concurrent.&lt;span style="color: #00bcff;"&gt;ExecutionContext&lt;/span&gt;.global
    &lt;span style="color: #00bcff;"&gt;Await&lt;/span&gt;.result(f1(&lt;span style="color: #00bcff;"&gt;10&lt;/span&gt;), &lt;span style="color: #00bcff;"&gt;1&lt;/span&gt; second)
    &lt;span style="color: #a8a8a8;"&gt;// &lt;/span&gt;&lt;span style="color: #a8a8a8;"&gt;Hi from the future! n is 13&lt;/span&gt;
  }

}
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
Context functions reduce boilerplate when dealing with implicit parameters in deeply nested code. We can apply this technique to our eval function so that the symbol table itself is the implicit piece of context.
&lt;/p&gt;

&lt;div class="org-src-container"&gt;
&lt;pre class="src src-scala"&gt;&lt;span style="color: #b6a0ff;"&gt;type&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;WithEnv&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; &lt;span style="color: #00bcff;"&gt;Env&lt;/span&gt; ?=&amp;gt; &lt;span style="color: #00bcff;"&gt;Int&lt;/span&gt;

&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;eval&lt;/span&gt;(exp&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;WithEnv&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt;
  exp &lt;span style="color: #b6a0ff;"&gt;match&lt;/span&gt; {
    &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Var&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;id&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; handleVar(id)
    &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Val&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;value&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; value
    &lt;span style="color: #b6a0ff;"&gt;case&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Add&lt;/span&gt;(&lt;span style="color: #00d3d0;"&gt;l&lt;/span&gt;,&lt;span style="color: #00d3d0;"&gt;r&lt;/span&gt;) &lt;span style="color: #b6a0ff;"&gt;=&amp;gt;&lt;/span&gt; handleAdd(l,r)
  }

&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;handleAdd&lt;/span&gt;(l&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;, r&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;Exp&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;WithEnv&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; eval(l) + eval(r)

&lt;span style="color: #b6a0ff;"&gt;def&lt;/span&gt; &lt;span style="color: #feacd0;"&gt;handleVar&lt;/span&gt;(s&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;String&lt;/span&gt;)&lt;span style="color: #b6a0ff;"&gt;:&lt;/span&gt; &lt;span style="color: #6ae4b9;"&gt;WithEnv&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt;
  &lt;span style="color: #b6a0ff;"&gt;val&lt;/span&gt; &lt;span style="color: #00d3d0;"&gt;env&lt;/span&gt; &lt;span style="color: #b6a0ff;"&gt;=&lt;/span&gt; summon[&lt;span style="color: #00bcff;"&gt;Env&lt;/span&gt;]
  env.getOrElse(s, &lt;span style="color: #00bcff;"&gt;0&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;
You can take a look at the final Scala 3 version of the code here.
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://github.com/justinhj/evalexample/blob/master/src/main/scala/Scala3Eval.scala"&gt;https://github.com/justinhj/evalexample/blob/master/src/main/scala/Scala3Eval.scala&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-org7baa236"&gt;
&lt;h2 id="org7baa236"&gt;Final notes&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-org7baa236"&gt;
&lt;p&gt;
Of all the new features in Scala 3, I found Context Functions of most interest because of Martin Odersky's blog from 2016 &lt;a href="https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html"&gt;https://www.scala-lang.org/blog/2016/12/07/implicit-function-types.html&lt;/a&gt; where this intriguing quote appears near the end. (Context functions were initially known as implicit functions).
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
There are many interesting connections with category theory to explore here. On the one hand, implicit functions are used for tasks that are sometimes covered with monads such as the reader monad. There’s an argument to be made that implicits have better composability than monads and why that is.
&lt;/p&gt;

&lt;p&gt;
On the other hand, it turns out that implicit functions can also be given a co-monadic interpretation, and the interplay between monads and comonads is very interesting in its own right.
&lt;/p&gt;

&lt;p&gt;
But these discussions will have to wait for another time, as this blog post is already too long.
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
Somewhat of a Fermat's last theorem moment there, and I am also interested in how we can represent concepts, that are currently implemented in libraries which model category theory, using vanilla Scala 3 or alternative representations.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div class="outline-2" id="outline-container-orga7482f9"&gt;
&lt;h2 id="orga7482f9"&gt;References&lt;/h2&gt;
&lt;div class="outline-text-2" id="text-orga7482f9"&gt;
&lt;p&gt;
&lt;a href="https://en.wikiquote.org/wiki/Pierre_de_Fermat"&gt;https://en.wikiquote.org/wiki/Pierre_de_Fermat&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://dotty.epfl.ch/docs/reference/enums/enums.html"&gt;https://dotty.epfl.ch/docs/reference/enums/enums.html&lt;/a&gt;
&lt;a href="https://dotty.epfl.ch/docs/reference/enums/adts.html"&gt;https://dotty.epfl.ch/docs/reference/enums/adts.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="http://dotty.epfl.ch/docs/reference/other-new-features/indentation.html"&gt;http://dotty.epfl.ch/docs/reference/other-new-features/indentation.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://dotty.epfl.ch/docs/reference/contextual/givens.html"&gt;https://dotty.epfl.ch/docs/reference/contextual/givens.html&lt;/a&gt; &lt;a href="https://dotty.epfl.ch/docs/reference/contextual/using-clauses.html"&gt;https://dotty.epfl.ch/docs/reference/contextual/using-clauses.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://dotty.epfl.ch/docs/reference/contextual/context-functions.html"&gt;https://dotty.epfl.ch/docs/reference/contextual/context-functions.html&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Foundations and Applications of Implicit Function Types
&lt;a href="https://infoscience.epfl.ch/record/229878/files/simplicitly_1.pdf"&gt;https://infoscience.epfl.ch/record/229878/files/simplicitly_1.pdf&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="http://recurse.se/2019/09/implicit-functions-in-scala-3/"&gt;http://recurse.se/2019/09/implicit-functions-in-scala-3/&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&amp;copy; 2020 Justin Heyes-Jones. All Rights Reserved.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><author>Functional[Justin]</author><pubDate>Wed, 18 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://justinhj.github.io/2020/11/18/scala-3-context-functions.html</guid></item><item><title>The Mythical Man Month - Review</title><link>https://lukesingham.com/mythical-man-month-review/</link><description>&lt;p&gt;📚 Book: &lt;a href="https://amzn.to/38P7XBK"&gt;Mythical Man Month&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;⭐️ Rating: 3/5 (4/5 if you haven't had experience in tech)&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://lukesingham.com/content/images/2020/mythical-man-month-frontcover.png#thumbnail" /&gt;&lt;/p&gt;
&lt;p&gt;The Mythical Man Month (MMM) is a collection of essays that encapsulate wisdom accumulated by the author Fred Brooks. If, like me, you have been in the tech industry for a number of years you are unlikely to gain much value from this book - as you have either read articles or experienced first hand these lessons.&lt;/p&gt;
&lt;h3 id="some-criticisms-of-the-book%3A"&gt;Some criticisms of the book: &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#some-criticisms-of-the-book%3A"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;🤦‍♀️ There's not a female pronoun in sight - one of the few mentions of a female, is for an analogy where the project is a pregnancy, adding more women to the project will not decrease the nine months it will take for the birth to happen. This is to be expected of a book originally written in 1975 and with a title like &lt;em&gt;Mythical Man Month&lt;/em&gt;. I read the 1995 edition. I would hope any subsequent editions endeavour to have more gender inclusive language.&lt;/li&gt;
&lt;li&gt;👼 There's quite a lot of God mentions, more mentions of God than Women.&lt;/li&gt;
&lt;li&gt;📠 Many of the examples are very out of date. And the details on these examples of e.g. IBM 360 are superfluous to the modern reader.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="major-(useful)-points-of-the-book"&gt;Major (Useful) Points of the Book &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#major-(useful)-points-of-the-book"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="%F0%9F%92%A3-combinatorial-explosion"&gt;💣 Combinatorial Explosion &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#%F0%9F%92%A3-combinatorial-explosion"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Where the title of the book comes from. Many simpler types of work scale linearly with additional resources. For example, if you were a Farmer of 20 fields employing labour to til those fields. You might imagine doubling labour from 2 to 4 would double results. This is true, as there is little requirement for coordination of the manual labour. Labourers each get an allocation of fields to independently til. However, with work that requires much coordination, alignment of corresponding components of a greater system like software, adding more labour is frequently counterproductive. This leads to an assertion that &lt;em&gt;adding engineers to a late project will make it later&lt;/em&gt; because of the communication overhead and the need to onboard.&lt;/p&gt;
&lt;p&gt;The effect is known as &lt;a href="https://en.wikipedia.org/wiki/Combinatorial_explosion"&gt;combinatorial explosion&lt;/a&gt;. Where each node (worker) that needs to be aligned with the rest of the team adds many more communication links.&lt;br /&gt;
&lt;math display="block" xmlns="http://www.w3.org/1998/Math/MathML"&gt;&lt;mrow&gt;&lt;mtext&gt;links&lt;/mtext&gt;&lt;/mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;-&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;/mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mfrac&gt;&lt;/math&gt;&lt;/p&gt;
&lt;p&gt;A few examples demonstrate this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;when &lt;code&gt;n=2&lt;/code&gt;, there is 1 link&lt;/li&gt;
&lt;li&gt;when &lt;code&gt;n=4&lt;/code&gt;, there are 6 links&lt;/li&gt;
&lt;li&gt;when &lt;code&gt;n=8&lt;/code&gt;, there are 28 links&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This rule is also known as the '&lt;a href="https://www.theguardian.com/technology/2018/apr/24/the-two-pizza-rule-and-the-secret-of-amazons-success"&gt;two pizza rule&lt;/a&gt;' 🍕 - teams shouldn't be larger than can be fed with two pizzas. Not helpful if you eat an entire pizza to yourself 🤤. However, 5-7 people is what is meant.&lt;/p&gt;
&lt;h3 id="%F0%9F%A7%A0-conceptual-integrity"&gt;🧠 Conceptual Integrity &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#%F0%9F%A7%A0-conceptual-integrity"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;... conceptual integrity is the most important consideration in system design&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Brooks talks a lot about &lt;em&gt;Conceptual Integrity&lt;/em&gt; of software systems. In data analytics this is known by various terms e.g. ontology, entity models. If you have worked with any system with multiple contributors you have likely witnessed the core concepts of a system drift over time. Here Brooks suggests a solution,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If a system is to have conceptual integrity, someone must control the concepts. That is an aristocracy that needs no apology.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="%F0%9F%93%88-10x-programmers"&gt;📈 10x programmers &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#%F0%9F%93%88-10x-programmers"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To maintain &lt;em&gt;conceptual integrity&lt;/em&gt; smaller teams should be preferred.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;one wants the system to be built by as few minds as possible&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The type of team you should favour is one of a few senior engineers rather than one that is larger with junior engineers. Brooks cites a study measuring programmer productivity which is probably where the &lt;em&gt;10x engineers&lt;/em&gt; terminology originated. I thought this might be an exaggeration, but I've seen this play out in a workplace. A leader of a project thought that software was a sweatshop and if they just got more cheap juniors fresh out of code bootcamps that software would happen. It didn't. However, hiring one senior and one mid-level engineer saw delivery sky rocket. And yes, the senior was an order of magnitude more productive than juniors and for less than 3x the price!&lt;/p&gt;
&lt;h3 id="%F0%9F%93%84-documentation"&gt;📄 Documentation &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#%F0%9F%93%84-documentation"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Write a spec/proposal document prior to commencing on the code. This outlines a number of things, the &lt;em&gt;why&lt;/em&gt;, the requirements of a solution, the range of solutions considered and the proposed solution to be implemented. This helps in many ways, the writing process helps expose gaps in thinking, communicates to others, helps align the team and provides a record of what is being done or has been done.&lt;/p&gt;
&lt;h3 id="%F0%9F%9A%A7-maintenance"&gt;🚧 Maintenance &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#%F0%9F%9A%A7-maintenance"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A program doesn't stop changing when it is delivered for customer usage&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Brooks estimates that maintenance is '40 percent or more' than the initial cost of developing a system. The more users you have the greater the cost as more bugs are found by more users.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources &lt;a class="direct-link" href="https://lukesingham.com/mythical-man-month-review/#resources"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://asciimath.org/"&gt;asciimath.org&lt;/a&gt; - used to generate mathML mathjax formula&lt;/li&gt;
&lt;/ul&gt;</description><author>Luke Singham</author><pubDate>Wed, 18 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lukesingham.com/mythical-man-month-review/</guid></item><item><title>Indirect Effects of Allocate Direct</title><link>https://serce.me/posts/2020-11-18-allocate-direct</link><description>This article explores the trade-offs between the allocate and allocateDirect methods in Java for allocating memory.</description><author>SerCe's blog</author><pubDate>Wed, 18 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://serce.me/posts/2020-11-18-allocate-direct</guid></item><item><title>Configuring Git for Work</title><link>https://phili.pe/posts/configuring-git-for-work/</link><description>How to use your work email in your work repositories</description><author>Philipe Fatio</author><pubDate>Tue, 17 Nov 2020 22:38:04 GMT</pubDate><guid isPermaLink="true">https://phili.pe/posts/configuring-git-for-work/</guid></item><item><title>It seems we need four more Asimov's laws</title><link>https://stop.zona-m.net/2020/11/it-seems-we-need-four-more-asimovs-laws/</link><description>&lt;p&gt;OK, but&amp;hellip; for whom? Robots, or something else?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 17 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/it-seems-we-need-four-more-asimovs-laws/</guid></item><item><title>Generating HTTPS Certificate using DNS a Challenge through Let's Encrypt</title><link>https://web.navan.dev/posts/2020-11-17-Lets-Encrypt-DuckDns.html</link><description>Short code-snippet to generate HTTPS certificates using the DNS Challenge through Lets Encrypt for a web-server using DuckDNS.</description><author>Navan's Archive</author><pubDate>Tue, 17 Nov 2020 17:04:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-11-17-Lets-Encrypt-DuckDns.html</guid></item><item><title>Fetching Data in React with useEffect</title><link>https://maxrozen.com/fetching-data-react-with-useeffect</link><description>If you're confused about side-effects and pure functions, it can be hard to understand useEffect. Let's learn them both, to fetch data with useEffect.</description><author>Max Rozen</author><pubDate>Tue, 17 Nov 2020 11:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/fetching-data-react-with-useeffect</guid></item><item><title>My terminal, coding workflow - i3, Kakoune, nnn</title><link>https://ciesie.com/post/i3_kakoune_nnn/</link><description>&lt;p&gt;If I&amp;rsquo;m working on code or tech related tasks, I&amp;rsquo;m doing it on &lt;em&gt;Linux&lt;/em&gt;. That&amp;rsquo;s because I enjoy
spending my time in terminal. I like playing around with new command line tools and fitting
them into my workflow. Improving my process is important so I often try to update parts of
my setup. The goal is to reduce the friction between my intention and execution.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Linux&lt;/em&gt; environment is full of various tools and utilities. I&amp;rsquo;ve always been a fan of &lt;em&gt;Vim&lt;/em&gt;
but quickly found &lt;em&gt;NeoVim&lt;/em&gt;, which is an attempt to modernize &lt;em&gt;Vim&lt;/em&gt;&amp;rsquo;s codebase. &lt;em&gt;Vim&lt;/em&gt; itself
is never enough so I&amp;rsquo;ve started integrating plugins, which in turn introduced me to a lot of
smaller tools that further improved my process. Some of those tools have been substituted by
a faster and more robust alternative (usually written in &lt;em&gt;Rust&lt;/em&gt;).&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Tue, 17 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/i3_kakoune_nnn/</guid></item><item><title>Seastar's weak pointer</title><link>https://makedist.com/posts/2020/11/17/seastars-weak-pointer/</link><description>The non-owning counterpart to Seastar&amp;rsquo;s shared pointer.</description><author>Noah Watkins</author><pubDate>Tue, 17 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://makedist.com/posts/2020/11/17/seastars-weak-pointer/</guid></item><item><title>Online direct democracy? No, thanks</title><link>https://stop.zona-m.net/2020/11/online-direct-democracy-no-thanks/</link><description>&lt;p&gt;Because the world is not what is used to be.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 16 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/online-direct-democracy-no-thanks/</guid></item><item><title>A quick readthedocs Wiki with mkdocs</title><link>https://geo.rocks/post/mkdocs-wiki/</link><description>&lt;p&gt;&lt;img alt="mkdocs wiki" src="https://geo.rocks/img/mkdocs-wiki.jpg" title="mkdocs wiki" /&gt;&lt;/p&gt;
&lt;p&gt;Setting up a readthedocs wiki like 1,2,3!&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Mon, 16 Nov 2020 14:41:55 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/mkdocs-wiki/</guid></item><item><title>Bedroom carbon dioxide buildup</title><link>https://ivymike.dev/bedroom-carbon-dioxide-buildup.html</link><description>&lt;p&gt;You probably already know that carbon monoxide (CO) from combustion is highly poisonous. Hemoglobin binds to CO tighter than it binds to O2 &lt;a href="https://en.wikipedia.org/wiki/Carboxyhemoglobin"&gt;by a factor of 200&lt;/a&gt;, so a small amount quickly prevents your blood cells from being able to carry oxygen, and you die. That's why you need …&lt;/p&gt;</description><author>IvyMike.dev</author><pubDate>Mon, 16 Nov 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://ivymike.dev/bedroom-carbon-dioxide-buildup.html</guid></item><item><title>Create Amazon Scraper in Python using Scraper API  Learn how to create an Amazon scraper in python to scrape product details like price, ASIN etc</title><link>https://blog.adnansiddiqi.me/create-amazon-scraper-in-python-using-scraper-api/</link><description>&lt;p&gt;In this post of ScrapingTheFamous, I am going o write a scraper that will scrape data from Amazon. I do not need to tell you what is Amazon. You are here because you already know about it 🙂 So, we are going to write two different scripts: one would be fetch.py that would be fetching URLs of individual listings and save in a text file. Later another script, parse.py that will have a function taking an individual listing URL, scrape data, and save in JSON format. I will be using Scraper API service for parsing purposes which makes me free from all worries blocking and rendering dynamic sites since it takes care of everything. The first script is to fetching listings of a category. So let&amp;#8217;s do it! import requests from bs4 import BeautifulSoup if __name__ == '__main__': headers = { 'authority': 'www.amazon.com', 'pragma': 'no-cache', 'cache-control': 'no-cache', 'rtt': '600', 'downlink': '1.5', 'ect': '3g', 'upgrade-insecure-requests': '1', 'dnt': '1', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'sec-fetch-site': 'same-origin', 'sec-fetch-mode': 'navigate', 'sec-fetch-user': '?1', 'sec-fetch-dest': 'document', 'referer': 'https://google.com', 'accept-language': 'en-US,en;q=0.9,ur;q=0.8,zh-CN;q=0.7,zh;q=0.6', } API_KEY = None links_file = 'links.txt' links = [] with open('API_KEY.txt', encoding='utf8') as f: API_KEY = f.read() URL_TO_SCRAPE = 'https://www.amazon.com/s?i=electronics&amp;#38;rh=n%3A172541%2Cp_n_feature_four_browse-bin%3A12097501011&amp;#38;lo=image' payload = {'api_key': API_KEY, 'url': URL_TO_SCRAPE, 'render': 'false'} r = requests.get('http://api.scraperapi.com', params=payload, timeout=60) if r.status_code == 200: text = r.text.strip() soup = BeautifulSoup(text, 'lxml') links_section = soup.select('h2 &amp;#62; .a-link-normal') for link in links_section: url = 'https://amazon.com' + link['href'] links.append(url) if len(links) &amp;#62; 0: with open(links_file, 'a+', encoding='utf8') as f: f.write('\n'.join(links)) print('Links stored successfully.') So here is the script. I picked the electronics category, you may choose anyone you want. I arranged relevant headers. You can either pick manually via Chrome Inspector or use https://curl.trillworks.com/ to do this for you by copying the cURL request. I am using the ScraperAPI API endpoint by setting both the payload and api_key.  I am using h2 &amp;#62; .a-link-normal selector because there are many .a-link-normal links which are not required so I am using h2 &amp;#62; to make sure to pick the required links. Once we have links we will be saving in a text file. Now the next part of the post is about parsing the info: import requests from bs4 import BeautifulSoup def parse(url): record = {} headers = { 'authority': 'www.amazon.com', 'pragma': 'no-cache', 'cache-control': 'no-cache', 'rtt': '1000', 'downlink': '1.5', 'ect': '3g', 'dnt': '1', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36', 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'sec-fetch-site': 'none', 'sec-fetch-mode': 'navigate', 'sec-fetch-user': '?1', 'sec-fetch-dest': 'document', 'accept-language': 'en-US,en;q=0.9,ur;q=0.8,zh-CN;q=0.7,zh;q=0.6', } payload = {'api_key': API_KEY, 'url': url, 'render': 'false'} r = requests.get('http://api.scraperapi.com', params=payload, timeout=60) if r.status_code == 200: data = r.text.strip() soup = BeautifulSoup(data, 'lxml') title_section = soup.select('#productTitle') price_section = soup.select('#priceblock_ourprice') availability_section = soup.select('#availability') features_section = soup.select('#feature-bullets') asin_section = soup.find('link', {'rel': 'canonical'}) print(asin_section) if title_section: title = title_section[0].text.strip() if price_section: price = price_section[0].text.strip() if availability_section: availability = availability_section[0].text.strip() if features_section: features = features_section[0].text.strip() if asin_section: asin_url = asin_section['href'] asin_url_parts = asin_url.split('/') asin = asin_url_parts[len(asin_url_parts) - 1] record = {'title': title, 'price': price, 'availability': availability, 'asin': asin, 'features': features} return record if __name__ == '__main__': API_KEY = None with open('API_KEY.txt', encoding='utf8') as f: API_KEY = f.read() result = parse('https://www.amazon.com/Bambino-Seconds-Stainless-Japanese-Automatic-Leather/dp/B07B49QG1H/') print(result) Pretty straightforward. I fetched title, scraped Amazon ASIN, and other stuff. You can scrape many other things like Amazon reviews as well. The data is stored in JSON format. Conclusion In this post, you learned how you can scrape Amazon data easily by using Scraper API in Python. You can enhance this script as per your need like writing a price monitoring script or as an ASIN scraper. Writing scrapers is an interesting journey but you can hit the wall if the site blocks your IP. As an individual, you can’t afford expensive proxies either. Scraper API provides you an affordable and easy to use API that will let you scrape websites without any hassle. You do not need to worry about getting blocked because Scraper API by default uses proxies to access websites. On top of it, you do not need to worry about Selenium either since Scraper API provides the facility of a headless browser too. I also have written a post about how to use it. Click here to signup with my referral link or enter promo code adnan10, you will get a 10% discount on it. In case you do not get the discount then just let me know via email on my site and I’d sure help you out. If you like this post then you should subscribe to my blog for future updates. * indicates required Email Address *&lt;/p&gt;
The post &lt;a href="https://blog.adnansiddiqi.me/create-amazon-scraper-in-python-using-scraper-api/"&gt;Create Amazon Scraper in Python using Scraper API &lt;br /&gt; &lt;span style="color: grey; font-size: 25px; font-weight: 300;"&gt;Learn how to create an Amazon scraper in python to scrape product details like price, ASIN etc&lt;/span&gt;&lt;/a&gt; first appeared on &lt;a href="https://blog.adnansiddiqi.me"&gt;Adnan's Random bytes&lt;/a&gt;.</description><author>Adnan's Random bytes</author><pubDate>Mon, 16 Nov 2020 09:51:11 GMT</pubDate><guid isPermaLink="true">https://blog.adnansiddiqi.me/create-amazon-scraper-in-python-using-scraper-api/</guid></item><item><title>Review: *NieR:Automata*</title><link>/2020/11/nier-automata</link><description>This review contains NO SPOILERS except where specifically marked.</description><author>Elliott Slaughter</author><pubDate>Mon, 16 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">/2020/11/nier-automata</guid></item><item><title>Openness, discussions and success</title><link>https://ilearnt.com/blog/measuringsuccess/</link><description>&lt;p&gt;I work very closely with two colleagues - and have done so for a number of years. Together we have experienced some serious ups and downs in the company we work for and also personally. We have each reached a point where we were close to leaving; we have each had something happen in our lives where the others have supported us.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sun, 15 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/measuringsuccess/</guid></item><item><title>Debugging Python</title><link>https://geo.rocks/post/debugging-python/</link><description>&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre class="chroma" tabindex="0"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pdb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pdb&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;set_trace&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;bp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;bp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Debugging Python with pdb 🐞&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Sun, 15 Nov 2020 13:17:55 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/debugging-python/</guid></item><item><title>Logstash ingestion of AWS billing customer usage reports</title><link>https://blog.cetinich.net/content/2020/2020-aws-billing-logstash/</link><description>To get the CUR reports into elastic search:</description><author>Brent's Blog</author><pubDate>Sun, 15 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-aws-billing-logstash/</guid></item><item><title>How to improve your mathematical writing</title><link>https://bastian.rieck.me/blog/2020/mathematical_writing/</link><description>&lt;p&gt;Having been a reviewer for numerous machine learning conferences now,
there are some repeated issues I want to point out, concerning the way
authors describe mathematical concepts in their papers. I hope that my
suggestions will serve in particular those that are new to machine
learning and for whom the task of reading a paper with a &amp;lsquo;bad&amp;rsquo;
mathematical style might seem a daunting prospect. Without further ado,
here are some suggestions for improving your research article.&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h1 id="build-intuition"&gt;Build intuition&lt;/h1&gt;
&lt;p&gt;Your primary objective when writing mathematics should be to build
intuition for readers. This does &lt;em&gt;not&lt;/em&gt; mean that you should sacrifice
any rigour or precision&amp;mdash;I am just advocating for considering that
a reader of your paper is not an expert in the subject matter yet. If
you want readers to take away some wisdom from the paper, you have to
address their intuition first. No one except an expert in your field
will be swayed by long-winded proofs.&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I am &lt;em&gt;not&lt;/em&gt; advocating for sloppy thinking, sloppy writing, or
&amp;lsquo;hand-waving&amp;rsquo; in your proofs.  I am just saying that the way you lay out
your overall argument should be based on intuition, such that even
reviewers that are not experts in your domain can follow along. If you
only write a paper geared towards a very small audience, you are
reducing its impact and make your life harder because it will almost be
impossible to find good reviewers for it in the conference cycle.&lt;/p&gt;
&lt;h1 id="strive-for-consistent-notation-and-terminology"&gt;Strive for consistent notation and terminology&lt;/h1&gt;
&lt;p&gt;Whenever you introduce notation, try to remain &lt;em&gt;consistent&lt;/em&gt;. For
example, if you want to name three objects, prefer calling them $a$, $b$, and
$c$, instead of $\alpha$, $\mathbf{B}$, and $\mathfrak{c}^\prime$.&lt;/p&gt;
&lt;p&gt;Whenever possible, follow established terminology&amp;mdash;such as calling loss
terms $\mathcal{L}$&amp;mdash;but do not assume that the reader is aware of
these conventions. &lt;em&gt;Always&lt;/em&gt; take the time to at least briefly introduce
your notation.&lt;/p&gt;
&lt;p&gt;This point is in fact closely related to the second issue, namely&amp;hellip;&lt;/p&gt;
&lt;h1 id="less-can-be-more"&gt;Less can be more&lt;/h1&gt;
&lt;p&gt;Some people aim to be extremely precise and &lt;em&gt;always&lt;/em&gt; employ index-based
notations. For example, instead of referring to objects $a$ and $b$, it
is always $a_1$ and $a_2$ or something. There is nothing wrong with this
in principle, but I would suggest to always strive for as little index
notations as possible and, if only two objects of the same type are needed,
why not use a $\prime$ symbol (&lt;code&gt;\prime&lt;/code&gt; in LaTeX) instead of indices?
This can often increase readability and makes you less error-prone
because you do not have to keep track of the indices any more. For
example, in our &lt;a href="https://arxiv.org/abs/2011.03854"&gt;survey on graph kernels&lt;/a&gt;,
we try to always speak of $G$ and $G^\prime$ when we need to refer to
two graphs. This leaves the indices free for when you actually &lt;em&gt;have&lt;/em&gt; to
index something, for example because you are aggregating over objects
arising from a certain set.&lt;/p&gt;
&lt;p&gt;In addition, try to adhere to &amp;rsquo;less can be more&amp;rsquo; in other places as
well, by removing unnecessary variables, unnecessary concepts, and
unnecessary definitions. It does you credit if you want to explain
&lt;em&gt;everything&lt;/em&gt; about a certain field in your paper, but if you introduce
a concept X as a special case of a concept Y, there is no need to go to
great lengths to describe any super-concept Z, unless you actually
&lt;em&gt;need&lt;/em&gt; to refer to its properties. This does not mean that you should
leave out salient information&amp;mdash;I am suggesting to &lt;em&gt;focus&lt;/em&gt; on pertinent
information only. For example, there is no need to expand on properties
of metric spaces, topologies, and so on, if all you need is Lipschitz
continuity. Aim to get to the point quickly and without too many
redirections (unless you are writing a book, but I am assuming that
the reader of this post is interested in writing research papers).&lt;/p&gt;
&lt;p&gt;Try also not to fall prey to the tendency to make your formulas more
complex than they have to be. For example, peppering your formulas with
logical quantifiers such as $\forall$ or $\exists$ is more appropriate
when you are publishing in logic. Many people, however, treat these
symbols as shortcuts. Please &lt;em&gt;do&lt;/em&gt; resist that temptation. As Knuth
remarks in &lt;a href="https://jmlr.csail.mit.edu/reviewing-papers/knuth_mathematical_writing.pdf"&gt;Mathematical Writing&lt;/a&gt;,
the overuse of such symbols just decreases readability.&lt;/p&gt;
&lt;p&gt;As a corollary to the preceding rule, do &lt;em&gt;not&lt;/em&gt; include &amp;lsquo;cosmetic
mathematics&amp;rsquo; in your paper.  Every equation, lemma, proposition, or
theorem should be there because it needs to be there. I know that there
is a tendency for reviewers to look favourably on a paper whose
mathematics seem &amp;lsquo;sufficiently complex&amp;rsquo;, but this is not the right way.
If you want to publish good papers, your first duty is to ensure that
readers of that paper can glean some insights from it. Showing off will
not help in the long run.&lt;/p&gt;
&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Similar to my previous post &lt;a href="https://bastian.rieck.me/blog/2019/on_writing/"&gt;on writing in general&lt;/a&gt;,
the main thing to remember is to know your audience. In machine
learning, this audience can come from highly different backgrounds. Make
them appreciate the ideas in your paper by guiding them gently into the
mathematics. Reserve the &amp;lsquo;heavy stuff&amp;rsquo; for an expert audience that can
give you some actual feedback for it instead of just skimming over it.&lt;/p&gt;
&lt;p&gt;Write well, until next time!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I am assuming throughout this article that your research article
is written for a machine learning conference. You might have to adjust
your writing considerably if you are a mathematician publishing for
other mathematicians&amp;mdash;but in machine learning, many people are not
exclusively trained in mathematics, making writing research papers
a little bit more challenging if you want to do it well.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Whether proofs should be included in machine learning papers at
all is still a matter of debate. I think that a rigorous, principled
exposition in a paper is to be welcomed. Yet, the more our community
expands, the more we have to think about how to successfully get the
point across in our papers! At some point, there will not be
a sufficient number of expert reviewers for highly specific papers,
I fear.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Sat, 14 Nov 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/mathematical_writing/</guid></item><item><title>Exploring a new Postgres database</title><link>/2020/11/14/Exploring-a-new-Postgres-database/</link><description>&lt;p&gt;At past jobs I&amp;rsquo;d estimate we had 100 different production apps that in some way were powering key production systems. Sure some were backend/internal apps while others key production apps such as the dashboard itself. At other companies we had a smaller handful of Heroku apps that powered our cloud service, about 5-10 in total. Even just working with those internal apps it&amp;rsquo;s a number of things to keep context on. But when it comes to interacting with something you don&amp;rsquo;t know getting a lay of the land quickly is key. In helping a customer optimize and tune, or even just understand what is going on in their app an understanding of the data model is key.&lt;/p&gt;
&lt;p&gt;As I just started a few months back at &lt;a href="https://www.crunchydata.com"&gt;Crunchy Data&lt;/a&gt; I found myself digging into a lot of new systems and quickly trying to ramp up and get a feel for them.&lt;/p&gt;
&lt;p&gt;Over the past 10 years I&amp;rsquo;ve pretty well codified my steps to getting a feel for a new database. While I&amp;rsquo;m not a DBA and a small portion of my job is spent &lt;a href="/2013/01/10/more-on-postgres-performance/"&gt;inside a database&lt;/a&gt; being able to quickly navigate one saves me hours each month and days out of the year. I&amp;rsquo;m sure my process isn&amp;rsquo;t perfect, but hopefully it helps other when navigating a new Postgres database for the first time.&lt;/p&gt;
&lt;h3 id="first-the-tooling"&gt;
&lt;div&gt;
First the tooling
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;For any new database my go to tool is psql. The built-in &lt;a href="/2013/02/21/more-out-of-psql/"&gt;Postgres CLI&lt;/a&gt; is going to be the quickest thing for me to navigate around. If you use a CLI for anything else then this should be your preference here as well. I&amp;rsquo;m also going to have a &lt;code&gt;psqlrc&lt;/code&gt; file setup that has some good defaults. My go to defaults in my psqlrc are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sh"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;-- Automatically format output based on result length and screen
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #ae81ff;"&gt;\x&lt;/span&gt; auto
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;-- Prettier nulls
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #ae81ff;"&gt;\p&lt;/span&gt;set null &lt;span style="color: #e6db74;"&gt;'#'&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;-- Save history based on database name
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #ae81ff;"&gt;\s&lt;/span&gt;et HISTFILE ~/.psql_history- :DBNAME
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;-- Turn on automatic query timing
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #ae81ff;"&gt;\t&lt;/span&gt;iming
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="getting-a-feel-for-the-tables"&gt;
&lt;div&gt;
Getting a feel for the tables
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;The first thing I&amp;rsquo;m going to do is just table a look at which objects exist within the database with &lt;code&gt;\d&lt;/code&gt;. This will spit out a mix of tables, views, sequences all within your database. A cleaner version of this may be &lt;code&gt;\dt&lt;/code&gt; which is only tables:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sql"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #960050; background-color: #1e0010;"&gt;\&lt;/span&gt;d
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; List &lt;span style="color: #66d9ef;"&gt;of&lt;/span&gt; relations
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;Schema&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; Name &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Type&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Owner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;--------+-------------------------------+----------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; pg_stat_statements &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;view&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; schema_migrations &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; sessions &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; sessions_id_seq &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; sequence &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; tasks &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; teams &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; users &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;(&lt;span style="color: #ae81ff;"&gt;7&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #960050; background-color: #1e0010;"&gt;\&lt;/span&gt;dt
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; List &lt;span style="color: #66d9ef;"&gt;of&lt;/span&gt; relations
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;Schema&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; Name &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Type&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Owner&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;--------+-------------------------------+----------+----------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; schema_migrations &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; sessions &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; tasks &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; teams &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;public&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; users &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;table&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; postgres
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;(&lt;span style="color: #ae81ff;"&gt;5&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;rows&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can also use the describe operation (&lt;code&gt;\d&lt;/code&gt;) on specific relations as well such as tables to get a feel for how they look:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sql"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #960050; background-color: #1e0010;"&gt;\&lt;/span&gt;d users
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;Table&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;"public.users"&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;Column&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Type&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Collation&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Nullable&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;---------------------------+--------------------------+-----------+----------+--------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;&lt;/span&gt; id &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; uuid &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;not&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;null&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; uuid_generate_v4()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; email &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; text &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;not&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;null&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;''&lt;/span&gt;::text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; encrypted_password &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; text &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;not&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;null&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;''&lt;/span&gt;::text
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; reset_password_token &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; text &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; reset_password_sent_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;timestamp&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;with&lt;/span&gt; time &lt;span style="color: #66d9ef;"&gt;zone&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; remember_created_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;timestamp&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;with&lt;/span&gt; time &lt;span style="color: #66d9ef;"&gt;zone&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; last_sign_in_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;timestamp&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;with&lt;/span&gt; time &lt;span style="color: #66d9ef;"&gt;zone&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; created_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;timestamp&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;with&lt;/span&gt; time &lt;span style="color: #66d9ef;"&gt;zone&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;not&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;null&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; updated_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;timestamp&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;with&lt;/span&gt; time &lt;span style="color: #66d9ef;"&gt;zone&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;not&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;null&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; name &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; text &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;not&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;null&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; team_id &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; uuid &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;not&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;null&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; deleted_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;timestamp&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;with&lt;/span&gt; time &lt;span style="color: #66d9ef;"&gt;zone&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;Indexes:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #e6db74;"&gt;"users_pkey"&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;KEY&lt;/span&gt;, btree (id)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #e6db74;"&gt;"index_users_on_email"&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;UNIQUE&lt;/span&gt;, btree (email)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #e6db74;"&gt;"index_users_on_reset_password_token"&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;UNIQUE&lt;/span&gt;, btree (reset_password_token)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;Foreign&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #66d9ef;"&gt;key&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;constraints&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #e6db74;"&gt;"users_team_id_fkey"&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;KEY&lt;/span&gt; (team_id) &lt;span style="color: #66d9ef;"&gt;REFERENCES&lt;/span&gt; teams(id)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="human-readable-output"&gt;
&lt;div&gt;
Human readable output
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;Of course you may want to go one step further and actually get a sense for the data. Here a basic &lt;code&gt;SELECT&lt;/code&gt; tends to work with a limit 1. As you don&amp;rsquo;t quite know the shape of the data this is where having &lt;code&gt;\x auto&lt;/code&gt; setup within your &lt;code&gt;.psqlrc&lt;/code&gt; file is helpful to autoformat the output to your screen. You can also just manually run &lt;code&gt;\x auto&lt;/code&gt; in your SQL session to get cleaner output.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-sql"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;SELECT&lt;/span&gt; &lt;span style="color: #f92672;"&gt;*&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;FROM&lt;/span&gt; users
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;LIMIT&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;[ RECORD &lt;span style="color: #ae81ff;"&gt;1&lt;/span&gt; ]&lt;span style="color: #75715e;"&gt;-------------+--------------------------------------------------------------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;&lt;/span&gt;id &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;0&lt;/span&gt;a7a3cde&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;3613&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;4073&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;86&lt;/span&gt;a7&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;6&lt;/span&gt;a19b4e62bbe
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;email &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; craig.kerstiens&lt;span style="color: #f92672;"&gt;@&lt;/span&gt;gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;encrypted_password &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #960050; background-color: #1e0010;"&gt;$&lt;/span&gt;&lt;span style="color: #f92672;"&gt;#&lt;/span&gt;IJ937Gmsdf00297sEmdfu12234
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;reset_password_token &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;reset_password_sent_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;remember_created_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;2016&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;07&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;14&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;14&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;31&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;01&lt;/span&gt;.&lt;span style="color: #ae81ff;"&gt;414795&lt;/span&gt;&lt;span style="color: #f92672;"&gt;+&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;last_sign_in_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;2020&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;02&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;12&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;21&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;32&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;53&lt;/span&gt;.&lt;span style="color: #ae81ff;"&gt;629246&lt;/span&gt;&lt;span style="color: #f92672;"&gt;+&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;created_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;2016&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;02&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;18&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;03&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;03&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;26&lt;/span&gt;.&lt;span style="color: #ae81ff;"&gt;403108&lt;/span&gt;&lt;span style="color: #f92672;"&gt;+&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;updated_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;2020&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;02&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;14&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;23&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;16&lt;/span&gt;:&lt;span style="color: #ae81ff;"&gt;16&lt;/span&gt;.&lt;span style="color: #ae81ff;"&gt;080729&lt;/span&gt;&lt;span style="color: #f92672;"&gt;+&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;name &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; Craig
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;team_id &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; d46e864&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;1886&lt;/span&gt;&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;45&lt;/span&gt;e6&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;b538&lt;span style="color: #f92672;"&gt;-&lt;/span&gt;&lt;span style="color: #ae81ff;"&gt;8991562&lt;/span&gt;d2e99
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;deleted_at &lt;span style="color: #f92672;"&gt;|&lt;/span&gt; &lt;span style="color: #f92672;"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;Time: &lt;span style="color: #ae81ff;"&gt;91&lt;/span&gt;.&lt;span style="color: #ae81ff;"&gt;592&lt;/span&gt; ms
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Most databases I work with now leverage JSONB. It&amp;rsquo;s a great tool for mixing semi-structured data with more structured data.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re using &lt;a href="https://info.crunchydata.com/blog/using-postgresql-for-json-storage"&gt;JSON&lt;/a&gt; or &lt;a href="https://info.crunchydata.com/blog/using-postgresql-for-json-storage"&gt;JSONB&lt;/a&gt; then there is also a handy utility function to clean up that output - &lt;code&gt;jsonb_pretty(yourcolumnhere)&lt;/code&gt;. This will take care of making that huge JSON blob nice and readable.&lt;/p&gt;
&lt;h3 id="feel-more-at-home-when-you-encounter-a-new-database"&gt;
&lt;div&gt;
Feel more at home when you encounter a new database
&lt;/div&gt;
&lt;/h3&gt;
&lt;p&gt;It doesn&amp;rsquo;t take hours of reading an ERD or schema files. In about 5-10 minutes of connecting to a new database I&amp;rsquo;m able to get a sense of how things are structured and able to actually start digging in. Don&amp;rsquo;t get me wrong, I&amp;rsquo;m by no means and expert in that time, but knowing some of these basic commands will really help the next time you encounter a database and are asked to help out or glean insights from it.&lt;/p&gt;</description><author>CRAIG KERSTIENS</author><pubDate>Sat, 14 Nov 2020 21:30:56 GMT</pubDate><guid isPermaLink="true">/2020/11/14/Exploring-a-new-Postgres-database/</guid></item><item><title>The second half of MANY chessboards</title><link>https://stop.zona-m.net/2020/11/the-second-half-of-many-chessboards/</link><description>&lt;p&gt;I&amp;rsquo;ts just where we ALL are, right now. And it&amp;rsquo;s dangerous.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 14 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/the-second-half-of-many-chessboards/</guid></item><item><title>The Roaring 2020's</title><link>https://www.swyx.io/roaring-2020s</link><description>Five themes I am optimistic about for the next decade - and more open questions I have no idea about.</description><author>swyx's site RSS Feed</author><pubDate>Sat, 14 Nov 2020 15:25:42 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/roaring-2020s</guid></item><item><title>Blog update</title><link>https://anisse.astier.eu/blog-update.html</link><description>&lt;p&gt;I recently updated the server where this blog is hosted, so I tought I'd do an update on the &lt;a href="hello-world.html"&gt;original post&lt;/a&gt; explaining the tech stack used to run it. Once in seven years shouldn't be too meta.&lt;/p&gt;
&lt;h3&gt;The design&lt;/h3&gt;
&lt;p&gt;First of all, kudos to &lt;a href="https://www.linkedin.com/in/pascalnaviere/"&gt;Pascal Navière&lt;/a&gt;, a very talented polymath …&lt;/p&gt;</description><author>Linux Engineer's random thoughts</author><pubDate>Sat, 14 Nov 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://anisse.astier.eu/blog-update.html</guid></item><item><title>The opaqueness of "Be Not Evil"</title><link>https://stop.zona-m.net/2020/11/the-opaqueness-of-be-not-evil/</link><description>&lt;p&gt;It is annoyingly hard to understand how to break up Google.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 13 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/the-opaqueness-of-be-not-evil/</guid></item><item><title>Writing Your Own Scraper - Simple Instagram Scraper</title><link>https://geo.rocks/post/writing-your-own-instagram-scraper/</link><description>&lt;p&gt;&lt;img alt="Picture by NeONBRAND on Unsplash" src="https://images.unsplash.com/photo-1505322747495-6afdd3b70760?ixlib=rb-1.2.1&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=1050&amp;amp;q=80" title="Picture by NeONBRAND on Unsplash" /&gt;
Photo by &lt;a href="https://unsplash.com/@neonbrand?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;NeONBRAND&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/instagram?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;How to write your DYI Instagram Scraper&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Fri, 13 Nov 2020 18:44:28 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/writing-your-own-instagram-scraper/</guid></item><item><title>M1 Memory and Performance</title><link>https://blog.metaobject.com/2020/11/m1-memory-and-performance.html</link><description>The M1 Macs are out now, and not only does Apple claim they're absolutely smokin', early benchmarks
seem to confirm those claims.  I don't find this surprising, Apple has been highly focused on 
performance ever since Tiger, and as far as I can tell hasn't let up since.&lt;p&gt;

One maybe somewhat surprising aspect of the M1s is the limitation to "only" 
16 Gigabytes of memory.  As someone who bought a 16 &lt;em&gt;Kilo&lt;/em&gt;byte language card to run the Merlin
6502 assembler on his Apple ][+ and expanded his NeXT cube, which isn't &lt;em&gt;that&lt;/em&gt; different from
a modern Mac, to a 
whopping 16 &lt;em&gt;Mega&lt;/em&gt;bytes, this doesn't actually seem that much of a limitation, but it did
cause a bit of consternation.&lt;p&gt;

I have a bit of a theory as to how this "limitation" might tie in to how Apple's outside-the-box
approach to memory and performance has contributed to the remarkable achievement that is the M1.&lt;p&gt;

The M1 is apparently a multi-die package that contains both the actual processor die and the
DRAM.  As such, it has a very high-speed interface between the DRAM and the processors.
This high-speed interface, in addition to the absolutely humongous caches, is key to keeping the various functional
units fed.  Memory bandwidth and latency are probably &lt;em&gt;the&lt;/em&gt; determining factors for many
of today's workloads, with a single access to main memory taking easily hundreds of clock cycles
and the CPU capable of doing a good number of operations in each of these clock cycles.
As Andrew Black &lt;a href="http://web.cecs.pdx.edu/~black/publications/O-JDahl.pdf"&gt;wrote&lt;/a&gt;:  "[..] computation is essentially free, because it happens 'in the cracks' between data fetch and data store; ..".&lt;p&gt;

The tradeoff is that you can only fit so much DRAM in that package for now, but if it fits,
it's going to be super fast.&lt;p&gt;

So how do we make sure it all fits?  Well, where Apple might have been "focused" on performance
for the last 15 years or so, they have been completely &lt;em&gt;anal&lt;/em&gt; about memory consumption.
When I was there, we were fixing 32 &lt;em&gt;byte&lt;/em&gt; memory leaks.  Leaks that happened &lt;em&gt;once&lt;/em&gt;.
So not an ongoing consumption of 32 bytes again and again, but a one-time leak of 32 bytes.&lt;p&gt;

That dedication verging on the obsessive is one of the reasons iPhones have been besting 
top-of-the-line Android phone that have twice the memory.  And not by a little, either.&lt;p&gt;

Another reason is the iOS team's steadfast refusal to adopt tracing garbage collection as
most of the rest of the industry did,
and macOS's later abandonment of that technology in favor of the reference counting (RC) they've
been using since NeXTStep 4.0.  With increased automation of those reference counting operations
and the addition of weak references, the convenience level for developers is essentially 
indistinguishable from a tracing GC now.&lt;p&gt;

The benefit of sticking to RC is much-reduced memory consumption.  It &lt;a href="https://people.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf"&gt;turns out&lt;/a&gt; that for
a tracing GC to achieve performance comparable with manual allocation, it needs several
times the memory (different studies find different overheads, but at least 4x is a conservative
lower bound).  While I haven't seen a study comparing RC, my personal experience is that the
overhead is much lower, much more predictable, and can usually be driven down with little
additional effort if needed.&lt;p&gt;

So Apple can afford to live with more "limited" total memory because they need much less
memory for the system to be fast.  And so they can do a system design that imposes this
limitation, but allows them to make that memory wicked fast. &lt;em&gt;Nice&lt;/em&gt;.&lt;p&gt;

Another "well-known" limitation of RC that has made it the second choice compared to tracing
GC is the fact that updating those reference counts all the time is expensive, particularly
in a multi-threaded environment where those updates need to be atomic. Well...&lt;p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;fun fact: retaining and releasing an NSObject takes ~30 nanoseconds on current gen Intel, and ~6.5 nanoseconds on an M1&lt;/p&gt;&amp;mdash; David Smith (@Catfish_Man) &lt;a href="https://twitter.com/Catfish_Man/status/1326238434235568128?ref_src=twsrc%5Etfw"&gt;November 10, 2020&lt;/a&gt;&lt;/blockquote&gt; 

How?

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;We got that working on x86-64 too :) this further improvement is because uncontended acquire-release atomics are about the same speed as regular load/store on A14&lt;/p&gt;&amp;mdash; David Smith (@Catfish_Man) &lt;a href="https://twitter.com/Catfish_Man/status/1326298205034696705?ref_src=twsrc%5Etfw"&gt;November 10, 2020&lt;/a&gt;&lt;/blockquote&gt; 

Problem solved. I guess it helps if you can make your own Silicon ;-)&lt;p&gt;


So Apple's focus on keeping memory consumption under control, which includes but is not limited
to going all-in on reference counting where pretty much the rest of the industry has adopted
tracing garbage collection, is now paying off in a majory way ("bigly"?  Too soon?).  They can get away 
with putting less memory in the system, which makes it possible to make that memory really fast.
And that locks in an advantage that'll be hard to duplicate.&lt;p&gt;

It also means that native development will have a bigger advantage compared to web technologies,
because native apps benefit from the speed and don't have a problem with the memory limitations,
whereas web-/electron apps will fill up that memory much more quickly.&lt;p&gt;</description><author>metablog</author><pubDate>Fri, 13 Nov 2020 14:46:29 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2020/11/m1-memory-and-performance.html</guid></item><item><title>Stashy is a Really simple Key Value store</title><link>https://secretGeek.net/stashy_gist</link><description>&lt;p&gt;In my various websites and web applications, I often need to store some things and later retrieve them.&lt;/p&gt;
&lt;p&gt;Mostly for this I use a really simple key value store called &amp;quot;Stashy&amp;quot;, that I built, oh, decades ago.&lt;/p&gt;
&lt;p&gt;Imagine I have a &amp;quot;plain old class object&amp;quot;, and I want to save it. It might be an object called &amp;quot;myNewBlogPost&amp;quot;.&lt;/p&gt;
&lt;p&gt;I will call:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;stashy.Save&amp;lt;BlogPost&amp;gt;(myNewBlogPost, myNewBlogPost.Slug);
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Later, if I want to load that blog post, I will need to know the key I used, let's say it was &amp;quot;hello-world&amp;quot;:&lt;/p&gt;

&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;var myNewBlogPost = stashy.Load&amp;lt;BlogPost&amp;gt;(&amp;quot;hello-world&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;And there's also a method for loading all objects of a given type:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;var myBlogPosts = stashy.LoadAll&amp;lt;BlogPost&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;And for deleting a single object:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;stashy.Delete&amp;lt;BlogPost&amp;gt;(&amp;quot;hello-world&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;And that's it!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It's not distributed. It doesn't have a query language. It doesn't have built in caching semantics. It's not even async.&lt;/p&gt;
&lt;p&gt;I tell you what it does have: &lt;strong&gt;utility&lt;/strong&gt;. It's bloody useful! I would definitely not consider it for cases with millions of records, but 1000 or under? It's &lt;em&gt;fine!&lt;/em&gt; And one less thing to worry about.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Stashy&lt;/code&gt; class is an implementation of the &lt;code&gt;IStashy&lt;/code&gt; interface. This makes it easier to test, and helps me with the dependency injection stuff. Mostly it serves to make sure I'm keeping the contract &lt;em&gt;small&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;IStashy&lt;/code&gt; interface is just this:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;code&gt;public interface IStashy&amp;lt;K&amp;gt;
{
    void Save&amp;lt;T&amp;gt;(T t, K id);
    T Load&amp;lt;T&amp;gt;(K id);
    IEnumerable&amp;lt;T&amp;gt; LoadAll&amp;lt;T&amp;gt;();
    void Delete&amp;lt;T&amp;gt;(K id);
    K GetNewId&amp;lt;T&amp;gt;();
}
&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;The type &lt;code&gt;K&lt;/code&gt; is the type of key you want to use. I usually use strings as my key. But you can use integers or guids, or anything else, if you like.&lt;/p&gt;
&lt;p&gt;As I tweeted recently, &lt;a href="https://twitter.com/secretGeek/status/1327038572558393345?s=20"&gt;The heart and soul of my most used key-value store fits in a single tweet. Easily!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I've used a couple of different implementations of this interface over the years, but currently what it does is serialize the object as &lt;code&gt;JSON&lt;/code&gt; and then store it in a file named after the key, in a sub-folder named after the &lt;code&gt;type&lt;/code&gt; of the object. (I also have a completely in-memory implementation, for testing etc.)&lt;/p&gt;
&lt;p&gt;Here's an implementation I use at the moment in one of my projects. It is &lt;em&gt;not&lt;/em&gt; glorious beautiful wondrous code, but it is working code that I just... well I just never have to look at it. But I rely on it &lt;em&gt;all&lt;/em&gt; the time:&lt;/p&gt;
&lt;p&gt;&lt;a class="action" href="https://gist.github.com/secretGeek/1afc53356373cc4c790876adf6a356cf" target="_blank"&gt;see gist: FileStashy.cs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It's about 100 lines of code, written &lt;em&gt;years&lt;/em&gt; ago, and relies on &lt;code&gt;Newtonsoft.Json&lt;/code&gt; to turn objects into Json and vice-versa.&lt;/p&gt;
&lt;p&gt;(10 years ago my FileStashy used XML, on Windows... Now it's all Json, and runs anywhere that .net core runs. Maybe one day, one &lt;em&gt;special&lt;/em&gt; day, we'll all switch to &lt;a href="https://github.com/secretGeek/AwesomeCSV"&gt;CSV&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Sometimes I build other stuff on-top of Stashy, such as indexes, for faster lookups, and &amp;quot;revisions&amp;quot;, so I can look at old versions of an object. That was easy enough to write (and very fun of course!) but I wouldn't want to do too much with it, or I'd switch to a &lt;em&gt;real&lt;/em&gt; key value store... but then get all the headaches that come from those.&lt;/p&gt;
 &lt;p&gt;Got any crufty little things you've rolled yourself instead of using something "better"?&lt;/p&gt;</description><author>secretgeek.net</author><pubDate>Fri, 13 Nov 2020 01:22:14 GMT</pubDate><guid isPermaLink="true">https://secretGeek.net/stashy_gist</guid></item><item><title>How we switched to 4-day weeks</title><link>https://www.gingerlime.com/2020/how-we-switched-to-4-day-weeks/</link><description>&lt;p&gt;We recently made a landmark decision at my company. Starting from Friday, 1st January, 2021, all Fridays are now part of the weekend. We&amp;#8217;ll be working Mon-Thu all year round. This is still considered an &amp;#8220;experiment&amp;#8221;, because we don&amp;#8217;t know if it&amp;#8217;s something we can commit to long-term. But honestly, I can&amp;#8217;t imagine going back.&amp;#8230;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://www.gingerlime.com/2020/how-we-switched-to-4-day-weeks/"&gt;How we switched to 4-day weeks&lt;/a&gt; appeared first on &lt;a href="https://www.gingerlime.com"&gt;Gingerlime&lt;/a&gt;.&lt;/p&gt;</description><author>Gingerlime</author><pubDate>Thu, 12 Nov 2020 21:28:43 GMT</pubDate><guid isPermaLink="true">https://www.gingerlime.com/2020/how-we-switched-to-4-day-weeks/</guid></item><item><title>Building a HomeKit compatible temperature and humidity sensor</title><link>https://tommasoamici.com/blog/building-a-homekit-compatible-temperature-and-humidity-sensor/</link><description>In this short post I'll explain how I set up a HomeKit compatible temperature and humidity sensor with a ESP8266 chip, Homebridge, and an AM2302 sensor&lt;hr /&gt;&lt;a href="https://tommasoamici.com/blog/building-a-homekit-compatible-temperature-and-humidity-sensor/"&gt;Read more&lt;/a&gt;</description><author>Tommaso Amici</author><pubDate>Thu, 12 Nov 2020 21:12:35 GMT</pubDate><guid isPermaLink="true">https://tommasoamici.com/blog/building-a-homekit-compatible-temperature-and-humidity-sensor/</guid></item><item><title>Contact tracing failures, again</title><link>https://stop.zona-m.net/2020/11/contact-tracing-failures-again/</link><description>&lt;p&gt;Nobody cares. But it still HAS value.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 12 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/contact-tracing-failures-again/</guid></item><item><title>Deleting Browser Cache with Python Selenium and Chromedriver</title><link>https://geo.rocks/post/deleting-browser-cache-with-python-selenium-and-chromedriver/</link><description>&lt;p&gt;&lt;img alt="Picture by Selenium" src="https://selenium-python.readthedocs.io/_static/logo.png" title="Picture by Selenium on readthedocs" /&gt;&lt;/p&gt;
&lt;p&gt;Quick and dirty&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Thu, 12 Nov 2020 17:03:58 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/deleting-browser-cache-with-python-selenium-and-chromedriver/</guid></item><item><title>AI breaks the game of hide and seek</title><link>https://ilearnt.com/blog/hideandseek/</link><description>&lt;p&gt;This is a really fun &lt;a href="https://www.youtube.com/watch?v=Lu56xVlZ40M" target="_blank"&gt;video&lt;/a&gt; where an AI is given a version of the game of hide and seek and each team has to learn ways to win - either by finding the other team or by not being found.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Thu, 12 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/hideandseek/</guid></item><item><title>Why I use GNU GPL (v3+)</title><link>https://thatxliner.github.io/posts/why-i-use-gnu-gpl-v3/</link><description>Because it's great.</description><author>ThatXliner's Blog</author><pubDate>Thu, 12 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://thatxliner.github.io/posts/why-i-use-gnu-gpl-v3/</guid></item><item><title>My First PC</title><link>https://boyter.org/posts/first-pc/</link><description>&lt;p&gt;At my current workplace we have been doing themed Friday stand-ups. The most recent was about your first PC love, or whatever technology you look back on fondly. What follows is my one.&lt;/p&gt;
&lt;p&gt;My first PC was I think a Commodore PC40-III. I&amp;rsquo;m a little fuzzy on the details and its hard to find it based on pictures. Was not my first taste of technology, but the one I look on back most fondly.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Thu, 12 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/first-pc/</guid></item><item><title>Why you want OPEN System-on-Chips</title><link>https://stop.zona-m.net/2020/11/why-you-want-open-system-on-chips/</link><description>&lt;p&gt;Because microelectronics is what makes the world go round.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 11 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/why-you-want-open-system-on-chips/</guid></item><item><title>The Light and Dark Side of the API Economy</title><link>https://www.swyx.io/api-economy</link><description>The 'API Economy' is a popular term for VC's and tech media, however Developers seem ironically out of the loop despite their central importance to the whole story. Here's my explanation, together with a dash of economics and social implications.</description><author>swyx's site RSS Feed</author><pubDate>Wed, 11 Nov 2020 18:07:36 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/api-economy</guid></item><item><title>Building Product</title><link>https://ferrucc.io/posts/building-product/</link><description>&lt;p&gt;If you&amp;rsquo;re working on something new, there are so many directions your work and product can take.&lt;/p&gt;
&lt;p&gt;The biggest risk is that you build something that is hard to explain and no one wants.&lt;/p&gt;
&lt;p&gt;A good process minimizes this risk. Helping you move in the direction of building something people want.&lt;/p&gt;
&lt;p&gt;To build &lt;a href="https://june.so"&gt;June&lt;/a&gt; me and my cofounder &lt;a href="https://twitter.com/0zne"&gt;Enzo&lt;/a&gt; used a very systematic approach. We decided to shared it as you might find useful.&lt;/p&gt;</description><author>ferrucc.io</author><pubDate>Wed, 11 Nov 2020 11:00:58 GMT</pubDate><guid isPermaLink="true">https://ferrucc.io/posts/building-product/</guid></item><item><title>Our work on obtaining dissolution profiles from single controlled-release drug particles using vibrating tube sensors published in &amp;lt;i&amp;gt;Scientific Reports&amp;lt;/i&amp;gt;</title><link>http://groverlab.org/news/2020/11/11/controlled-release.html</link><description>&lt;p&gt;&lt;img alt="" src="/assets/controlled_release_1.png" /&gt;&lt;/p&gt;

&lt;p&gt;Heran Bhakta and Jessica Lin’s paper “Measuring dissolution profiles of single controlled-release drug pellets” was &lt;a href="https://www.nature.com/articles/s41598-020-76089-z"&gt;published in &lt;em&gt;Scientific Reports&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Heran and Jessica show that a simple and inexpensive vibrating tube sensor can measure the dissolution of single microgram-sized controlled-release pellets in physiologically relevant fluids with nanogram-scale resolution. Their technique addresses many of the shortcomings of existing USP testing methods, requires no additional analytical instrumentation like UV-VIS or HPLC, and is suitable for both fast-dissolving and slow-dissolving formulations. And by obtaining dissolution profiles for single pellets instead of populations of pellets, their technique is capable of measuring pellet-to-pellet variations in dissolution behavior that are much more difficult to measure using existing methods. Using this technique, we observed significant variations in single-pellet dissolution profiles, not only between different types of drugs in different physiological conditions, but also between generic and name-brand formulations of the same drug, and even between different pellets from the exact same capsule.&lt;/p&gt;

&lt;p&gt;This technique provides pharmaceutical researchers and producers with a simple, low-cost, and fully automated tool for obtaining single-pellet dissolution profiles from any drug in any desired fluid. This capability should be powerful in a variety of different scenarios. For example, measurements of the dissolution behavior of pellets from each production batch can provide valuable quality assurance data and illuminate possible production defects before the product reaches consumers. Even within a single batch, single pellet dissolution profiles provide information about the consistency of the pellet manufacturing process. And as a gravimetric (mass-based) method, this technique places no constraints on the chemical or physical composition of the fluid surrounding the pellet, meaning that pharmaceutical developers are free to measure pellet dissolution in any physiologically-relevant fluid without fear that the fluid will interfere with the measurement process. For these reasons, vibrating tube sensors should help facilitate the development of better controlled-release pharmaceuticals with better patient outcomes.&lt;/p&gt;</description><author>Grover Lab</author><pubDate>Wed, 11 Nov 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">http://groverlab.org/news/2020/11/11/controlled-release.html</guid></item><item><title>Power Costs</title><link>https://blog.herlein.com/post/power/</link><description>&lt;p&gt;A quick measure of the costs of running on-premise computers.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Wed, 11 Nov 2020 10:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/power/</guid></item><item><title>i3 Migration Guide</title><link>https://cookie.engineer/weblog/articles/i3-migration-guide.html</link><description>Tutorial on how to migrate to the i3 window manager with explanations for typical keybindings, configuration problems and status bar integrations.</description><author>Cookie Engineer's Web Log</author><pubDate>Wed, 11 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://cookie.engineer/weblog/articles/i3-migration-guide.html</guid></item><item><title>The impact of management teams as a decision-making group, in startups and enterprise</title><link>http://notes.eatonphil.com/the-impact-of-management-teams-on-startups-and-enterprises.html</link><description>&lt;p&gt;Ambitious companies form management teams at every level above you,
sometimes including you. Management teams meet periodically and have
private chat rooms. They discuss customers, product and organizational
direction. Sometimes discussions are well documented and periodically
public. Sometimes decisions are poorly telegraphed out.&lt;/p&gt;
&lt;p&gt;Management teams do no inherent harm in a company with customers;
employees outside of the management team can unearth customer usage
data to discover meaningful places to contribute. For example,
graphing historic server logs to discover slowest requests, figure out
why and how to fix. Or even just paying attention to the most frequent
questions sales asks and finding ways to clarify. (All of this under
the assumption that even when there is solid product direction, good
employees tend to have extra time at work and want to make good use of
it.)&lt;/p&gt;
&lt;p&gt;For the first few years even in a well-funded startup with solid
founders, there are few customers. Even under a solid product team,
the product direction is not yet completely clear. The management team
includes founders and non-engineering executives. As a decision making
group they are opaque. Employees outside the management team face a
barrier in finding ways to meaningful contribute. Ambitious, dedicated
folks outside the team leave.&lt;/p&gt;
&lt;h3 id="so-what?"&gt;So what?&lt;/h3&gt;&lt;p&gt;It is not clear to me how the natural (and not inherently bad) concept
of management teams attracts and retains ambitious, dedicated
non-founders at small companies. Maybe disenfranchisement is not
important, or even necessary.&lt;/p&gt;
&lt;p&gt;Or maybe management teams as a decision-making group are too easily a
substitute for developing a grassroots culture of collaboration and
trust between marketing, sales, product and development.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;New post! &amp;quot;management teams as a decision-making group are too easily a substitute for developing a grassroots culture of collaboration and trust between marketing, sales, product and development.&amp;quot;&lt;a href="https://t.co/7RukBMI59h"&gt;https://t.co/7RukBMI59h&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1328482381314084864?ref_src=twsrc%5Etfw"&gt;November 16, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Wed, 11 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/the-impact-of-management-teams-on-startups-and-enterprises.html</guid></item><item><title>Watch out! Vokenization is coming!</title><link>https://stop.zona-m.net/2020/11/watch-out-vokenization-is-coming/</link><description>&lt;p&gt;Computers are learning the colour of sheeps. Here is why it matters.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 10 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/watch-out-vokenization-is-coming/</guid></item><item><title>The growing power of influencers</title><link>https://ilearnt.com/blog/thepowerofinfluencers/</link><description>&lt;p&gt;Quite often I will come across long articles and either put off reading them or just skim through their content. This &lt;a href="https://redef.com/original/age-of-abundance-how-the-content-explosion-will-invert-the-media-industry" target="_blank"&gt;article&lt;/a&gt; is well worth taking the time to read as it completely changed my views on where the media industry is heading. My notes here do not do it justice but will hopefully give you enough to encourage you to read it in full.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Tue, 10 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/thepowerofinfluencers/</guid></item><item><title>My thoughts on PiHole</title><link>https://heitorpb.github.io/bla/pihole-dnsmasq/</link><description>My experience with PiHole after one month.</description><author>Heitor's log</author><pubDate>Tue, 10 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://heitorpb.github.io/bla/pihole-dnsmasq/</guid></item><item><title>Rust as a productive high-level language</title><link>https://omarabid.com/rust-high-level-language/</link><description>High-level productivity with Rust</description><author>Omar Abid - Personal Blog</author><pubDate>Tue, 10 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://omarabid.com/rust-high-level-language/</guid></item><item><title>Michelin Stars for Celiacs: Angler, San Francisco: Not recommended</title><link>https://rob.sh/post/angler-sf-celiac/</link><description>&lt;p&gt;As some folks might be aware, I became allergic to gluten and dairy through the spring of 2019, and have been avoiding them in my diet since. Becca and I have not lost our passion for eating great foods, and visiting some of the fantastic restaurants in the cities we visit (although, in 2020, this has meant a lot of places in the Bay Area). One of the things that we&amp;rsquo;ve struggled a bit with is finding out how well some of the Michelin star establishments handle the gluten-free, dairy-free diet. This weekend, after a visit to Angler - down on the Embarcadero, here in San Francisco - we discussed that it&amp;rsquo;d be useful if there was more information available for folks that are celiac and interested in fine dining. So this is the first post &amp;ndash; I&amp;rsquo;ll try and add some reviews of previous places we&amp;rsquo;ve eaten through the next few weeks.&lt;/p&gt;</description><author>rob.sh</author><pubDate>Mon, 09 Nov 2020 23:30:00 GMT</pubDate><guid isPermaLink="true">https://rob.sh/post/angler-sf-celiac/</guid></item><item><title>The coming, dangerous hyper-segmentation of "news"</title><link>https://stop.zona-m.net/2020/11/the-coming-dangerous-hyper-segmentation-of-news/</link><description>&lt;p&gt;It&amp;rsquo;s bad, and it is on ALL sides.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 09 Nov 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/the-coming-dangerous-hyper-segmentation-of-news/</guid></item><item><title>Borat Subsequent Moviefilm</title><link>https://olshansky.info/movie/borat_subsequent_moviefilm/</link><description>Olshansky's review of Borat Subsequent Moviefilm</description><author>🦉 olshansky 🦁</author><pubDate>Mon, 09 Nov 2020 10:28:10 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/borat_subsequent_moviefilm/</guid></item><item><title>Individualism Vs Collectivism</title><link>https://reticulated.net/posts/individualismvscollectivism/</link><description>It&amp;rsquo;s odd when you think about how most of your understanding of the world, your political views, your goals, and much more is defined by just a few experiences. I can lay out the path from being born a southern, Christian-by-default, Republican-by-default kid to a Democratic Atheist person whose not sold on the virtues or unendingness of Capitalism.
Funnily, the International House of Pancakes has quite a bit to do with the start of all that, but I&amp;rsquo;ll save some of those stories for another post.</description><author>Reticulated</author><pubDate>Mon, 09 Nov 2020 02:25:01 GMT</pubDate><guid isPermaLink="true">https://reticulated.net/posts/individualismvscollectivism/</guid></item><item><title>Towards a Lightweight Jamstack</title><link>https://phacks.dev/articles/towards-a-lightweight-jamstack</link><description>This article aims to give directions to curb the JavaScript tax in the Jamstack.</description><author>Nicolas Goutay</author><pubDate>Mon, 09 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://phacks.dev/articles/towards-a-lightweight-jamstack</guid></item><item><title>The modern editor war</title><link>https://thatxliner.github.io/posts/the-modern-editor-war/</link><description>Goodbye, Emacs</description><author>ThatXliner's Blog</author><pubDate>Mon, 09 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://thatxliner.github.io/posts/the-modern-editor-war/</guid></item><item><title>Dissonance: Your Tolerance to Change</title><link>http://spirals.blog/articles/6-conditions-of-change/dissonance/</link><description>&lt;p&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/"&gt;👈 Back to all conditions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Our third condition that unlocks the door of real change is the ever-so-stubborn beast of &lt;strong&gt;Dissonance&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What’s Dissonance, you may ask? Put simply, how much does the boat need to rock before a change occurs? Do you &lt;em&gt;feel&lt;/em&gt; enough tension to get off your but and do something?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dissonance: The awareness of a gap between life’s present conditions and our current means of solving them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Put bluntly, Dissonance is the fire under you that makes you move your ass when it gets too hot.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dissonance: Your Tolerance to change" src="http://spirals.blog/articles/6-conditions-of-change/dissonance/dissonance.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;Rocking the boat&lt;/h2&gt;
&lt;p&gt;Have you ever had one fight too many in your relationship? You know that big one? The one that leaves you thinking, “That’s it! No more”.&lt;/p&gt;
&lt;p&gt;What about at work? One task too many, or failed project later, and you feel it’s about time to move on to greener pastures?&lt;/p&gt;
&lt;p&gt;Perhaps the climate gets too hot, and you move towns. Or you get enough comments from your friends that it’s time to give up partying and settle down.&lt;/p&gt;
&lt;p&gt;In our image above, Mr. Blue comes home to one too many of Mr. Red’s parties. He’s thinking it might be time to find a new flatmate.&lt;/p&gt;
&lt;p&gt;We are not strangers to Dissonance. It’s often the driving force that pushes us into new life choices, relationships, ideas, beliefs, and even towns!&lt;/p&gt;
&lt;p&gt;Before the moment of change sets in, we feel the &lt;em&gt;tension&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But it’s not yet painful enough for us to do anything about it. Depending on our pain tolerance, &lt;a href="https://spirals.blog/articles/6-conditions-of-change/potential/"&gt;Potential&lt;/a&gt;, and how much we care about the situation, we may stay where we are for a &lt;em&gt;good while&lt;/em&gt;. We’re more stubborn than we give ourselves credit for, us humans.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Many of us have things we want in our lives, but we don’t have a strong enough reason to realize them.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The fire beneath us is not hot enough to warrant moving away. At least for now…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The amount of disharmony (&lt;strong&gt;Dissonance&lt;/strong&gt;) needed to create change is determined by the &lt;em&gt;willingness&lt;/em&gt; to change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;How stubborn are you?&lt;/h2&gt;
&lt;h3&gt;Getting to know your tolerance for Dissonance&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Dissonance meter: How high is your tolerance?" src="http://spirals.blog/articles/6-conditions-of-change/dissonance/dissonance-meter.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We all have a level. It’s that point before we break and make something happen. When we get pushed too far, or the world is too much, and where the thermometer bursts. We make a change. Sometimes even a snap-decision!&lt;/p&gt;
&lt;p&gt;Of course, we can have different levels for different parts of our life also!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Dissonance levels for each part of our life" src="http://spirals.blog/articles/6-conditions-of-change/dissonance/dissonance-levels.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I may have a &lt;strong&gt;high Dissonance tolerance&lt;/strong&gt; for my &lt;strong&gt;relationship&lt;/strong&gt;. This could mean it would take a lot of heat (strong Dissonance) to change the dynamics.&lt;/p&gt;
&lt;p&gt;I could also have a &lt;em&gt;&lt;strong&gt;low Dissonance tolerance&lt;/strong&gt;&lt;/em&gt; with &lt;strong&gt;work&lt;/strong&gt;, implying I’m jumping from companies all the time due to my frustrations with company politics.&lt;/p&gt;
&lt;p&gt;Sometimes these levels work for us, and other times they don’t. Sometimes high tolerance is good, and sometimes it’s not.&lt;/p&gt;
&lt;p&gt;Your tolerance could be &lt;strong&gt;too high&lt;/strong&gt; if your mirror’s reflection starts saying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“I’ve just gotta stick with it” when everyone’s telling you to relax.&lt;/li&gt;
&lt;li&gt;“He’ll change one of these days, I know it!” when your friends are praying that you’ll leave him.&lt;/li&gt;
&lt;li&gt;“I refuse to change” when the world is demanding it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And your tolerance may be &lt;strong&gt;too low&lt;/strong&gt; when it says:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“This place is already on my nerves” when you haven’t even worked a month at the new job.&lt;/li&gt;
&lt;li&gt;“She’s not the same as when we first met”, but you’ve only been dating 2 weeks.&lt;/li&gt;
&lt;li&gt;“I give up” when you’ve only just started.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Using Dissonance&lt;/h2&gt;
&lt;p&gt;As always, A Matter of Perspective likes to provide &lt;em&gt;practical&lt;/em&gt; tools take us away from theory alone. How might we employ &lt;strong&gt;Dissonance&lt;/strong&gt; as a catalyst for change?&lt;/p&gt;
&lt;p&gt;The first step is to assess the &lt;a href="https://spirals.blog/articles/6-conditions-of-change/potential/"&gt;“Potential” of a given system &lt;/a&gt;(the first Condition of Change). If the system/person/group is &lt;strong&gt;Closed&lt;/strong&gt;, a heavy dose of &lt;strong&gt;Dissonance&lt;/strong&gt; may be required to shake the shackles loose. &lt;em&gt;&lt;strong&gt;It may not even be worth the effort.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;However, if they remain &lt;strong&gt;Open&lt;/strong&gt; to new ideas and ways of life, then the boat requires less rocking. They are already willing to change and half out the boat.&lt;/p&gt;
&lt;p&gt;In the case that &lt;strong&gt;Dissonance&lt;/strong&gt; &lt;strong&gt;IS&lt;/strong&gt; needed, what might that look like? Consider a personal coach that picks up a client early every morning. Should the lazy client decide they want to sleep in, the coach promptly holds the horn until they drag themselves out of bed and into the car. He is creating such conditions in life that will force you to change. The neighbors love him.&lt;/p&gt;
&lt;p&gt;Another example may lie in a corporation attempting to shift it’s work culture. At a management level, it may decide to hire a very new type of employee in hopes of stimulating fresh ideas and energy. With enough new people pushing for a new idea, the old ones may begin to loosen, creating a shift towards a different culture. All provided they’re open, of course 😉 (they’re often not, and this creates a big dilemma).&lt;/p&gt;
&lt;p&gt;In our own lives, we may use this key-of-change to push ourselves. Getting ourselves to a meditation retreat when we least want it and most need it. Throwing out all the junk food. Giving ourselves a vacation. Depending on your situation (and if it’s required), there may be many ways to inject a little &lt;strong&gt;Dissonance&lt;/strong&gt;. To put some fire under your belly.&lt;/p&gt;
&lt;p&gt;Provided you need to change. And &lt;em&gt;&lt;strong&gt;can&lt;/strong&gt;&lt;/em&gt; change.&lt;/p&gt;
&lt;p&gt;Often, we can just enjoy where we are and go along for the boat–ride.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Boat" src="http://spirals.blog/articles/6-conditions-of-change/dissonance/boat.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/"&gt;👈 Back to all conditions&lt;/a&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Mon, 09 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/6-conditions-of-change/dissonance/</guid></item><item><title>How-to revert HP printer firmware ban on 3rd-party toner cartridges</title><link>https://kevin.deldycke.com/2020/revert-hp-printer-ban-on-third-party-ink-cartridges</link><description>&lt;p&gt;
 Hewlett &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Packard, the founders, had great lessons to teach us (managers in high-tech) about culture. To the extend of
 &lt;a class="reference external" href="https://github.com/kdeldycke/awesome-engineering-team-management/commit/de3e64647c911f78a37b3e54c7e46197acb061e1"&gt;
  quoting them
 &lt;/a&gt;
 in my
 &lt;a class="reference external" href="https://github.com/kdeldycke/awesome-engineering-team-management#readme"&gt;
  awesome list on engineering team management
 &lt;/a&gt;
 .&amp;nbsp;👨‍💼
&lt;/p&gt;



&lt;p&gt;
 &lt;span class="caps"&gt;HP&lt;/span&gt; Inc., the company, sucks. At least their
 &lt;a class="reference external" href="https://news.ycombinator.com/item?id=25045024"&gt;
  printer division’s business model
 &lt;/a&gt;
 . They recently pushed a
 &lt;strong&gt;
  firmware update to ban …&lt;/strong&gt;&lt;/p&gt;</description><author>Kevin Deldycke</author><pubDate>Mon, 09 Nov 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://kevin.deldycke.com/2020/revert-hp-printer-ban-on-third-party-ink-cartridges</guid></item><item><title>DSA-2020-209: Dell XPS 13 9370 Improper Exception Handling vulnerability</title><link>https://sayr.us/exploit/dell-exploit/</link><description>In August 2019, I’ve discovered a bug in how the XPS Bios handles a bootable device. This bug allows an attacker with write permission to a bootable device or physical access to the computer to prevent it from booting.</description><author>Sayr.us</author><pubDate>Sun, 08 Nov 2020 19:20:00 GMT</pubDate><guid isPermaLink="true">https://sayr.us/exploit/dell-exploit/</guid></item><item><title>Ferrari F12 Berlinetta</title><link>https://smcleod.net/2020/11/ferrari-f12-berlinetta/</link><description>&lt;p&gt;Last weekend I had a chance encounter with a &lt;a href="https://en.wikipedia.org/wiki/Ferrari_F12"&gt;Ferrari F12 Berlinetta&lt;/a&gt; and the owner kindly let me jump in and take a few photos.&lt;/p&gt;
&lt;h2 id="specs"&gt;Specs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;6.3L v12&lt;/li&gt;
&lt;li&gt;544 KW (740 Horsepower)&lt;/li&gt;
&lt;li&gt;690 Nm at 6000RPM&lt;/li&gt;
&lt;li&gt;1525 kg&lt;/li&gt;
&lt;li&gt;0-100 in 3.1s&lt;/li&gt;
&lt;li&gt;0-200 in 8.5s&lt;/li&gt;
&lt;li&gt;Maximum speed: &amp;lsquo;over 340 km/h&amp;rsquo;&lt;/li&gt;
&lt;li&gt;Was &lt;a href="https://web.archive.org/web/20121228015009/http://www.ferrari.com/english/gt_sport%20cars/gt/pages/120229-car-announcing-the-f12berlinetta-the-fastest-ferrari-ever-built.aspx"&gt;&amp;lsquo;The fastest road car Ferrari ever built&amp;rsquo;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="photos"&gt;Photos&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/ferrari_f12/F12B_1.jpeg?raw=true" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/ferrari_f12/F12B_2.jpeg?raw=true" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/ferrari_f12/F12B_8.jpeg?raw=true" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/ferrari_f12/F12B_4.jpeg?raw=true" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/ferrari_f12/F12B_5.jpeg?raw=true" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/ferrari_f12/F12B_6.jpeg?raw=true" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/ferrari_f12/F12B_7.jpeg?raw=true" /&gt;&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Sun, 08 Nov 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2020/11/ferrari-f12-berlinetta/</guid></item><item><title>The loosely held product roadmap</title><link>https://ilearnt.com/blog/looselyheldroadmap/</link><description>&lt;p&gt;In a recent article by Ryan Singer, &lt;a href="https://m.signalvnoise.com/options-not-roadmaps/" target="_blank"&gt;Options, Not Roadmaps&lt;/a&gt;, he explains why he doesn&amp;rsquo;t use roadmaps - he uses options instead.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sun, 08 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/looselyheldroadmap/</guid></item><item><title>Protecting TimeMachine backups from itself</title><link>https://www.gingerlime.com/2020/going-down-the-time-machine-rabbit-hole/</link><description>&lt;p&gt;Going down the time machine rabbit hole&amp;#8230; I love the fact that MacOS comes with TimeMachine built-in, and I also really appreciate its simplicity. It makes backups easy and accessible even for non-technical people. It gets messy though if you also want to have real offsite backups however. TimeMachine works great with a USB external&amp;#8230;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://www.gingerlime.com/2020/going-down-the-time-machine-rabbit-hole/"&gt;Protecting TimeMachine backups from itself&lt;/a&gt; appeared first on &lt;a href="https://www.gingerlime.com"&gt;Gingerlime&lt;/a&gt;.&lt;/p&gt;</description><author>Gingerlime</author><pubDate>Sun, 08 Nov 2020 11:54:20 GMT</pubDate><guid isPermaLink="true">https://www.gingerlime.com/2020/going-down-the-time-machine-rabbit-hole/</guid></item><item><title>Halloween Coding Adventure</title><link>http://acbart.github.io//2020/11/08/halloween-adventure/</link><description>This has been a challenging semester for my students. I am teaching CISC108, the introductory class for Computer Science majors. The class is tough enough, even for many students with prior programming experience. But, due to the Global Pandemic, this Fall 2020 semester is online. In addition to my existing curricular framework, I have a lot of new course policies meant to make the experience easier: no exams, flexible deadlines, and a huge team of excellent TAs giving 12:1 attention. But even with all this, my students are all still struggling to stay engaged.</description><author>Acbart ePortfolio</author><pubDate>Sun, 08 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://acbart.github.io//2020/11/08/halloween-adventure/</guid></item><item><title>Kubernetes tips</title><link>https://blog.cetinich.net/content/2020/2020-kubectl-cp-tar-remove-leading-slash-from-member-names/</link><description>The problem is solved by removing the leading slash after the podname
colon separator:</description><author>Brent's Blog</author><pubDate>Sun, 08 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-kubectl-cp-tar-remove-leading-slash-from-member-names/</guid></item><item><title>Enterprise tips for AWS Workspaces and AWS Managed AD</title><link>https://blog.cetinich.net/content/2020/2020-aws-workspaces-managedad/</link><description>::: note
::: title
Note
:::</description><author>Brent's Blog</author><pubDate>Sun, 08 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.cetinich.net/content/2020/2020-aws-workspaces-managedad/</guid></item><item><title>I made a website to guess tomorrow’s number of COVID-19 cases, and here’s what happened</title><link>http://blog.danieljanus.pl/coronalotto/</link><description>&lt;div&gt;&lt;h2 id="before"&gt;Before&lt;/h2&gt;&lt;p&gt;It seems so obvious in hindsight. Here in Poland, people have been guessing it ever since the pandemic breakout: in private conversations, in random threads on social media, in comments under governmental information outlets. It seemed a matter of time before someone came up with something like this. In fact, on one Sunday evening in October, I found myself flabbergasted that apparently no one yet has.&lt;/p&gt;&lt;p&gt;I doled out $4 for a domain, &lt;a href="http://koronalotek.pl"&gt;koronalotek.pl&lt;/a&gt; (can be translated as “coronalotto” or “coronalottery” – occurrences of the name on Twitter date back at least as far as April), and fired up a REPL. A few hours and 250 Clojure LOCs later, the site was up.&lt;/p&gt;&lt;p&gt;I wanted it to be as simple as possible. A form with two fields: “your name” and “how many cases tomorrow?” A top-ten list of today’s winners, sorted by the absolute difference between the guess and the actual number of cases, as &lt;a href="https://twitter.com/mz_gov_pl"&gt;reported daily on Twitter&lt;/a&gt; by the Polish Ministry of Health. The official number, prominently displayed. And that’s all.&lt;/p&gt;&lt;img src="/img/blog/koronalotek.png" /&gt;
&lt;p&gt;On 17 October, I posted the link on my Facebook and Twitter feeds, and waited. The stream of guesses started to trickle in.&lt;/p&gt;&lt;h2 id="after"&gt;After&lt;/h2&gt;&lt;p&gt;It never grew to be more than a stream, but it hasn’t gone completely unnoticed either.&lt;/p&gt;&lt;img src="/img/blog/koronalotek-g1.png" /&gt;
&lt;p&gt;The above plot shows daily number of accepted guesses (i.e., those that were used to generate the next day’s winners) over time – a metric of popularity. Each day’s number means guesses cast in the 24 hours up until 10:30 (Warsaw time) on that day, which is when the official numbers are published by the Ministry of Health.&lt;/p&gt;&lt;p&gt;I’ve been filtering out automated submissions, as well as excess manual submissions by the same IP that seemed to skew the results too much – I’ve arbitrarily set the “excess” threshold at 10. The missing datapoint for 19 October is not a zero, but a N/A: I’ve lost that datapoint due to a glitch. More on this below.&lt;/p&gt;&lt;p&gt;The interest peaked on October 23, with more than a thousand guesses for that day (I think it was reposted by someone with a significant outreach back then), and has been slowly declining since.&lt;/p&gt;&lt;p&gt;I have privately received some feedback. One person has pointed out that they found the site distasteful and that making fun of pandemic tragedies made them uncomfortable. (I empathise; for me it’s not so much making fun as it is a coping mechanism—a way to put distance between my thoughts and the difficult times we’re in and to keep fears at bay.) Some people, however, have thanked me for making them smile when they guessed more or less correctly.&lt;/p&gt;&lt;p&gt;Back to data. Being a data junkie, I looked at what I had been collecting. First things first: how accurate is the collective predictive power of the guessers?&lt;/p&gt;&lt;img src="/img/blog/koronalotek-g2.png" /&gt;
&lt;p&gt;Quite accurate, in fact! Data for this plot has only been slightly preprocessed, by filtering out “unreasonable” guesses that don’t fall within the range &lt;code&gt;[100; 50000]&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;People have over- and underguesstimated the number of new cases, but not by much. There were only a few occasions where the actual case count didn’t fall within one standard deviation of the mean of guesses (represented by the whiskers around blue bars on the plot). Granted, the daily standard deviation tends to be large (on the order of a few thousand), but still, I’m impressed. A paper on estimating the growth of pandemic based on coronalottery results coming soon to a journal near you! ;-)&lt;/p&gt;&lt;p&gt;Just for the heck of it, I’ve also been looking at individual votes. Specifically, names. Here’s a snapshot of unique guessers’ names sorted by decreasing length, on 23 October. (NSFW warning: expletives ahead!)&lt;/p&gt;&lt;img src="/img/blog/koronalotek-names.jpg" /&gt;
&lt;p&gt;Let me translate a few of these for those of you who don’t speak Polish:&lt;/p&gt;&lt;p&gt;1 is “Sasin has fucked over 70 million zlotys for elections that didn’t take place and was never held responsible.” This alludes to the &lt;a href="https://notesfrompoland.com/2020/05/27/70-million-zloty-bill-for-polands-abandoned-presidential-election/"&gt;ghost election in Poland&lt;/a&gt; from May. This news had gone memetic, going so far as Minister Sasin’s name being ironically used as a dimensionless unit of 70 million (think Avogadro’s number). You’ll discover the same theme in #2, #3, #5, and others.&lt;/p&gt;&lt;p&gt;6 is “CT {Constitutional Tribunal}, you focking botch, stop repressing my abortion”. Just a day before, the Polish constitutional court (whose current legality is &lt;a href="https://en.wikipedia.org/wiki/Constitutional_Tribunal_(Poland)#2015%E2%80%93present:_Polish_Constitutional_Court_crisis"&gt;disputed at best&lt;/a&gt;) has &lt;a href="https://notesfrompoland.com/2020/10/22/constitutional-court-ruling-ends-almost-all-legal-abortion-in-poland/"&gt;decreed a ban on almost all legal abortion&lt;/a&gt; in Poland, giving rise to &lt;a href="https://edition.cnn.com/2020/10/31/europe/poland-abortion-protests-scli-intl/index.html"&gt;the biggest street protests in decades&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Not all is political: 4 is “Why study for the exam if we’re not gonna survive until November anyway?”. I hope whoever wrote this is alive and well.&lt;/p&gt;&lt;p&gt;Corollary? Give people a text field, and they’ll use it to express themselves: politically or otherwise.&lt;/p&gt;&lt;p&gt;In fact, I have taken the liberty of chiming in. Shortly after, I altered the thank-you page (which used to just say “thanks for guessing”) to proudly display one of the emblems of the Women’s Strike, along with a link to a &lt;a href="https://zrzutka.pl/kasa-na-aborcyjny-dream-team-55g5gx"&gt;crowdfounding campaign&lt;/a&gt; for an NGO that supports women needing abortion.&lt;/p&gt;&lt;img src="/img/blog/koronalotek-thanks.jpg" /&gt;
&lt;h2 id="inside-out"&gt;Inside out&lt;/h2&gt;&lt;p&gt;I’m not much of a DevOps person, so I deployed it the quick and dirty way, not caring about scalability or performance. The maxim “make it as simple as possible” permeates the setup.&lt;/p&gt;&lt;p&gt;I just started a REPL within a &lt;code&gt;screen&lt;/code&gt; session on the tiny Scaleway C1 server that also hosts this blog and some of my other personal stuff. I launched a Jetty server within it, and set up a nginx proxy. And that’s pretty much it. I liberally tinker with the app’s state in “production,” evaluating all kinds of expressions when I feel like it.&lt;/p&gt;&lt;p&gt;Code changes are deployed by &lt;code&gt;git pull&lt;/code&gt;ing new developments and doing &lt;code&gt;(require 'koronalotek.core :reload)&lt;/code&gt; in the REPL.&lt;/p&gt;&lt;p&gt;Someone tried a SQL injection attack. This is doomed to fail because there’s no SQL involved. In fact, there’s no database at all. The entire state is kept in an in-memory atom and periodically synced out to an EDN file. In addition, state is reset and archived daily at the time of announcing winners. (I’ve added the archiving after forgetting it on one occasion – hence the lack of data for 19 October.)&lt;/p&gt;&lt;p&gt;I also don’t yet have a mechanism of automatically pulling in the Ministry of Health’s data. Every morning, I spend two minutes checking if there’s excess automatic votes, removing them if any, and then filling in the blanks:&lt;/p&gt;&lt;pre&gt;&lt;code class="hljs clojure"&gt;(&lt;span class="hljs-name"&gt;new-data!&lt;/span&gt; #inst &lt;span class="hljs-string"&gt;&amp;quot;2020-11-08T10:30+01:00&amp;quot;&lt;/span&gt; &lt;span class="hljs-number"&gt;24785&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For all the violations of good practices in this setup, it has worked out surprisingly well so far. I’ve resorted to removing automated votes a handful of times, and blacklisting IPs of voting bots in the nginx setup twice, but otherwise it’s been a low-maintenance toy. People seem to be willing to have fun, and I’m just not interfering.&lt;/p&gt;&lt;h2 id="takeaways"&gt;Takeaways&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;span&gt;You should call on your country’s authorities to exert pressure on the Polish government to respect women’s choices and stop actively repressing them.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Give people a text field, and they’ll use it to express themselves.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt;Release early, release often.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</description><author>code · words · emotions: Daniel Janus’s blog</author><pubDate>Sun, 08 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://blog.danieljanus.pl/coronalotto/</guid></item><item><title>De-mainstream YouTube? Bad idea</title><link>https://stop.zona-m.net/2020/11/de-mainstream-youtube-bad-idea/</link><description>&lt;p&gt;Seriously. Bad idea. In good faith, but bad.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 07 Nov 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/de-mainstream-youtube-bad-idea/</guid></item><item><title>Day of Automation</title><link>http://evantravers.com/articles/2020/11/07/day-of-automation/</link><description>&lt;p&gt;I thought I'd record the automations that I've written that I use in a normal workday… I started &lt;a href="https://talk.automators.fm/t/a-day-in-the-life-of-an-automator/8735"&gt;a thread on automators.fm&lt;/a&gt; for this, hopefully someone else will take this up and I'll learn some neat things from y'all!&lt;/p&gt;
&lt;p&gt;My alarm wakes me up… depends on the day there's different alarms (that's an automation, right?)&lt;/p&gt;
&lt;figure class="dual"&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/11/log_weight.PNG" /&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/11/weight_chart.PNG" /&gt;
&lt;/figure&gt;
&lt;p&gt;I step on my (formerly &amp;quot;smart&amp;quot; but now broken!) scale and use a shortcut to log weight to Apple Health. It then uses &lt;a href="https://apps.apple.com/us/app/charty-for-shortcuts/id1494386093"&gt;Charty&lt;/a&gt; to display a custom graph showing me how far I have to go til my goal weight.&lt;/p&gt;
&lt;p&gt;Today was a run day… so I grabbed my running gear and drove out to the route I run.&lt;/p&gt;
&lt;figure class="dual"&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/11/shortcuts.PNG" /&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/11/headspaces.PNG" /&gt;
&lt;/figure&gt;
&lt;p&gt;I have a master &amp;quot;headspace&amp;quot; shortcut for all the things on my phone… I choose &amp;quot;Workout&amp;quot; and &lt;a href="/articles/2020/11/06/one-button-workout-shortcut/"&gt;it runs the workout I have scheduled for that day&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After my run, it's time to have my quiet time: I run my Quiet Time headspace on my phone, it launches Dark Noise to a sound I only play during quiet time, and opens the app that controls the camera in my daughter's room so I can see when she's stirring and swoop her up before she wakes my wife.&lt;/p&gt;
&lt;p&gt;&lt;img alt="rituals" src="https://images.evantravers.com/articles/2020/11/rituals.png" /&gt;&lt;/p&gt;
&lt;p&gt;I have several recurring to-dos and lists to help me to plan my day, write the Monday blog post for work, etc.&lt;/p&gt;
&lt;p&gt;Once at my desk, I use &lt;a href="/articles/2020/06/08/hammerspoon-a-better-better-hyper-key/"&gt;Hyper&lt;/a&gt; to open a few apps and clean out a few emails.&lt;/p&gt;
&lt;p&gt;Then I used Headspace to enter &lt;a href="/articles/2020/06/19/hammerspoon-headspace/"&gt;meeting mode&lt;/a&gt; for standup.&lt;/p&gt;
&lt;p&gt;Each Monday, I presently write a mini-blog post at work in our wiki.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I use Alfred's text expansion feature to generate the post title (&lt;code&gt;,,puweekly&lt;/code&gt; becomes &lt;code&gt;UXWEEKLY (2020.43)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I build the post by pulling the links from a &amp;quot;workspace&amp;quot; in Drafts using the links I'd saved to drafts using the &lt;a href="/articles/2020/06/11/hammerspoon-automating-airpods-and-brave-browser/#bonus-snip-browser-highlight-to-drafts-as-a-simple-markdown-zettelkasten"&gt;Hammerspoon snip tool I built&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today happens to have lots of meetings…&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://evantravers.com/articles/2020/06/11/hammerspoon-automating-airpods-and-brave-browser/"&gt;A quick script&lt;/a&gt; I wrote in Hammerspoon tied to my Hyper key allows me to focus the tab with the google meet. I use it constantly to help me unmute.&lt;/li&gt;
&lt;li&gt;I have &lt;a href="/articles/2020/06/12/hammerspoon-handling-windows-and-layouts/"&gt;Autolayout&lt;/a&gt; rules that put the window with the meeting tab on the monitor that has the camera.&lt;/li&gt;
&lt;li&gt;Headspace is tracking the time spent in meetings to Toggl Track.&lt;/li&gt;
&lt;li&gt;Headspace is also blocking distracting applications like Reeder, so that I can stay focused.&lt;/li&gt;
&lt;li&gt;Hyper is letting me log little notes into Drafts.&lt;/li&gt;
&lt;li&gt;I do have some &lt;a href="/articles/2019/09/24/world-of-textfiles-meeting-notes/"&gt;Drafts automations&lt;/a&gt; for tying to a meeting note… so that it get's saved into my Zettelkasten in the right format, but I don't use that too often.&lt;/li&gt;
&lt;li&gt;Hyper is letting me push to-dos to Things inbox.&lt;/li&gt;
&lt;li&gt;I open a design file, and my &lt;a href="https://github.com/evantravers/qmk_firmware/blob/e712a196f3f821afc1754813b45c1abf4e471c3d/users/evantravers/wrappers.h#L67-L69"&gt;QMK custom layout&lt;/a&gt; tricks let me &lt;a href="/articles/2019/04/03/my-keyboard-setup/#qmk-layers"&gt;use my keyboard as a macropad&lt;/a&gt;, changing tabs, zooming, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Meetings are over! Time to go to lunch… I run &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/3d84ed6cbdca91bb5b11bd646ff75ed351db3298/spaces/shutdown.lua"&gt;shutdown headspace&lt;/a&gt; that stops tracking, clears the blocked apps, and closes all apps so that I have a fresh chance at being focused when I get back.&lt;/p&gt;
&lt;p&gt;More of the same as before lunch… I do take a break, running my &amp;quot;Rest/Play&amp;quot; Headspace so that Reeder and some other distractions are unblocked. I can now set a timer in my headspace by prefixing integers with &lt;code&gt;:&lt;/code&gt;, so I use that to for 15 minutes. &lt;code&gt;play :15&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My energy is &lt;strong&gt;really&lt;/strong&gt; low… so I run the &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/3d84ed6cbdca91bb5b11bd646ff75ed351db3298/spaces/shallow.lua"&gt;&amp;quot;Shallow&amp;quot; time headspace&lt;/a&gt; to unblock some distractions, but it also loads up all the work to-dos tagged &lt;code&gt;$Low&lt;/code&gt;. Sure enough, I find some good ankle-biter tasks to work on. I'm encouraged and energized by the momentum to get into some better, deeper work.&lt;/p&gt;
&lt;p&gt;At the end of the day, I run through my review checklist to review and plan the next day.&lt;/p&gt;
&lt;p&gt;I open my &lt;a href="/articles/2020/10/09/focus-budget-updated-implementation/"&gt;Headspace scheduling automation&lt;/a&gt; to put to-dos on the calendar for tomorrow.&lt;/p&gt;
&lt;p&gt;The day done, I run Shutdown again to stop timer and close apps for a fresh focused start tomorrow.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This was a fun exercise... it was both super interesting to see just how much of my tooling is totally custom to me, and way more satisfying to see that I've already written about and documented a lot of it. In the days since I recorded this, I've realized even more automations that I haven't covered... more iOS stuff, lots of dotfiles automations to keep my computers synced and current... a lot more to share!&lt;/p&gt;</description><author>trv.rs</author><pubDate>Sat, 07 Nov 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/11/07/day-of-automation/</guid></item><item><title>Temporal Transparency Update</title><link>https://www.swyx.io/temporal-transparency-update-9-auth-is-coming-2nok</link><description>Our 9th transparency update describing how we are shipping the upcoming Authentication feature</description><author>swyx's site RSS Feed</author><pubDate>Sat, 07 Nov 2020 05:04:37 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/temporal-transparency-update-9-auth-is-coming-2nok</guid></item><item><title>Demystifying malloc</title><link>https://riv.dev/demystifying-malloc/</link><description>A journey through the implementation of malloc.</description><author>River Gillis [riv.dev]</author><pubDate>Sat, 07 Nov 2020 04:29:20 GMT</pubDate><guid isPermaLink="true">https://riv.dev/demystifying-malloc/</guid></item><item><title>The Man Who Solved the Market: How Jim Simons Launched the Quant Revolution</title><link>https://olshansky.info/book/the_man_who_solved_the_market/</link><description>Olshansky's review of The Man Who Solved the Market: How Jim Simons Launched the Quant Revolution by Gregory Zuckerman</description><author>🦉 olshansky 🦁</author><pubDate>Sat, 07 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/the_man_who_solved_the_market/</guid></item><item><title>Stranded • Art</title><link>https://muffinman.io/art/stranded-blue-red/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;November 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;42x23cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Fabriano Bristol 250gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Pigma Micron, Sakura Gelly Rolls&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery art-gallery--wide"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1358" src="./0.jpg" width="2200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1650" src="./w_500-h_500--1.jpg" width="2200" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./plot_1080x1080.mp4"&gt;&lt;video class="gallery__video" src="./plot_1080x1080.mp4#t=0.001"&gt;&lt;/video&gt;&lt;svg class="gallery__play-icon" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20 c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./thumb.jpg"&gt;&lt;img alt="" class="gallery__image" height="685" src="./w_500-h_500--thumb.jpg" width="1200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Sat, 07 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/stranded-blue-red/</guid></item><item><title>Stranded • Art</title><link>https://muffinman.io/art/stranded-silver/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;November 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;42x30cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Fabriano Bristol 250gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Pigma Micron, Uni-ball Signo UM-153, Mechanical pencil&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1823" src="./0.jpg" width="2600" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1875" src="./w_500-h_500--1.jpg" width="2500" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./2.jpg"&gt;&lt;img alt="" class="gallery__image" height="1650" src="./w_500-h_500--2.jpg" width="2200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Sat, 07 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/stranded-silver/</guid></item><item><title>The Hidden Cost of Streaming Music: is it really IN music?</title><link>https://stop.zona-m.net/2020/11/the-hidden-cost-of-streaming-music-is-it-really-in-music/</link><description>&lt;p&gt;Me, I am not sure.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 06 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/the-hidden-cost-of-streaming-music-is-it-really-in-music/</guid></item><item><title>Naked Emperors in Tech</title><link>https://www.swyx.io/naked-emperors</link><description>Some things we often repeat as truth just aren't. We should call bullshit more often.</description><author>swyx's site RSS Feed</author><pubDate>Fri, 06 Nov 2020 15:01:55 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/naked-emperors</guid></item><item><title>New ways to generate ideas online</title><link>https://ilearnt.com/blog/betterideaprompts/</link><description>&lt;p&gt;There are a lot of sites that claim to be idea generators. Most of them turn out to be just a button you click that slings together a bunch of random words that are meant to then become a prompt to generate ideas.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Fri, 06 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/betterideaprompts/</guid></item><item><title>One-Button Workout Shortcut</title><link>http://evantravers.com/articles/2020/11/06/one-button-workout-shortcut/</link><description>&lt;p&gt;Any area of your life where there are regular patterns or discipline is ripe for automation... like exercise!&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#alarming-developments" id="alarming-developments"&gt;&lt;/a&gt;Alarming developments...&lt;/h2&gt;
&lt;p&gt;I’ve going to &lt;a href="http://f3birmingham.com/"&gt;f3birmingham.com&lt;/a&gt; workouts, and I’ve got a shortcut to remind me to log the workout to Strava. I don’t go &lt;em&gt;every&lt;/em&gt; time, so I just figured out a way to automate it: fire the automation only when the alarm I set to attend in the morning goes off.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/alarm_automation.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The automation in the “Do” block looks like:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/schedule_pushcut.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#one-button" id="one-button"&gt;&lt;/a&gt;One button&lt;/h2&gt;
&lt;p&gt;On all the other days, I used to have a &amp;quot;choose one&amp;quot; shortcut that let me pick what workout I wanted to do from a list. I was using the iOS14 &amp;quot;choose from Shortcut folder&amp;quot; action, so I have separate Shortcuts for each type of workout I do.&lt;/p&gt;
&lt;p&gt;Last night I realized that I could make life even easier on my sleepy self... I have a consistent schedule for my workouts, so if I know in advance what workout I'm going to do in the morning, I can program that in!&lt;/p&gt;
&lt;p&gt;So I wrote a new workout shortcut:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/one_button_workout.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I have a shortcut that builds that dictionary in &lt;a href="https://datajar.app/"&gt;Data Jar&lt;/a&gt; to “set my schedule”&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/set_schedule.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;That means if I want to tune a particular workout, I just change its shortcut in that Workouts folder… I’ll probably make one for stretching or yoga and just add it, and I can change my schedule!&lt;/p&gt;
&lt;p&gt;This means that when I wake up, I hit workout and the app opens, playlist starts, all that jazz.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#its-easy" id="its-easy"&gt;&lt;/a&gt;It's easy.&lt;/h2&gt;
&lt;p&gt;On mornings when I commit to F3, my phone will automatically remind me to log my workout.&lt;/p&gt;
&lt;p&gt;On all other mornings, I hit &lt;em&gt;one&lt;/em&gt; button and it does &lt;em&gt;exactly&lt;/em&gt; what I want. I'm basically using iOS Shortcuts to do a User Experience style experiment on my morning routine. 💪&lt;/p&gt;</description><author>trv.rs</author><pubDate>Fri, 06 Nov 2020 11:02:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/11/06/one-button-workout-shortcut/</guid></item><item><title>Lang. Identification in Code Mixed Text - Lit. Review 3</title><link>https://trigonaminima.github.io/2020/11/lang-id-3/</link><description>I am reviewing the literature available on language identification for multilingual documents, focusing on Indic languages. I’ll try to cover it in chronological order, but there might be a few misses here and there. After a decent coverage of the research, I expect to have enough understanding to discuss the challenges present in this task in a code-switched setting and its importance.</description><author>Playground</author><pubDate>Fri, 06 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://trigonaminima.github.io/2020/11/lang-id-3/</guid></item><item><title>When Joe Biden becomes the next president this site will beep</title><link>https://ferrucc.io/us-election/</link><description>&lt;button id="winner-beep"&gt;Try the beep&lt;/button&gt;


&lt;div id="winner"&gt;&lt;/div&gt;
&lt;div id="democrats"&gt;&lt;/div&gt;
&lt;div id="republicans"&gt;&lt;/div&gt;


&lt;p&gt;As requested by &lt;a href="https://twitter.com/hunterwalk/status/1324416369857720320"&gt;Hunter Walk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data sourced from the &lt;a href="https://static01.nyt.com/elections-assets/2020/data/api/2020-11-03/national-map-page/national/president.json"&gt;NYT&lt;/a&gt;&lt;/p&gt;

&lt;div&gt;&lt;p style="font-weight: bold; font-size: 36px;"&gt;&lt;/p&gt;</description><author>ferrucc.io</author><pubDate>Fri, 06 Nov 2020 00:20:05 GMT</pubDate><guid isPermaLink="true">https://ferrucc.io/us-election/</guid></item><item><title>Just because it isn't Closed, Doesn't Mean It Is Socialism</title><link>https://stop.zona-m.net/2020/11/just-because-it-isnt-closed-doesnt-mean-it-is-socialism/</link><description>&lt;p&gt;Is it so hard to see it, with software or anything else?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 05 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/just-because-it-isnt-closed-doesnt-mean-it-is-socialism/</guid></item><item><title>Rise of the Bandits</title><link>https://one.mikro2nd.net/pages/rise-of-the-bandits/</link><description>One of the most potent signs of a disintegrating state is the rise of independent militias and the ruling government&amp;rsquo;s inability/unwillingness to eliminate them. Now read today&amp;rsquo;s DM lead article: Radical document by &amp;lsquo;retired generals&amp;rsquo; spurs Gwede Mantashe into action.
Huh. Who woulda thunk. Retired generals want to stage a military coup. Supplize.
We already have a variety of part-time militias, some of mysterious provenance, some pretty obvious. There are the metropoles&amp;rsquo; various Police &amp;ldquo;forces&amp;rdquo;, the so-called Red Ants (who is behind them, anyway?</description><author>one mikro2nd</author><pubDate>Thu, 05 Nov 2020 15:19:38 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/rise-of-the-bandits/</guid></item><item><title>Mining Instagram location IDs</title><link>https://geo.rocks/post/mining-locations-ids/</link><description>&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre class="chroma" tabindex="0"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre class="chroma" tabindex="0"&gt;&lt;code class="language-json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"Jena"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"673710"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"Jena-Zentrum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"1006125655"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"Plan B Boulderhalle Jena"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"613227777"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"Kassablanca Jena"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"5752477"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"Kulturarena Jena"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"574057843"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"University of Jena"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"251848169"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"Paradiespark Para - Jena Paradies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"228419929"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;"Ernst-Abbe-Sportfeld"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"326665551"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;How to quickly mine location IDs from Instagram&amp;rsquo;s location explorer.&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Wed, 04 Nov 2020 21:37:39 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/mining-locations-ids/</guid></item><item><title>Let's read Libra Shrugged</title><link>https://stop.zona-m.net/2020/11/lets-read-libra-shrugged/</link><description>&lt;p&gt;This seems like the next book I (and you too) should read.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 04 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/lets-read-libra-shrugged/</guid></item><item><title>Questions to ask yourself before you buy</title><link>https://ilearnt.com/blog/pausingbeforebuying/</link><description>&lt;p&gt;Sometimes it is very easy to buy things just for the sake of it. We get that rush when either we bring the item home or it is delivered. It is easy to form an addiction to that feeling.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Wed, 04 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/pausingbeforebuying/</guid></item><item><title>Using CloudWatch for On-Premise Ubuntu Servers</title><link>https://blog.herlein.com/post/ubuntu-on-prem-cloudwatch/</link><description>&lt;p&gt;Can I replace a local Prometheus with AWS CloudWatch?  And include syslog monitoring as well?  Yes, I can.  But it was a PITA to set up.  Here&amp;rsquo;s how.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Wed, 04 Nov 2020 10:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/ubuntu-on-prem-cloudwatch/</guid></item><item><title>How To Improve Your Luck</title><link>https://jonpauluritis.com/articles/how-to-improve-your-luck/</link><description>&lt;p&gt;In September 1928 a bacteriologist name Alexander Fleming came back from a &amp;quot;holiday&amp;quot; (vacation) to find a set of petri dishes which had been &amp;quot;necessarily exposed to the air&amp;quot; had become contaminated by various micro-organisms. One of those petri dishes had grown a mold that appeared to be inhibiting the growth of a colony of Staphylococcus aureus. (You can read the original paper &lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2048009/pdf/brjexppathol00255-0037.pdf"&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;To quote Dr. Fleming: “When I woke up just after dawn on September 28, 1928, I certainly didn’t plan to revolutionize all medicine by discovering the world’s first antibiotic, or bacteria killer.&amp;quot;&lt;/p&gt;
&lt;p&gt;You've probably heard this story before. &lt;em&gt;However&lt;/em&gt;, there is a second part to the penicillin story that is told a lot less.&lt;/p&gt;
&lt;p&gt;What happened following the discovery on the part of Dr. Fleming was practically nothing. He published a paper on his findings, and that was pretty much it. Sure he did some more research in the area, but he ultimately concluded that his discovery wouldn't be useful for treating infection and wasn't worth pursuing further. Effectivity his part in the story stopped right after publication.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I want to pause to let that sink in for a second.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Not many people realize that it is entirely possible that the publication could have been the end of the story... or worse it might not have even made publication. If that were the case no one would would have benefited from perhaps the greatest life saving discovery in the 20th century.&lt;/p&gt;
&lt;p&gt;What did happen (a decade after publication) was that an Oxford Scientist named Dr. Howard Florey was reading back issues of The Journal of Experimental Pathology and ran into Fleming's article. It interested him enough to try and reproduce the work, eventually culminating in a streptococcus study of mice in 1940 with Dr. Ernst Chain &amp;amp; Dr. Norman Heatley. That study produced verifiable results that the production of antibiotics were indeed possible (though engineering efforts were required to make mass production viable).&lt;/p&gt;
&lt;h3&gt;How narratives shape our perception&lt;/h3&gt;
&lt;p&gt;Dr. Fleming's story is clearly in the genre of &amp;quot;dumb luck&amp;quot; (supposedly he even used the most famous phrase in all of science: &amp;quot;Huh. That's funny...&amp;quot;). Sure, he was a trained bacteriologist, and he had been working on infectious disease studies for a long time, but the mold literally fell out of the air perfectly into his petri dish.&lt;/p&gt;
&lt;p&gt;Dr. Florey's is on the other side of the &amp;quot;narrative&amp;quot; coin. He built a top lab at Oxford through hustle and grit. According to a PBS article on Florey he was &amp;quot;a master at extracting research grants from tight-fisted bureaucrats and an absolute wizard at administering a large laboratory filled with talented but quirky scientists.&amp;quot; His &amp;quot;discovery&amp;quot; of the Fleming study was the result of searching, learning, and accumulating resources to be able to leverage.&lt;/p&gt;
&lt;p&gt;These two versions of the &amp;quot;luck narrative&amp;quot; form a dichotomy for the way people like to look at luck. Either 1) serendipity is out of our control and &amp;quot;the gods will gift who they deem worthy&amp;quot; or 2) we can make our own luck through hard work, and determination.&lt;/p&gt;
&lt;h3&gt;What is luck anyway?&lt;/h3&gt;
&lt;p&gt;So the following is what is called the &amp;quot;Probability Mass Function&amp;quot; (one way of defining &amp;quot;luck&amp;quot;):&lt;/p&gt;
&lt;p&gt;&lt;img alt="function" src="https://jonpauluritis.com/img/function.png" /&gt;
$$
f(x,n,p) = \frac{!x}{n!(x-n)!}p^n(1-p)^x-n
$$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Defined
p = probablility of success
x = is the number of attempts
n = the number of winning attempts / successful attempts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To be &amp;quot;lucky&amp;quot; in the mathematical sense is where an agent achieves a successful (or unsuccessful) outcome that exceeds its probabilistic expectation given an environment. &lt;a href="http://www.havensmath.com/math-extras/binomial"&gt;(link)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;quot;Luck&amp;quot;, in the colloquial sense, is the result of chance. It's a surprise, an unexpected event. You have &amp;quot;bad&amp;quot; luck when bad (unexpected) things happen to you or &amp;quot;good&amp;quot; luck when good things happen to you. Luck in this sense is all around us, impacts us all, with the only difference being how much it effects us.&lt;/p&gt;
&lt;p&gt;[This colloquial luck has powerful psychological effects too... Higher socioeconomic status is correlated with lower belief in luck and vice-versa (&lt;a href="https://www.ncbi.nlm.nih.gov/pubmed/28689347"&gt;e.g. research&lt;/a&gt;). ]&lt;/p&gt;
&lt;h2&gt;How can one improve their luck?&lt;/h2&gt;
&lt;p&gt;So how can you improve your luck?&lt;/p&gt;
&lt;p&gt;...Well, you can't. Thanks for reading my article! (&lt;em&gt;just kidding&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;That is to say, you can't improve your luck in a &amp;quot;mathematical sense.&amp;quot; Luck in that sense is &lt;em&gt;actually&lt;/em&gt; random... otherwise it wouldn't be luck.&lt;/p&gt;
&lt;p&gt;&amp;quot;Luck&amp;quot; in the colloquial sense however is arguably more about narrative than probability. The magnitude of the outcomes in &amp;quot;colloquial luck&amp;quot; create the perceived &amp;quot;luckiness.&amp;quot; Receiving an &amp;quot;asymmetric payoff&amp;quot; makes you appear to be more lucky. So if you are interested in improving your luck in the colloquial sense you can accomplish this by exposing yourself to environments that have outsized payouts.&lt;/p&gt;
&lt;p&gt;...Ergo the process of &amp;quot;Improving your luck&amp;quot; is simple. Marry together what we know about mathematical luck and colloquial luck.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Start by finding environments that can provide outsized payouts.&lt;/strong&gt; I cannot stress enough how important it is to &lt;strong&gt;FIND THE RIGHT ENVIRONMENT&lt;/strong&gt;, as it will basically be the single largest influence on your probability of success. Searching for these sorts of environments takes work. You need to figure out as accurately as possible what &lt;strong&gt;your probability of success&lt;/strong&gt; will be, so that you can commit to working in that environment... which is no easy task.&lt;/p&gt;
&lt;p&gt;After you have chosen the right environment you want to &lt;strong&gt;search for ways to improve the probability of being successful&lt;/strong&gt; and execute them. More often than not the simplest way to improve the probability of a successful outcome is just to &lt;strong&gt;increase the number of attempts&lt;/strong&gt;. But similarly, there are often ways to decrease the &lt;strong&gt;total number of attempts needed to be successful-&lt;/strong&gt; basically influence your environment in a way that is favorable to you.&lt;/p&gt;
&lt;p&gt;And of course the last piece of the puzzle is to figure out ways to &lt;strong&gt;increase the narrative value&lt;/strong&gt; when you are successful. &lt;strong&gt;Being perceived as being lucky&lt;/strong&gt; is a powerful attribute and can help you improve your &amp;quot;luck&amp;quot; for future opportunities.&lt;/p&gt;
&lt;h3&gt;Hundreds of millions of lives saved...&lt;/h3&gt;
&lt;p&gt;When looking back at Dr. Howard Florey, his search through back issues of the Journal of Experimental Pathology was effectively his way of &lt;em&gt;choosing the environment&lt;/em&gt; he wanted to work in. He was beginning in a place that &lt;em&gt;already had some level of success&lt;/em&gt; and he knew he could increase the chances of success by starting with something that was already somewhat successful. The work of Alexander Fleming wasn't just a starting place- it reduced the total number of attempts it would take to be successful... all Florey had to do was put the work in and there was a good chance that luck would find him. The final piece of the puzzle was that Florey was choosing to &lt;em&gt;work on something that had an outsized payout&lt;/em&gt; or impact.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;...If you want it distilled, here's your recipe for improving your luck:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select what you work on carefully.&lt;/li&gt;
&lt;li&gt;Make sure that you can be successful and that the payouts are outsized.&lt;/li&gt;
&lt;li&gt;Try to find ways to reduce what it takes to be successful.&lt;/li&gt;
&lt;li&gt;Be focused and work hard.&lt;/li&gt;
&lt;/ol&gt;</description><author>JonPaulUritis.com</author><pubDate>Wed, 04 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://jonpauluritis.com/articles/how-to-improve-your-luck/</guid></item><item><title>Fight or flight? Breathe instead</title><link>https://www.alexanderlolis.com/fight-or-flight-breathe-instead</link><description>How to achieve the best attitude at work with integrity and self-awareness</description><author>Alexander's Blog Blog</author><pubDate>Wed, 04 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://www.alexanderlolis.com/fight-or-flight-breathe-instead</guid></item><item><title>A random list of ten Python standard library modules you must learn know</title><link>https://thatxliner.github.io/posts/a-random-list-of-ten-python-standard-library-modules-you-must-learn-know/</link><description>This is a *very short* ~~blog post~~ list of 10 Python standard library modules (that I think) you **must know** (as of python3.9).</description><author>ThatXliner's Blog</author><pubDate>Wed, 04 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://thatxliner.github.io/posts/a-random-list-of-ten-python-standard-library-modules-you-must-learn-know/</guid></item><item><title>Specular Realms founded.</title><link>https://specularrealms.com/2020/11/03/hello-world/</link><description>&lt;p&gt;With blood, sweat and tears, this company is finally off the ground. Now let the money start rolling in baby because I have the combined business acumen of the underpants gnomes combined with Sam the Eagle.&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://specularrealms.com/2020/11/03/hello-world/" rel="nofollow"&gt;Specular Realms founded.&lt;/a&gt; appeared first on &lt;a href="https://specularrealms.com" rel="nofollow"&gt;Specular Realms&lt;/a&gt;.&lt;/p&gt;</description><author>Specular Realms</author><pubDate>Wed, 04 Nov 2020 00:39:45 GMT</pubDate><guid isPermaLink="true">https://specularrealms.com/2020/11/03/hello-world/</guid></item><item><title>A quick portrait of digital gerrymandering</title><link>https://stop.zona-m.net/2020/11/a-quick-portrait-of-digital-gerrymandering/</link><description>&lt;p&gt;Why TODAY? Well, why NOT?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 03 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/a-quick-portrait-of-digital-gerrymandering/</guid></item><item><title>Nationality as a Service</title><link>https://nonhuman.party/post/nationality_as_a_service/</link><description>As a sentient being, thinking about your own existence and your place in the world; you must’ve asked yourself what runs the world.
Money! That&amp;rsquo;s what it used to be, but now, it’s undeniable that software has to be included in the answer too.</description><author>Non-Human Party</author><pubDate>Tue, 03 Nov 2020 17:25:05 GMT</pubDate><guid isPermaLink="true">https://nonhuman.party/post/nationality_as_a_service/</guid></item><item><title>Exposing the beauty in a problem</title><link>https://ilearnt.com/blog/beautyinaproblem/</link><description>&lt;p&gt;I was recently reminded of this great quote:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;When I&amp;rsquo;m working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong.&amp;rdquo; - R. Buckminster Fuller&lt;/em&gt;&lt;/p&gt;</description><author>I Learnt</author><pubDate>Tue, 03 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/beautyinaproblem/</guid></item><item><title>Guidelines for choosing React Libraries</title><link>https://maxrozen.com/guidelines-for-choosing-react-libraries</link><description>There are a *lot* of React libraries out there. So how do you pick which one to use in your app? This article provides guidelines for choosing.</description><author>Max Rozen</author><pubDate>Tue, 03 Nov 2020 11:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/guidelines-for-choosing-react-libraries</guid></item><item><title>Single file applications</title><link>https://ricardoanderegg.com/posts/write-apps-in-single-file/</link><description>&lt;p&gt;Storytelling is part of the human essence. Stories have let humans survive until today, they became the medium to move information between individuals.&lt;/p&gt;
&lt;p&gt;Programming can be considered another form of moving information. With different levels of abstraction, programming becomes a medium to transfer information between humans and computers.&lt;/p&gt;
&lt;p&gt;A programming paradigm mixing those two concepts is &lt;strong&gt;literate programming&lt;/strong&gt;. According to its definition:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Literate programming is a methodology that combines a programming language with a documentation language, thereby making programs more robust, more portable, more easily maintained, and arguably more fun to write than programs that are written only in a high-level language. The main idea is to treat a program as a piece of literature, addressed to human beings rather than to a computer.&lt;/em&gt; &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;</description><author>Posts on rand[om]</author><pubDate>Tue, 03 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://ricardoanderegg.com/posts/write-apps-in-single-file/</guid></item><item><title>Uvinji</title><link>https://benovermyer.com/blog/2020/11/uvinji/</link><description>&lt;p&gt;As soon as the pre-expansion patch launched, I fired up World of Warcraft with the intent to create my new main character and begin my adventure anew.&lt;/p&gt;
&lt;p&gt;Well, that first night there was a bit of a hiccup, as everyone else had the same idea. It took a lot longer to unlock the Vulpera allied race than I thought it would, as there was a quest chain for me to complete and it was very buggy. On top of that, I kept getting logged out. Eventually, I gave up for the night and logged back in the next day. Everything went smoothly after that.&lt;/p&gt;
&lt;p&gt;I created Uvinji, my Vulpera Shaman, and logged in. I expected to start at the new new-player island, but instead it started me off at level 10 and skipped all of that. I was a little disappointed, but oh well.&lt;/p&gt;
&lt;p&gt;After a little bit of running around Orgrimmar, I went on my way to Northrend to do the Wrath of the Lich King content. It was fun, at first, especially because I started in an area that I'd never actually done before. I made my way through all the quests in the Borean Tundra and ended up in Dragonblight.&lt;/p&gt;
&lt;p&gt;At this point, I'd leveled up to 31. With the level cap being 50 now, that was quite a bit of progress. However, at this point, I got bored of the grind. The content was familiar, and honestly, I hate the Scourge and all of the undead-filled areas. They're very monotone in color and boring to level through. So, I used my one-time Shadowlands level-up-to-50 token on Uvinji to power him all the way up, and went through the "you're a brand new 50" tutorial.&lt;/p&gt;
&lt;p&gt;I'm looking forward to the pre-expansion event that starts next Tuesday. Here's hoping it's more exciting than the last time the Scourge event happened...&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Tue, 03 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/11/uvinji/</guid></item><item><title>On the Storing of Dates</title><link>https://xavd.id/blog/post/on-the-storing-of-dates/</link><description>In all of my personal record keeping, I use a slightly unusual method of tracking the date. Learn how I do it and what problems it solves&lt;br /&gt;&lt;br /&gt;&lt;a href="https://xavd.id/blog/post/on-the-storing-of-dates/"&gt;Read the whole thing&lt;/a&gt;.</description><author>The David Brownman Blog</author><pubDate>Tue, 03 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xavd.id/blog/post/on-the-storing-of-dates/</guid></item><item><title>DKIM: Show Your Privates</title><link>https://rya.nc/dkim-privates.html</link><description>&lt;!-- included from `include/globals.rst` --&gt;
&lt;p&gt;If you’re like most people, there’s a good chance that it’s been years since
you’ve sent an email that wasn’t cryptographically signed. You don’t use PGP,
you say? Well, even if &lt;em&gt;you&lt;/em&gt; are not signing your email, your provider is
almost certainly doing it for you. Plausible deniability has been tossed aside
in the name of stopping spam, but it doesn’t have to be.&lt;/p&gt;</description><author>rya.nc</author><pubDate>Mon, 02 Nov 2020 22:02:00 GMT</pubDate><guid isPermaLink="true">https://rya.nc/dkim-privates.html</guid></item><item><title>On Being a Postdoctoral Researcher</title><link>https://bastian.rieck.me/blog/2020/postdoc/</link><description>&lt;p&gt;This is one of the posts I wish I had available when I was pondering
options&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; after my Ph.D. So if you, dear reader, are in the same
position, I wrote this just for &lt;em&gt;you&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Postdocs or postdoctoral researchers are arguably the middle children of
academia&amp;mdash;not getting the attention Ph.D. students &lt;em&gt;should&lt;/em&gt; be getting
while also not counting as faculty, making them ineligible for numerous
grants and other programmes. Many academics therefore see this time as
something that is to be endured until the &amp;rsquo;next step&amp;rsquo; finally beckons,
i.e. they become faculty members. I want to offer another perspective
here, viz. one of &lt;em&gt;cherishing&lt;/em&gt; this time.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s why: as a postdoc in a good lab,&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt; you are in a perfect
position. First, you enjoy a certain freedom to pursue your
own research directions, create your own own research agenda, and in
general just play around with whatever tickles your fancy. This is more
freedom than you probably had as a Ph.D. student, and it can be
extremely liberating (so much so that it might make you dizzy at
first). Second, you can also assume more responsibilities!
You can serve as a mentor to Ph.D. students and undergrads. You can
learn how to supervise them and how to manage projects. This is
a privilege, but it also carries a certain weight&amp;mdash;suddenly, you are
supposed to be the experienced person in the room.
The saving grace of this situation is that you are still in a protected
position! You are &lt;em&gt;not&lt;/em&gt; responsible for running a whole lab; you are
&lt;em&gt;not&lt;/em&gt; responsible for acquiring more funding for all your employees; you
are &lt;em&gt;not&lt;/em&gt; responsible for ensuring future collaborations.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This&lt;/em&gt; is why I think that a postdoctoral position can be an excellent
one, having just the right amount of responsibilities and competencies.
Or, to paraphrase the inimitable &lt;a href="https://en.wikipedia.org/wiki/Night_Watch_(Discworld)"&gt;Terry Pratchett&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is a very useful rank for the right person. The optimum balance of
power and responsibility.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Therefore, enjoy and cherish this time as long as it lasts. And if you
are still on the fence whether you should look for such a position:
consider the postdoc to be a ‘taste test’ for academia, directing
research, and mentorship. That way&amp;mdash;regardless of what &lt;em&gt;your&lt;/em&gt; personal next step should be&amp;mdash;you will be able to make an informed decision.&lt;/p&gt;
&lt;p&gt;What you should &lt;em&gt;not&lt;/em&gt; do is treat your postdoctoral time as a &amp;lsquo;Ph.D.
2.0.&amp;rsquo; By this I mean that you should not just continue your research as
a ‘lone wolf.’ Treat this time as a period of growth; try out different
directions and see where they will take you in the end. And most of all:
enjoy yourself.&lt;/p&gt;
&lt;p&gt;Good luck with this incredible adventure, until next time!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I had even less of a foggy idea of academia than I have now.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Meaning one that is run by a supervisor who cares about their
employees. I concede that there are some places you do not want to
work at.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Mon, 02 Nov 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/postdoc/</guid></item><item><title>Here is my hippocratic oath</title><link>https://stop.zona-m.net/2020/11/here-is-my-hippocratic-oath/</link><description>&lt;p&gt;You should take one too. It&amp;rsquo;s NOT about medicine.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 02 Nov 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/11/here-is-my-hippocratic-oath/</guid></item><item><title>Fractional talent as an alternative pool of resources</title><link>https://ilearnt.com/blog/fractionaltalent/</link><description>&lt;p&gt;At the startup I work for we used to have a full time HR person. These were in the days when the expectation was that we would have explosive growth and the company would &amp;ldquo;at least double in size every few months&amp;rdquo;. Unfortunately that is not the way it played out - we are still making good progress but have much more realistic growth plans.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Mon, 02 Nov 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/fractionaltalent/</guid></item><item><title>Books and Links: October</title><link>http://evantravers.com/articles/2020/11/02/books-and-links-october/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/11/october.jpg" /&gt;&lt;/p&gt;&lt;p&gt;This year is &lt;em&gt;flying&lt;/em&gt; by... I can't believe how quickly this month has come and gone. Grateful for a lot of beautiful days spent outside with those that I love.&lt;/p&gt;
&lt;p&gt;I did get some writing done this month... I have adjusted my system to where I have a big folder of wild, half-written idea sentences, and an area where I continue to edit and develop those ideas, and I think that's unblocked me a little bit when it comes to writing.&lt;/p&gt;
&lt;p&gt;I do owe many of you an update to my Simple Markdown Zettelkasten post... honestly I started a transition between two styles of ZK and kinda got stuck. Fortunately, both have stable IDs in the content of the file, so it's still usable... it just offends my data aesthetic. 🤷‍♂️&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;p&gt;I've been catching up on some web reading and some writing, so I haven't done as much reading this month.&lt;/p&gt;
&lt;p&gt;Currently reading: Knowing God, Whiskey Tango Foxtrot, Programmer's Introduction to Mathematics.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#interesting-thoughts" id="interesting-thoughts"&gt;&lt;/a&gt;Interesting Thoughts&lt;/h3&gt;
&lt;h4&gt;&lt;a class="anchor" href="#before-the-web-the-1980s-dream-of-a-free-and-borderless-virtual-world-pt1---youtube" id="before-the-web-the-1980s-dream-of-a-free-and-borderless-virtual-world-pt1---youtube"&gt;&lt;/a&gt;Before the Web: The 1980s Dream of a Free and Borderless Virtual World (Pt.1) - YouTube&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Part one of a four-part documentary series about the cypherpunk movement of the 1990s, which led to the creation of bitcoin, WikiLeaks, and more.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Originally linked on Marginal Revolution, I enjoyed this dive into the philosophical underpinnings of the early cypherpunk folk… makes me want to read Cryptonomicon again.&lt;/p&gt;
&lt;p&gt;(And reinstall PGP or something!)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=YWh6Yzr12iQ"&gt;Before the Web: The 1980s Dream of a Free and Borderless Virtual World (Pt.1) - YouTube&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#america-in-decay-the-sources-of-political-disfunction" id="america-in-decay-the-sources-of-political-disfunction"&gt;&lt;/a&gt;America in Decay: The Sources of Political Disfunction&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;What was arguably one of the most important changes in American public policy came about not because Congress as representative of the American people voted for it but because private individuals litigated through the court system to change the rules.
[…]
There is virtually no other liberal democracy that proceeds in this fashion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm not a giant Fukuyama fan, but his depiction of &amp;quot;adversarial legalism&amp;quot; is interesting.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.gwern.net/docs/history/2014-fukuyama.pdf"&gt;&lt;em&gt;America in Decay: The Sources of Political Disfunction&lt;/em&gt;&lt;/a&gt;, Francis Fukuyama, 2014&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#the-recursive-universe" id="the-recursive-universe"&gt;&lt;/a&gt;The Recursive Universe&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Since its inception in 1970, Conway’s Game of Life has developed a cult following of researchers, engineers, and hobbyists, pushing each other to construct increasingly elaborate “machines” from pixels on a screen. These investigations have resulted in a lengthy taxonomy of motifs, reactions, and mechanisms, as well as engineering principals and design abstractions. These days you can spend a long time on YouTube exploring the seemingly impossible things people are designing in the “simple” Life universe.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I've been in love with this simple puzzle toy ever since learning about it… it seems every five years when I check back in on it there are new crazy nano machines being built in it.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://blog.amandaghassaei.com/2020/05/01/the-recursive-universe/"&gt;The Recursive Universe&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#this-isnt-a-spaceship-its-a-lego-brain-teaser--the-brothers-brick--the-brothers-brick" id="this-isnt-a-spaceship-its-a-lego-brain-teaser--the-brothers-brick--the-brothers-brick"&gt;&lt;/a&gt;This isn't a spaceship, it's a LEGO brain-teaser | The Brothers Brick | The Brothers Brick&lt;/h4&gt;
&lt;p&gt;This is an amazing behind the scenes look at a master builder… my brain is still boggled at how complicated that wing is.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nick builds his creations as an iterative process–he’ll work on the same design for months, going through multiple versions and refining the design until everything fits just the way he wants. Usually, he’ll do this without regard for color, and only once he has the design down pat does he rebuild it in the final colors. Nick has published a few images of this ship giving us a look under the hood. First up, let’s look at the wing without the final colors applied, which makes it easier to distinguish the individual elements. One of the key elements you can spot here is that strange slope with 5 studs from the 90s (all those yellow parts in the image below). Incorporating its unique geometry makes for a fantastic starting point if you’re looking to give your LEGO brain a workout.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As my friend Andy B. put it best: &amp;quot;this is the greatest example of the idea that constraints breed creativity i've seen in a LONG time.&amp;quot;&lt;/p&gt;
&lt;p&gt;How does this...
&lt;img alt="how does this..." src="https://live.staticflickr.com/65535/50501686802_2d90b0bb52_h.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;become this? 🤯
&lt;img alt="become this?" src="https://live.staticflickr.com/65535/50512986576_3f692c30f5_h.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.brothers-brick.com/2020/10/23/this-isnt-a-spaceship-its-a-lego-brain-teaser/"&gt;This isn't a spaceship, it's a LEGO brain-teaser | The Brothers Brick | The Brothers Brick&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#right-now----a-giant-ant-short---youtube" id="right-now----a-giant-ant-short---youtube"&gt;&lt;/a&gt;Right Now -- A Giant Ant Short. - YouTube&lt;/h4&gt;

&lt;p&gt;I've thought about this &lt;em&gt;video&lt;/em&gt; a lot. The central question keeps bouncing around my head.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=rCD1KOOHwwE&amp;amp;t"&gt;Right Now -- A Giant Ant Short. - YouTube&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#productivity" id="productivity"&gt;&lt;/a&gt;Productivity&lt;/h3&gt;
&lt;h4&gt;&lt;a class="anchor" href="#weekly-planning" id="weekly-planning"&gt;&lt;/a&gt;Weekly Planning&lt;/h4&gt;
&lt;p&gt;Shoutout to &lt;a href="https://twitter.com/megalithic"&gt;Seth&lt;/a&gt; for pointing me at this awesome blog. I'm a fan.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Regardless of how this manifests in your system, it's vital to document and review your thoughts, ideas, and notes. Don't disregard them to gather dust in the corner of the closet (of your mind?).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Great&lt;/em&gt; write up of a mature planning process.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://drewbarontini.com/blog/weekly-planning/"&gt;Weekly Planning&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#ankit-pansari-on-twitter" id="ankit-pansari-on-twitter"&gt;&lt;/a&gt;Ankit Pansari on Twitter:&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;One of my favorite browsers hack is to use the .new domain in the address bar to jump straight into the action. &lt;a href="https://t.co/N5LpCIF7VX"&gt;https://t.co/N5LpCIF7VX&lt;/a&gt; -&amp;gt; creates a new Google Calendar Event No need to visit the app, find the right menu, and then start an activity. More on this👇 &lt;a href="https://t.co/aIEoYEMGql"&gt;https://t.co/aIEoYEMGql&lt;/a&gt;&amp;quot; / Twitter&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This thread was worth it &lt;em&gt;just&lt;/em&gt; for &amp;quot;meet.new.&amp;quot; 🙌&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/ankitpansari_/status/1322171784263655427"&gt;Ankit Pansari on Twitter&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#code" id="code"&gt;&lt;/a&gt;Code&lt;/h3&gt;
&lt;h4&gt;&lt;a class="anchor" href="#this-page-is-a-truly-naked-brutalist-html-quine" id="this-page-is-a-truly-naked-brutalist-html-quine"&gt;&lt;/a&gt;This page is a truly naked, brutalist html quine.&lt;/h4&gt;
&lt;p&gt;👏👏👏&lt;/p&gt;
&lt;p&gt;I have loved quines since school, this is a pretty cool example of one.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://secretgeek.github.io/html_wysiwyg/html.html"&gt;This page is a truly naked, brutalist html quine.&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#focus-management-and-inert--css-tricks" id="focus-management-and-inert--css-tricks"&gt;&lt;/a&gt;Focus management and inert | CSS-Tricks&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Focus management is the practice of coordinating what can and cannot receive focus events. It is one of the trickier things to do in front-end development, but it is important for making websites and web apps accessible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://css-tricks.com/focus-management-and-inert/"&gt;Focus management and inert | CSS-Tricks&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#functional-programming-for-the-rest-of-us" id="functional-programming-for-the-rest-of-us"&gt;&lt;/a&gt;Functional Programming For The Rest of Us&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;It's true that FP articles and papers are hard to understand, but they don't have to be. The reasons for the knowledge gap are purely historical. There is nothing inherently hard about FP concepts. Consider this article &amp;quot;an accessible guide to FP&amp;quot;, a bridge from our imperative minds into the world of FP. Grab a coffee and keep on reading. With any luck your coworkers will start making fun of you for your FP comments in no time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I know this has been floating around for a while, but I'm re-reading it and enjoying it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.defmacro.org/2006/06/19/fp.html"&gt;Functional Programming For The Rest of Us&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#coding-with-voice-dictation-using-talon-voice--josh-w-comeau" id="coding-with-voice-dictation-using-talon-voice--josh-w-comeau"&gt;&lt;/a&gt;Coding with voice dictation using Talon Voice · Josh W Comeau&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Earlier this year, I developed Cubital Tunnel Syndrome, a repetitive-strain injury, in both of my elbows. As a result, I pretty much can't use a mouse or keyboard; after a few minutes, I get a burning pain shooting down my arms. Even if I try to limit my computer usage to 60-second bursts, I wind up inadvertently making the situation worse.&lt;/p&gt;
&lt;p&gt;As you might imagine, this was a pretty big deal; as a software developer, my entire career is based on being able to use a keyboard!&lt;/p&gt;
&lt;p&gt;After many failed attempts at solving the problem with physiotherapy, ergonomics, and prescription medications, I've found a solution that allows me to be productive without risking further nerve damage. I now work almost exclusively using a microphone and an eye-tracker.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://joshwcomeau.com/accessibility/hands-free-coding/"&gt;Coding with voice dictation using Talon Voice · Josh W Comeau&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#the-state-of-css-survey" id="the-state-of-css-survey"&gt;&lt;/a&gt;The State of CSS Survey&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Flexbox, Grid, Multi-Column… To say nothing of whole new paradigms like CSS-in-JS.&lt;/p&gt;
&lt;p&gt;So after the success of our annual State Of JavaScript survey, we’ve decided to take on the world of styles and selectors to help identify the latests trends… and try to bridge the ever-growing “great front-end divide”!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I &lt;em&gt;loved&lt;/em&gt; that at the end of this survey it gave me a list of things I marked that I didn't know with a link to learn more… that's awesome.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://stateofcss.com/"&gt;The State of CSS Survey&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#the-erlangelist---to-spawn-or-not-to-spawn" id="the-erlangelist---to-spawn-or-not-to-spawn"&gt;&lt;/a&gt;The Erlangelist - To spawn, or not to spawn?&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;But before starting, since this is going to be a long article, I want to immediately share my main points:&lt;/p&gt;
&lt;p&gt;Use functions and modules to separate thought concerns.
Use processes to separate runtime concerns.
Do not use processes (not even agents) to separate thought concerns.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using a blackjack game, the author explains an interesting idea that feels more like pure mathematics than anything else. I think this will unblock me in Advent of Code!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.theerlangelist.com/article/spawn_or_not"&gt;The Erlangelist - To spawn, or not to spawn?&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Mon, 02 Nov 2020 12:03:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/11/02/books-and-links-october/</guid></item><item><title>The Kite Runner</title><link>https://arunmani.in/library/the-kite-runner/</link><description>Beautiful narration of a culture, traditions and difficulties.</description><author>Arun Mani</author><pubDate>Mon, 02 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://arunmani.in/library/the-kite-runner/</guid></item><item><title>A Practical Analysis of the Ledger Phishing Email</title><link>https://serhack.me/articles/practical-analysis-ledger-phishing-email/</link><description>Attempts at phishing and social engineering attacks have increased exponentially as of late, especially towards users who are active in the cryptocurrency space. Recently, there has been much discussion about a cunning attempt by phishers against Ledger and its users. -&lt;a href="https://serhack.me/articles/practical-analysis-ledger-phishing-email/"&gt;Continue to read the article on SerHack.me&lt;/a&gt;</description><author>SerHack - Security Researcher</author><pubDate>Mon, 02 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://serhack.me/articles/practical-analysis-ledger-phishing-email/</guid></item><item><title>Remove (deinit) a Git submodule</title><link>https://jmthornton.net/blog/p/git-submodule-deinit</link><description>A quick reminder of how to remove a Git submodule, because I always forget</description><author>Blog by Jade Michael Thornton</author><pubDate>Sun, 01 Nov 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://jmthornton.net/blog/p/git-submodule-deinit</guid></item><item><title>Fruit Plate</title><link>https://utf9k.net/blog/fruit-plate/</link><description>A minor tangent about... I don't remember, GTD and fruit?</description><author>utf9k</author><pubDate>Sun, 01 Nov 2020 13:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/fruit-plate/</guid></item><item><title>RSS from private multireddits</title><link>https://voussoir.net/writing/multireddit_rss</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;RSS from private multireddits&lt;/h1&gt;
&lt;p&gt;The RSS URL for a multireddit is &lt;code&gt;https://www.reddit.com/user/username/m/multiname/new.rss&lt;/code&gt;. But, putting this into your RSS client without making the multi public will yield a 404.&lt;/p&gt;
&lt;p&gt;On &lt;a href="https://old.reddit.com/prefs/feeds/"&gt;reddit.com/prefs/feeds&lt;/a&gt; you'll find some RSS links that use a static token in the URL to act as the authentication, so you don't have to provide login credentials in your client. It turns out, the token is the same for all of the feeds, and you can use it on the multireddit feed too.&lt;/p&gt;
&lt;p&gt;Just use &lt;code&gt;https://www.reddit.com/user/username/m/multiname/new.rss?feed=XXXXXXX&amp;amp;user=username&lt;/code&gt; and you're good to go.&lt;/p&gt;
&lt;p&gt;Since a single multireddit can aggregate up to 100 subreddits, you can save yourself and reddit up to 99 web requests per refresh by doing it this way.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/multireddit_rss/multireddit_rss.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/e4501b37c56c5baf27921fca9e1cd6dc2d4fbfe9"&gt;&lt;time datetime="2020-11-11T15:27:42-08:00"&gt;2020-11-11&lt;/time&gt; Explain why multireddits are better than separate rss feeds.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/d5356b0b0779ebb81b15783069c05d4c6646fa8c"&gt;&lt;time datetime="2020-11-01T00:01:56-07:00"&gt;2020-11-01&lt;/time&gt; Add multireddit_rss.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Sun, 01 Nov 2020 09:01:56 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/multireddit_rss</guid></item><item><title>Zettelkasten bookmarks</title><link>https://xenodium.com/zettelkasten-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://zettelkasten.de/introduction/"&gt;Introduction to the Zettelkasten Method&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.viktomas.com/posts/slip-box/#fnref:1"&gt;Zettelkasten note-taking in 10 minutes · Tomas Vik&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 01 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/zettelkasten-bookmarks</guid></item><item><title>My first time using rust</title><link>https://blog.imraniqbal.org/first-time-with-rust/</link><description>&lt;p&gt;Replacing one of my shell scripts with a compiled binary using rust.&lt;/p&gt;</description><author>Imran's Blog</author><pubDate>Sun, 01 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.imraniqbal.org/first-time-with-rust/</guid></item><item><title>Solutions: What are you solving for in life?</title><link>http://spirals.blog/articles/6-conditions-of-change/solutions/</link><description>&lt;p&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/"&gt;👈 Back to all conditions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The second condition required to unlock change is our &lt;strong&gt;Solutions&lt;/strong&gt; to our current life-problems.&lt;/p&gt;
&lt;p&gt;Solving for the &lt;em&gt;wrong type&lt;/em&gt; of problem can be very frustrating. We are often drawn to the “idea” of a life-style or challenge that is &lt;em&gt;not yet ours to solve&lt;/em&gt;. Instead of &lt;a href="https://spirals.blog/articles/getting-to-know-your-own-perspective-part-1/"&gt;focusing on where we’re at&lt;/a&gt;, we get caught up with shiny objects, distractions, and are lead down the garden path. We lose track of the real issues in our lives and instead choose to focus on other things that appear sexier or more gratifying.&lt;/p&gt;
&lt;h2&gt;Are you really ready?&lt;/h2&gt;
&lt;p&gt;How does one truly know whether what they’re focusing on is the “right” thing or not? A good indicator is if you’re currently in balance with your existing life-conditions.&lt;/p&gt;
&lt;p&gt;For example, take an employee who is performing remarkably at work. Their clients shower them in constant praise, are continuously promoted, and everyone in the office enjoys their company. They learn from everyone and spend years getting to know the ins and outs of their industry, business, and money. One day, this employee might think to themselves, “Gee, I think I know enough about this to run my own shop!”. After talking about it with their partner (check supporting structure), they decide to start a business on the side. They grow it until they can run it full time and enter a whole new perspective. (A Blue to Orange transition)&lt;/p&gt;
&lt;p&gt;In contrast, how would this play out if the employee was terrible with money, didn’t understand the market, and was too junior? It doesn’t matter how many business courses they take, life-coaches they hire, or books they read – they’re not ready. Ultimately, they will fail in their endeavors if they don’t go back and sort out the prerequisites. (&lt;em&gt;Orange cannot be supported by an unhealthy Blue&lt;/em&gt;).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If we haven’t solved the problems of where we’re at, we don’t have the &lt;strong&gt;supporting structure&lt;/strong&gt; to jump into the “next thing.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Are there enough resources to move on?&lt;/h2&gt;
&lt;p&gt;Let’s look at another example. While travelling, I meet many individuals claiming to be “changing/helping the world,” yet they can’t afford the bill when we go to dinner.&lt;/p&gt;
&lt;p&gt;How can you expect to help the world when you can’t help yourself? The world is littered with well-intentioned but broke hippies. &lt;em&gt;&lt;strong&gt;Ensure your own house is in order before fixing others.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When a new perspective or set of problems is presented to us, a great deal of energy is invested in understanding and dealing with them. As we mature in this perspective, we (hopefully) get better at solving them (how often do you think about tying your shoelaces these days?) and use fewer resources, time, and energy to solve them.&lt;/p&gt;
&lt;p&gt;For example, when you start a new job, there are, imaginably, many modern systems, people, processes, technical words, etc. to learn. Over time these things become familiar to you, and what requires a whole day to complete in your first month may take you a few minutes down the road. &lt;strong&gt;This means that there is an excess of energy.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It is in this excess that we find ourselves on stable ground. Only now may we safely stand up and look beyond where we are.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we were still doing a lousy job (not solving our current problems), there would be no energy to think about other things because we’re tied up in what we’re doing.&lt;/p&gt;
&lt;h2&gt;Revisit what you think you know&lt;/h2&gt;
&lt;p&gt;There seems to be this “great rush” to modern life. Grow faster, work faster, learn quicker, go further, more, MORE! All well and good in some situations, but often this leads us to skip over some things. The issue with this is we can sometimes be carrying around unhealthy solutions that we “found” long ago. Re-addressing the problems in Spiral, starting from the base, can strengthen the foundation in more complex places (“higher” colors).&lt;/p&gt;
&lt;p&gt;We may test ourselves on these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Purple Problem:&lt;/strong&gt; Do you feel that you truly belong in this world, are loved and accepted, and are comfortable being yourself?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Red Problem:&lt;/strong&gt; Are you comfortable standing up for yourself, expressing, and finding your own way (when needed) in life?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Blue Problem:&lt;/strong&gt; Are you able to let your own needs go for the group, stay disciplined, and &lt;em&gt;truly&lt;/em&gt; sacrifice now for the future?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Orange Problem:&lt;/strong&gt; Have you solved the money/success/power problem? Are you able to throw yourself at a problem and never give up, despite fierce competition, incredible odds, debilitating loneliness, and come out victorious? Do you have the external resources to move forward?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Green Problem:&lt;/strong&gt; Are you able to let go of material desire, status, and ego? Do you value all life forms? Are you able to encourage diversity, love, and harmony? Are you warm of spirit and words to yourself and others?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Slow down and take stock&lt;/h2&gt;
&lt;p&gt;We all need work. All of us would have elements in each of these perspectives that could do with a little love and kindness. This is where the power of community and environment helps us, as we are incapable of detecting our blindspots.&lt;/p&gt;
&lt;p&gt;So next time you feel friction, come back to these problems. Ask yourself if the desire for something else blinds you, or are you working at where you’re at? This is a hard question answer sometimes, but a necessary one.&lt;/p&gt;
&lt;p&gt;Going back to support our foundations transforms us into healthier, stronger, more flexible people/companies/countries/etc. It’s perfectly ok to admit we’re insecure and work to heal it. There is no shame in discovering that we don’t know ourselves or have trouble doing what we really want in life (many of us are like this). Consistency, discipline, and dedication are hard virtues to manifest. Don’t beat yourself up. Just keep going.&lt;/p&gt;
&lt;p&gt;Keep living, learning, and growing. Don’t let other people’s ideas of what you should be doing deter you. They’re on their own journey, and no two roads are the same.&lt;/p&gt;
&lt;p&gt;But most of all, if you want to change, be honest with yourself about where you are and what you’re doing. You’ll thank yourself in the long run.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/"&gt;👈 Back to all conditions&lt;/a&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 01 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/6-conditions-of-change/solutions/</guid></item><item><title>5 Z shell features that will encourage you to switch from Bash</title><link>https://jasoneckert.github.io/myblog/moving-from-bash-to-zsh/</link><description>&lt;p&gt;&lt;img alt="tux zsh shell" src="tuxzsh.jpg#right" title="tux zsh shell" /&gt;&lt;/p&gt;
&lt;p&gt;The command line interface on your system is provided by a shell. And while there are dozens of different shells available to choose from, nearly every UNIX and Linux system over the past two decades has used the feature-rich Bash shell as the default login shell.&lt;/p&gt;
&lt;p&gt;Although the Bash shell still remains the most common login shell used on UNIX and Linux systems, macOS and a few Linux distributions (e.g. Kali) have switched their default shell to the Z shell (&lt;code&gt;zsh&lt;/code&gt;), and this trend is likely to continue. The Z shell has been around for three decades, and is the second most popular shell next to Bash.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Sun, 01 Nov 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/moving-from-bash-to-zsh/</guid></item><item><title>What Does It Take To Resolve A Hostname</title><link>https://venam.net/blog/unix/2020/11/01/resolving-a-hostname.html</link><description>Resolving hostnames (DNS?) might not seem like it, but it's complicated. Let's take a moment to see if we can at least demystify what happens on the client side instead of seeing it as a big tangled mess of configurations, libraries, and tools.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Sun, 01 Nov 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/unix/2020/11/01/resolving-a-hostname.html</guid></item><item><title>Habitat 2020 - Coliving during COVID</title><link>https://jonlu.ca/posts/habitat</link><description>A look back at living in a coliving community during the first year of COVID-19.</description><author>JonLuca's Blog</author><pubDate>Sat, 31 Oct 2020 23:06:30 GMT</pubDate><guid isPermaLink="true">https://jonlu.ca/posts/habitat</guid></item><item><title>Robotic Blacksmiths? Yeah!</title><link>https://stop.zona-m.net/2020/10/robotic-blacksmiths-yeah/</link><description>&lt;p&gt;When hammer and anvil meet bits. Possibly, everywhere.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 31 Oct 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/robotic-blacksmiths-yeah/</guid></item><item><title>Masking in Deep Reinforcement Learning</title><link>https://boring-guy.sh/posts/masking-rl/</link><description>Introduction I worked on an environment where specific actions are not available at every timestep \(t\) when I started deep reinforcement learning. Let&amp;rsquo;s illustrate the concept of impossible or unavailable action concretely:
Suppose you want to develop an agent to play Mario Kart. Next, assume that the agent has an empty inventory (no banana 🍌 or anything). The agent can&amp;rsquo;t execute the action &amp;ldquo;use the object in the inventory&amp;rdquo;. Limiting the agent to a meaningful choice of actions will enable it to explore in a smarter way and output a better policy.</description><author>Boring Guy</author><pubDate>Sat, 31 Oct 2020 17:20:06 GMT</pubDate><guid isPermaLink="true">https://boring-guy.sh/posts/masking-rl/</guid></item><item><title>Committing time to stand out from the crowd</title><link>https://ilearnt.com/blog/standingout/</link><description>&lt;p&gt;There is a famous quote that asks how you eat an elephant and the answer is one bite at a time. It can be very daunting when attempting something new especially if it is potentially a large task. However it is impossible if you don&amp;rsquo;t take the first step.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sat, 31 Oct 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/standingout/</guid></item><item><title>Wallace Falls</title><link>https://sam.hooke.me/trip/2020/10/wallace-falls/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;p&gt;No trip report yet.&lt;/p&gt;



 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/wallace-falls/pylons.jpg"&gt;
 
 &lt;img alt="Pylons." src="https://sam.hooke.me/images/trip/2020/wallace-falls/pylons_hu10692177722623319716.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Pylons.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/wallace-falls/bridge.jpg"&gt;
 
 &lt;img alt="Bridge." src="https://sam.hooke.me/images/trip/2020/wallace-falls/bridge_hu16678080353928776636.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Bridge.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/wallace-falls/golden.jpg"&gt;
 
 &lt;img alt="Golden." src="https://sam.hooke.me/images/trip/2020/wallace-falls/golden_hu15849630120159808238.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Golden.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/wallace-falls/up.jpg"&gt;
 
 &lt;img alt="Up." src="https://sam.hooke.me/images/trip/2020/wallace-falls/up_hu13068883001207155331.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Up.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/wallace-falls/straight.jpg"&gt;
 
 &lt;img alt="Straight." src="https://sam.hooke.me/images/trip/2020/wallace-falls/straight_hu8061071069783171524.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Straight.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/wallace-falls/waterfall.jpg"&gt;
 
 &lt;img alt="Waterfall." src="https://sam.hooke.me/images/trip/2020/wallace-falls/waterfall_hu1786666031592307682.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Waterfall.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;




 




&lt;figure class="single"&gt;
 &lt;div class="single-inset"&gt;
 










 
 
 
 &lt;a href="https://sam.hooke.me/images/trip/2020/wallace-falls/distance.jpg"&gt;
 
 &lt;img alt="Distance." src="https://sam.hooke.me/images/trip/2020/wallace-falls/distance_hu10389930511384944427.jpg" /&gt;
 
 &lt;/a&gt;
 


 &lt;figcaption style="margin: auto;"&gt;
 
 Distance.
 
 &lt;/figcaption&gt;
 &lt;/div&gt;
&lt;/figure&gt;</description><author>Sam Hooke</author><pubDate>Sat, 31 Oct 2020 05:20:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/10/wallace-falls/</guid></item><item><title>Democracy is an achievement, not a recipe</title><link>https://nutcroft.mataroa.blog/blog/democracy-is-an-achievement-not-a-recipe/</link><description>&lt;p&gt;There is—thankfully—&lt;a href="https://www.ft.com/content/53fc1c4a-7ca3-4406-b9db-bebf1af9c9b8"&gt;consid&lt;/a&gt;&lt;a href="https://quillette.com/2020/08/01/twilight-of-democracy-a-review/"&gt;erable&lt;/a&gt; &lt;a href="https://www.thetimes.co.uk/article/chinas-young-watch-trump-and-breathe-a-sigh-of-relief-they-dont-have-democracy-r7bc3g2wf"&gt;collo&lt;/a&gt;&lt;a href="https://press.princeton.edu/books/hardcover/9780691169446/democracy-for-realists)"&gt;quy&lt;/a&gt; on the quality of our world’s democracies. People talk about whether democracy is actually a good idea while others claim it’s just the &lt;a href="https://www.sundayguardianlive.com/opinion/democracy-mercy-public-opinion"&gt;least worse&lt;/a&gt;. In this text I will attempt to convince you that democracy is not only a good idea, but actually a great one. All this with a transcendental shift in our perception of democracy:&lt;/p&gt;
&lt;p&gt;Democracy is not a system; it is an achievement.&lt;/p&gt;
&lt;h2 id="unsystemacy"&gt;Unsystemacy&lt;/h2&gt;
&lt;p&gt;We can’t have democracy if we do not &lt;em&gt;think&lt;/em&gt; in democratic principles. It’s like agile when developing software. You can’t switch to agile by adding a standup and a retro—it’s not a recipe&lt;sup id="fnref:agile"&gt;&lt;a class="footnote-ref" href="#fn:agile"&gt;1&lt;/a&gt;&lt;/sup&gt;. You can only be agile if you have the &lt;a href="https://agilemanifesto.org/"&gt;agile mindset&lt;/a&gt;. In the same way, you can’t be a democracy just by having your leaders elected&lt;sup id="fnref:elected"&gt;&lt;a class="footnote-ref" href="#fn:elected"&gt;2&lt;/a&gt;&lt;/sup&gt;. You can only have democracy if you include everyone in the actual decision making processes. When venturing democracy, there is a constant need for self-reflection on whether everyone is actually involved. This requires a continuous, active examination of societal processes, an everlasting reworking of the methods of decision making. That's core to the democratic mindset.&lt;/p&gt;
&lt;h2 id="recipe-status"&gt;Recipe status&lt;/h2&gt;
&lt;p&gt;It's evident in the global society that we view democracy as a set of rules that once applied, all societal desires will be aligned and non-zero sum benefits will unequivocally emerge. One piece of this evidence is the common remark: &lt;em&gt;democracy has failed us&lt;/em&gt;; or: &lt;em&gt;democracy doesn’t work&lt;/em&gt;. But that’s not the case. There is a limit to the range of influence of any &lt;a href="https://en.wikipedia.org/wiki/Structure_and_agency"&gt;social structure&lt;/a&gt;. Nothing will force all our interests to be aligned—only our &lt;a href="https://en.wikipedia.org/wiki/Agency_(sociology)"&gt;agency&lt;/a&gt;. If not this, then what's left is searching for loopholes in extraneously established laws with the purpose of making one’s life easier at the expense of the whole society's betterment.&lt;/p&gt;
&lt;p&gt;That's not to say this is an argument against social structures. On the contrary, it's one in favour. The disparity in this text's thesis is that these structures should be created directly from the people they are designed to apply to, not from a handful of elected officials.&lt;/p&gt;
&lt;h2 id="against-chain-of-agency"&gt;Against chain of agency&lt;/h2&gt;
&lt;p&gt;Democracy, by definition, is when people themselves have the power to make political and societal decisions. It was, historically, the &lt;a href="https://en.wikipedia.org/wiki/Dialectic#Modern_philosophy"&gt;dialectic antithesis&lt;/a&gt; to oligarchy: when power resides with the few. Indirect, or representative democracy, the current prevalent version of democracy, is not democracy, but rather an oligarchy.&lt;/p&gt;
&lt;p&gt;In representative democracy, politician (i.e. one who discusses and decides on societal issues) is a career. Whereas, in democracy, everyone is a politician and is expected to actively engage with any societal issues at hand. That is in addition to their job&lt;sup id="fnref:slavery"&gt;&lt;a class="footnote-ref" href="#fn:slavery"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Representative democracy politicians aim to convince people to vote for them via superficially dramatic campaigns, &lt;a href="https://en.wikipedia.org/wiki/Demonstration_(political)"&gt;rally&lt;/a&gt;-style theatrical performances, and by employing fanfare. There are no real societal plans being discussed&lt;sup id="fnref:ad hominem"&gt;&lt;a class="footnote-ref" href="#fn:ad hominem"&gt;4&lt;/a&gt;&lt;/sup&gt; between the politicians and the people, just statements and ambiguous responses—approval or rejection—from the public.&lt;/p&gt;
&lt;p&gt;However, discussion is a core feature of the democratic framework. How can a team make a collective decision if there is no discussion on the issue? In other words, how can a people make a democratic decision if there are no processes to discuss issues?&lt;/p&gt;
&lt;p&gt;Across the whole wide spectrum of actionable politics, in representative democracy a citizen makes, on average, two political decision every four years&lt;sup id="fnref:elections"&gt;&lt;a class="footnote-ref" href="#fn:elections"&gt;5&lt;/a&gt;&lt;/sup&gt;. As mentioned, achieving democracy means people exert the governing power. Nevertheless, half a political decision per year is not nearly enough for people to be considered actively involved in the decision making process.&lt;/p&gt;
&lt;h2 id="as-essence"&gt;As essence&lt;/h2&gt;
&lt;p&gt;Before we argue against the shortcomings of direct democracy, there is a case to be made for the essential quality of democracy as a societal framework&lt;sup id="fnref:system"&gt;&lt;a class="footnote-ref" href="#fn:system"&gt;6&lt;/a&gt;&lt;/sup&gt;. Why is democracy important?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Proposition 1&lt;/em&gt;: People value autonomy more than life itself. Indications are &lt;a href="https://en.wikipedia.org/wiki/Liberty_or_death"&gt;spread across history&lt;/a&gt;, ranging from the &lt;a href="https://en.wikipedia.org/wiki/Eleftheria_i_thanatos"&gt;motto of Greece&lt;/a&gt; to the ethos of &lt;a href="https://en.wikipedia.org/wiki/Live_Free_or_Die_(Breaking_Bad)"&gt;Breaking Bad&lt;/a&gt;.&lt;br /&gt;
&lt;em&gt;Proposition 2&lt;/em&gt;: Sharing our lives with other people (friends, family, strangers) is part of the essence of our humanity.&lt;br /&gt;
&lt;em&gt;Proposition 3&lt;/em&gt;: It follows from 1 and 2 that being autonomous together with other people is vital.  &lt;/p&gt;
&lt;p&gt;Democracy is the actualisation of this: making collective decisions on how we live. Undoubtedly, fundamental. I would go as far as to say that there is no point in life without this sport of endeavouring democracy. If not for it, our life would be either an autonomous loneliness or an enslaved collectivity.&lt;/p&gt;
&lt;h2 id="in-defence-of"&gt;In defence of&lt;/h2&gt;
&lt;p&gt;Let's assume Fred, our imaginary assistant for the demonstration of the argumentative against the shortcomings of direct democracy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fred: “Well, that’s all nice and stuff, but we can’t have direct democracy because people are not well educated to have opinions on significant matters and/or they will make horrible decisions. See Brexit, for example.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Fred, allow me to disagree. For one, there are solid arguments to be made in favour of Brexit, regardless of Brexiteers basing their vote on the silly ones.&lt;/p&gt;
&lt;p&gt;It is true that people will be unknowledgeable on a variety of issues that they will be asked to give opinions on. However, during an honest discourse where all voices are given equal ground and are heard in the same level, it is an argument of human rationality and aligned interests that people are going to behave responsibly&lt;sup id="fnref:expectations"&gt;&lt;a class="footnote-ref" href="#fn:expectations"&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Another argument to be made here is that there are, and have been through recent history, multiple political leaders the intelligence of whom is highly questionable. Yet, we survived. Therefore, I have little fear that the consequences of a potential lack of intelligence will be destructive.&lt;/p&gt;
&lt;p&gt;Finally, freedom is more important than making the best decision—it’s more important than life itself, for many! Let people decide for themselves, even if it kills them. How much more different would it be from the present, when elected leaders decide for people, and it still kills them&lt;sup id="fnref:police"&gt;&lt;a class="footnote-ref" href="#fn:police"&gt;8&lt;/a&gt;&lt;/sup&gt;?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fred: “So you’re saying instead of Trump ordering the police to kill people, people will accidentally kill themselves and that’s ok. Great stuff! You know what, direct democracy is never going to work because people don’t have time to talk politics all day. Not to mention that many don't even care about politics. They have jobs and are busy with their actual life. Direct democracy was only good when it was invented, when they had slaves to work the fields, in ancient Athens.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Come on, Fred, you know the first part is a straw man.&lt;/p&gt;
&lt;p&gt;Here's the thing about people's time. All these decisions already &lt;em&gt;are&lt;/em&gt; part of their busy life. Politics and societal issues unavoidably affect everyone and the only other path is lack of action—being a puppet while others decide for your life and the civic institutions that eventually you, too, will encounter. Is that not a core part of everyone's life? It seems fundamental to find the time for it.&lt;/p&gt;
&lt;p&gt;There are many things to say about all this people's busyness and the concept of bullshit jobs is one of them. The work ethic that is currently permeating the global society is one that associates work with self-worth&lt;sup id="fnref:protestant"&gt;&lt;a class="footnote-ref" href="#fn:protestant"&gt;9&lt;/a&gt;&lt;/sup&gt;. David Graeber describes &lt;a href="https://en.wikipedia.org/wiki/Bullshit_Jobs"&gt;Bullshit Jobs&lt;/a&gt; as meaningless jobs that exist only because it's shameful to not work. Hence, we had to invent jobs such as &lt;em&gt;door attendants&lt;/em&gt; and &lt;em&gt;airline desk staff who calm passengers whose bags do not arrive&lt;/em&gt; to keep up with the demand for &lt;em&gt;virtuous suffering&lt;/em&gt;. &lt;/p&gt;
&lt;p&gt;In regards to the argument of people not being interested in politics, I see that more of an aftereffect of the complete disaster that modern politics has been&lt;sup id="fnref:modern politics"&gt;&lt;a class="footnote-ref" href="#fn:modern politics"&gt;10&lt;/a&gt;&lt;/sup&gt;, rather than an inherent characteristic of people not concerned about how they live. Ultimately, many may not care, but at least those who do will have the capacity to act.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fred: “Well, you didn’t convince me at all. We have this system for so long now; it's not perfect—nothing is—but it's so much better than all the previous ones&lt;sup id="fnref:churchill"&gt;&lt;a class="footnote-ref" href="#fn:churchill"&gt;11&lt;/a&gt;&lt;/sup&gt;. We're not going to make such an inconsiderate change and abandon it for something evidently not working.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Today, I learned that up until 2006&lt;sup id="fnref:security"&gt;&lt;a class="footnote-ref" href="#fn:security"&gt;12&lt;/a&gt;&lt;/sup&gt; one could take &lt;a href="https://en.wikipedia.org/wiki/2006_transatlantic_aircraft_plot"&gt;liquids on a plane&lt;/a&gt;. It sounds like a magical time, but it was only fourteen years ago. Something so established and familiar didn’t exist until very recently. The point I want to make is that changes seem scary but only from afar. In the end, this world is all about risk taking and &lt;a href="https://en.wikipedia.org/wiki/Heraclitus#Panta_rhei"&gt;change&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another point about radical change is technology. It has evolved enormously during the last twenty years, not to mention the last hundred. Who could ever imagine in 1920, that humanity would be so intimately enmeshed in a global cybernetic network?&lt;/p&gt;
&lt;p&gt;Yet, on the other side, how much have our societal and political systems change since then? It’s only fitting that a change of an equivalent radical degree is waiting to happen on how our societies work.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:agile"&gt;
&lt;p&gt;There is some disagreement over this but &lt;a href="https://itrevolution.com/agile-conversations/"&gt;here's a book&lt;/a&gt; that expands on agile requiring the appropriate mindset.&amp;#160;&lt;a class="footnote-backref" href="#fnref:agile" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:elected"&gt;
&lt;p&gt;Elected is many times better than not elected, yet still not good enough.&amp;#160;&lt;a class="footnote-backref" href="#fnref:elected" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:slavery"&gt;
&lt;p&gt;In Ancient Athens, they didn't need to do that since slaves would do everyone's job, for free. In the modern world, until robots can do all jobs, I think it’s important that we do both products/services and politics.&amp;#160;&lt;a class="footnote-backref" href="#fnref:slavery" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:ad hominem"&gt;
&lt;p&gt;The worst version of this absence of real discussion is &lt;a href="https://en.wikipedia.org/wiki/Ad_hominem"&gt;attacking the opponent’s credibility&lt;/a&gt;, the one of the lowest quality of the techniques of persuasion.&amp;#160;&lt;a class="footnote-backref" href="#fnref:ad hominem" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:elections"&gt;
&lt;p&gt;Two elections, one for the local authority and one for the country-level authority. This is an average of western countries, but I assume it can also vary, as I'm not aware of all European political systems. Notable exception is Switzerland, in which multiple referendums take place and &lt;a href="https://en.wikipedia.org/wiki/Landsgemeinde"&gt;other direct democracy processes&lt;/a&gt; occur frequently.&amp;#160;&lt;a class="footnote-backref" href="#fnref:elections" title="Jump back to footnote 5 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:system"&gt;
&lt;p&gt;I'm consciously avoiding the term &lt;em&gt;political system&lt;/em&gt; here.&amp;#160;&lt;a class="footnote-backref" href="#fnref:system" title="Jump back to footnote 6 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:expectations"&gt;
&lt;p&gt;There are also &lt;a href="https://www.psychologytoday.com/us/blog/living-single/200911/can-your-expectations-shape-my-behavior"&gt;indications&lt;/a&gt; that people will behave as you expect them to. I expect them to make serious, responsible decisions that will affect the whole.&amp;#160;&lt;a class="footnote-backref" href="#fnref:expectations" title="Jump back to footnote 7 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:police"&gt;
&lt;p&gt;Trump &lt;a href="https://www.theatlantic.com/ideas/archive/2020/06/chauvin-did-what-trump-asked-him-do/612574/"&gt;prompted&lt;/a&gt; the police to not be &lt;a href="https://abcnews.go.com/Politics/trump-police-nice-suspects/story?id=48914504"&gt;too nice&lt;/a&gt; to the people protesting for &lt;a href="https://en.wikipedia.org/wiki/Killing_of_George_Floyd"&gt;rudimentary justice&lt;/a&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:police" title="Jump back to footnote 8 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:protestant"&gt;
&lt;p&gt;Max Weber coined the term in his book &lt;em&gt;&lt;a href="https://en.wikipedia.org/wiki/The_Protestant_Ethic_and_the_Spirit_of_Capitalism"&gt;The Protestant Ethic and the Spirit of Capitalism&lt;/a&gt;&lt;/em&gt;. &lt;a href="https://en.wikipedia.org/wiki/Protestant_work_ethic"&gt;Protestant work ethic&lt;/a&gt; is the principle that hard work and discipline are a righteous person's driving ideals.&amp;#160;&lt;a class="footnote-backref" href="#fnref:protestant" title="Jump back to footnote 9 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:modern politics"&gt;
&lt;p&gt;It is neither accidental nor satisfactory that young smart people allow themselves to become absorbed by the realms of academia or industry rather than politics.&amp;#160;&lt;a class="footnote-backref" href="#fnref:modern politics" title="Jump back to footnote 10 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:churchill"&gt;
&lt;p&gt;This is another iteration of the &lt;a href="https://www.goodreads.com/quotes/267224-democracy-is-the-worst-form-of-government-except-for-all"&gt;famous Churchill quote&lt;/a&gt; that helps us accept the inadequacy of the status quo: "Democracy is the worst form of government, except for all the others."&amp;#160;&lt;a class="footnote-backref" href="#fnref:churchill" title="Jump back to footnote 11 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:security"&gt;
&lt;p&gt;I learned that from &lt;a href="https://youtu.be/yyzd_a6vLWY?t=111"&gt;this very interesting video on security&lt;/a&gt; by Oliver Thorn.&amp;#160;&lt;a class="footnote-backref" href="#fnref:security" title="Jump back to footnote 12 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>nutcroft</author><pubDate>Sat, 31 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/democracy-is-an-achievement-not-a-recipe/</guid></item><item><title>2020–10–31: New p-boot released, new pre-built/updated kernels</title><link>https://xnux.eu/log/#024</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 31 Oct 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#024</guid></item><item><title>Gotta cut wood</title><link>http://www.nuke24.net/plog/28.html</link><author>TOGoS's Project Log</author><pubDate>Fri, 30 Oct 2020 20:13:37 GMT</pubDate><guid isPermaLink="true">http://www.nuke24.net/plog/28.html</guid></item><item><title>Project Cybersin</title><link>https://stop.zona-m.net/2020/10/project-cybersin/</link><description>&lt;p&gt;We rarely look to older technologies for inspiration. That&amp;rsquo;s bad.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 30 Oct 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/project-cybersin/</guid></item><item><title>CCEC 2020 3-Minute Pitch [Video]</title><link>https://www.youtube.com/watch?v=j48QJP9dQUc</link><description>Summary of my Masters research at the 2020 Canadian Chemical Engineering Conference. First-place in the 3-Minute Pitch competition.</description><author>David Schlachter</author><pubDate>Fri, 30 Oct 2020 18:15:00 GMT</pubDate><guid isPermaLink="true">https://www.youtube.com/watch?v=j48QJP9dQUc</guid></item><item><title>Why the Westminster Reference Bible is the best all-around bible you can buy</title><link>https://honza.pokorny.ca/2020/10/why-the-westminster-reference-bible-is-the-best-all-around-bible-you-can-buy/</link><description>&lt;figure&gt;&lt;img src="https://honza.pokorny.ca/images/wrb.jpg" /&gt;
&lt;/figure&gt;

&lt;p&gt;I will argue that the &lt;a href="https://www.heritagebooks.org/products/westminster-reference-bible-kjv-calfskin.html"&gt;Westminster Reference Bible&lt;/a&gt; in black calfskin published by
the Trinitarian Bible Society (TBS) is the best all-around printed bible that
you can buy today in the English language.&lt;/p&gt;
&lt;p&gt;I will not be considering digital bibles, or bibles in languages other than
English.  And by &lt;em&gt;all-around&lt;/em&gt;, I will mean &lt;em&gt;all-purpose&lt;/em&gt;.  The bible should work
well in as many contexts as possible.  There are specialty bibles that will work
better in some contexts; however, I will focus on having a single bible that can
do everything: preaching, personal and group study, casual reading, hospital
visits, public and family worship.&lt;/p&gt;
&lt;p&gt;There are two parts to this evaluation: the translation, and the printed volume
itself.&lt;/p&gt;
&lt;h2 id="the-translation"&gt;The translation&lt;/h2&gt;
&lt;p&gt;The Westminster Reference Bible uses the Authorized Version, more commonly
known as the King James Version (KJV).  The KJV was first published in 1611,
and has since enjoyed great popularity.  It has altered the course of the
English language as many of its phrases have entered into common speech.&lt;/p&gt;
&lt;h3 id="the-received-text"&gt;The Received Text&lt;/h3&gt;
&lt;p&gt;The KJV was translated from the Reformation-era text of Scripture.  Unlike most
modern English translations of the Bible, the KJV uses the Received Text, as
opposed to the Critical Text as its underlying source.  The Received Text is the
providentially preserved Word of God, without spot or blemish.  This means that
the KJV doesn&amp;rsquo;t need to be updated when textual-critical scholarship decides
that new manuscript evidence warrants a change of the wording of the Holy
Scriptures.  The KJV presents in English what the apostles wrote in Greek.  The
KJV unashamedly and proudly includes all of the text of Scripture, and doesn&amp;rsquo;t
neglect any of the contested passages, like Mark 16:9-20 or John 7:53-8:11.  The
KJV as a translation is driven by the ideals of the Reformation.&lt;/p&gt;
&lt;h3 id="transliteration"&gt;Transliteration&lt;/h3&gt;
&lt;p&gt;The KJV employs an interesting strategy when transliterating proper names to
English.  The Bible was original written in Hebrew (and Aramaic), and Greek, and
those languages don&amp;rsquo;t use the Latin alphabet.  Each proper name must be
transliterated to an English form.  This is common to all translations.  Παῦλος
becomes Paul.  But the way that the KJV goes about it is different.  Many proper
names are rendered differently in the Old Testament, and the New Testament.  For
example, the prophet Isaiah is called &lt;em&gt;Isaiah&lt;/em&gt; in the Old Testament, but
&lt;em&gt;Esaias&lt;/em&gt; in the New Testament (e.g. Matthew 3:3).  This becomes important in
passages like Hebrews 4:8 where Jesus is said to give rest.  The KJV uses the
word &lt;em&gt;Jesus&lt;/em&gt; instead of &lt;em&gt;Joshua&lt;/em&gt; as many modern translations do.  This shows the
reader that the two names are the same, and that the context must determine
which person is being spoken of.  The KJV gives you the option; modern
translations don&amp;rsquo;t.&lt;/p&gt;
&lt;h3 id="singular-and-plural-personal-pronouns"&gt;Singular and plural personal pronouns&lt;/h3&gt;
&lt;p&gt;The KJV uses archaic personal pronouns like &lt;em&gt;thou&lt;/em&gt;, &lt;em&gt;thee&lt;/em&gt;, &lt;em&gt;thine&lt;/em&gt;, and &lt;em&gt;ye&lt;/em&gt;.
This is done in order to signal to the reader whether a singular or a plural
form of the verb is being employed in the original languages.  Modern English
doesn&amp;rsquo;t have this ability aside from regional colloquialisms like &lt;em&gt;y&amp;rsquo;all&lt;/em&gt;.  This
enables the reader to obtain a greater understanding of the biblical text.&lt;/p&gt;
&lt;h3 id="void-of-modern-gendered-language"&gt;Void of modern gendered language&lt;/h3&gt;
&lt;p&gt;The KJV doesn&amp;rsquo;t suffer from modern inclusive language issues.  It doesn&amp;rsquo;t try to
be politically correct.  It doesn&amp;rsquo;t say &lt;em&gt;brothers and sisters&lt;/em&gt; where the Greek
original says &lt;em&gt;brothers&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="it-s-final"&gt;It&amp;rsquo;s final&lt;/h3&gt;
&lt;p&gt;The KJV hasn&amp;rsquo;t changed in centuries, and isn&amp;rsquo;t going to.  This is in stark
contrast with modern translations which need to be updated every few years.&lt;/p&gt;
&lt;p&gt;Generations of Christians have read the KJV, and memorized passages from it, and
we can follow in their footsteps.  We don&amp;rsquo;t need to worry that our bibles will
become obsolete with the next update.  We can buy a bible, and it can last us a
lifetime.&lt;/p&gt;
&lt;h3 id="the-standard-version"&gt;The standard version&lt;/h3&gt;
&lt;p&gt;The KJV is the only translation which can be considered a standard version.
Thousands of churches recite the Lord&amp;rsquo;s prayer using the words of the KJV
despite using a modern translation in preaching.&lt;/p&gt;
&lt;h3 id="public-domain"&gt;Public domain&lt;/h3&gt;
&lt;p&gt;The text of the KJV is in the public domain in most of the world, and is freely
and readily available.  The Word of God is precious.&lt;/p&gt;
&lt;h2 id="the-book-itself"&gt;The book itself&lt;/h2&gt;
&lt;h3 id="binding-and-leather"&gt;Binding and leather&lt;/h3&gt;
&lt;p&gt;The book itself is smyth-sewn, and bound in black calfskin.  The calfskin
presents a happy trade-off between quality, price, and comfort.  It&amp;rsquo;s very
durable, feels great to the touch, and isn&amp;rsquo;t very expensive compared to
goatskin.  It&amp;rsquo;s only available in black, the only colour that matters.&lt;/p&gt;
&lt;h3 id="subsidized-cost"&gt;Subsidized cost&lt;/h3&gt;
&lt;p&gt;The cost of producing the Westminster Reference Bible is being subsidized from a
large pool of money a generous donor has made available.  Thus, one is able to
acquire a premium bible without a premium price tag.  This shows the integrity
of the publisher, and assures us that their primary interest isn&amp;rsquo;t getting rich.&lt;/p&gt;
&lt;h3 id="references"&gt;References&lt;/h3&gt;
&lt;p&gt;The Westminster Reference Bible is a reference edition which means that the text
of Scripture is surrounded by footnotes, and notes.  These notes link various
places in the bible together for study purposes.  This bible has over 200,000 of
such references in its margins.  A regular reference or study bible might have
about 60,000-80,000 references.  These references come from John Brown&amp;rsquo;s
Self-Interpreting Bible.  Using the reference system, one can explore what else
the bible has to say on what is currently being read.&lt;/p&gt;
&lt;p&gt;And yet, despite this wealth of information on each page, the text of Holy
Scripture isn&amp;rsquo;t obscured or hard to read.  The helps and reference material only
comes into view when one desires.&lt;/p&gt;
&lt;h3 id="no-undermining"&gt;No undermining&lt;/h3&gt;
&lt;p&gt;Despite being a reference edition, it doesn&amp;rsquo;t undermine the reader&amp;rsquo;s confidence
in the text.  The Westminster Reference Bible doesn&amp;rsquo;t include comments on the
quality of the manuscripts used, let alone call any passages into question.&lt;/p&gt;
&lt;p&gt;Even R.L. Allan&amp;rsquo;s flagship &lt;em&gt;Longprimer&lt;/em&gt; has comments that say that a certain
reading isn&amp;rsquo;t supported by the oldest manuscripts.&lt;/p&gt;
&lt;h3 id="verse-by-verse"&gt;Verse by verse&lt;/h3&gt;
&lt;p&gt;The modern trend is to present the text of Scripture in a single-column,
paragraphed setting.  The Westminster Reference Bible is a verse-by-verse,
double-column edition.  This means that the volume can be smaller because the
two columns are more space efficient.  And just like the reference system, it
encourages bible study because it puts the verse number front and center.&lt;/p&gt;
&lt;p&gt;It may be argued that verse-by-verse double-column bibles are hard to read.
Yes, I&amp;rsquo;d say it&amp;rsquo;s more challenging than reading a novel.  However, slower
reading leads greater comprehension.&lt;/p&gt;
&lt;h3 id="obscure-words"&gt;Obscure words&lt;/h3&gt;
&lt;p&gt;In addition to its extensive reference system, it also has obsure words
explained inline.  Since the Westminster Reference Bible uses the text of the
KJV, some of the words used won&amp;rsquo;t be easily understood by the modern reader.  To
aid reading, the bible includes short explanations of these difficult words
right on the page.  This includes both archaic words, and so-called false
friends (e.g. &lt;em&gt;conversation&lt;/em&gt; used to have the sense of today&amp;rsquo;s &lt;em&gt;behaviour&lt;/em&gt;).&lt;/p&gt;
&lt;h3 id="chapter-summaries"&gt;Chapter summaries&lt;/h3&gt;
&lt;p&gt;Unlike modern editions of the bible, the Westminster Reference Bible doesn&amp;rsquo;t use
headings through the text.  Instead, it uses chapter summaries.  The reader can
quickly gain an overview of each chapter when locating a passage.  Moreover,
these summaries are original to the KJV, and as such are full of Reformed
theology.  This perhaps most obvious in the Psalms, e.g. the summary of Psalm
110 reads:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;A prediction of the kingdom, 4. priesthood, 5. triumphs, 7. and sufferings of Christ.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Or, the Song of Solomon, chapter 1:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;The church&amp;rsquo;s love unto Christ&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Chapter summaries are arguably more useful than headings in the text.  If
nothing else, they don&amp;rsquo;t introduce uninspired breaks in the text.&lt;/p&gt;
&lt;h3 id="pauline-authorship-of-hebrews"&gt;Pauline authorship of Hebrews&lt;/h3&gt;
&lt;p&gt;The Westminster Reference Bible proudly and rightly announces that the author of
the book of Hebrews is none other than the Apostle Paul.&lt;/p&gt;
&lt;h3 id="black-letter-edition"&gt;Black-letter edition&lt;/h3&gt;
&lt;p&gt;Unlike many modern-day editions of the KJV, the Westminster Reference Bible is a
black-letter edition.  This means that all of the words of the Holy Bible are in
black in contrast with red-letter editions which render the words of Christ in
red.  Reformed theology argues that &lt;em&gt;all scripture is given by inspiration of
God&lt;/em&gt; (2 Tim 3:16), and should therefore be red.  And red is of course hard to
read.&lt;/p&gt;
&lt;h3 id="italics"&gt;Italics&lt;/h3&gt;
&lt;p&gt;The KJV translators felt that certain words not present in the original had to
be added in order to translate a passage better.  These words they marked in
italics.  The Westminster Reference Bible respects their wishes, and prints
these words in italics.  It has been shown that these are somewhat arbitrary and
inconsistent, and one shouldn&amp;rsquo;t rely on them too much; however, they are still
useful in reminding the reader that translating a text from one language to
another isn&amp;rsquo;t an exact science, and a one-to-one correspondence isn&amp;rsquo;t always
achievable.&lt;/p&gt;
&lt;h3 id="no-quotation-marks"&gt;No quotation marks&lt;/h3&gt;
&lt;p&gt;Modern bibles introduce un-inspired quotation marks into the text to indicate
when a person starts speaking.  The problem is that sometimes these decisions
are wrong, and affect doctrine in negative ways.  An example of this can be
found in &lt;a href="https://purelypresbyterian.com/2016/04/24/was-johns-baptism-christian/"&gt;Acts 19&lt;/a&gt;.  The Westminster Reference Bible omits these quotation marks
just like the original text, allowing the diligent student of the Scriptures to
advance without distractions.&lt;/p&gt;
&lt;h3 id="epistle-to-the-reader"&gt;Epistle to the reader&lt;/h3&gt;
&lt;p&gt;The printed volume includes the KJV translators&amp;rsquo; &lt;em&gt;Epistle to the reader&lt;/em&gt; where
they explain their motivations.  Sadly, it is common today to exclude this
wonderful letter from printed editions.  This epistle argues against the modern
concept called &lt;em&gt;KJV Onlyism&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="reading-plan"&gt;Reading plan&lt;/h3&gt;
&lt;p&gt;If this is to be the best all-around bible, a reading plan is a must.  It keeps
the serious student of the word of God on grounded, and on track.  No external
tools are necessary.  It would make the perfect desert island bible.&lt;/p&gt;
&lt;h3 id="digital-font"&gt;Digital font&lt;/h3&gt;
&lt;p&gt;Unlike R.L. Allan&amp;rsquo;s &lt;em&gt;Longprimer&lt;/em&gt;, the Westminster Reference Bible doesn&amp;rsquo;t pander
to 1950s aesthetics, and it uses a modern digital font.  This makes the page
crisp and clean.&lt;/p&gt;
&lt;h3 id="high-view-of-scripture"&gt;High view of Scripture&lt;/h3&gt;
&lt;p&gt;The publisher&amp;rsquo;s high view of Scripture can be seen in their including three
separate pages with quotes from the Bible which highlight the Bible&amp;rsquo;s purity,
and excellence.  Not one, but three:  Psalm 119:18, Psalm 19:7-11, and 2 Timothy
3:16-17&lt;/p&gt;
&lt;h3 id="explanation-of-thees-and-thous"&gt;Explanation of thees and thous&lt;/h3&gt;
&lt;p&gt;The front matter in the book provides a helpful explanation of how the archaic
personal pronouns work.&lt;/p&gt;
&lt;h3 id="reformed-theology"&gt;Reformed theology&lt;/h3&gt;
&lt;p&gt;This bible is called the &lt;em&gt;Westminster&lt;/em&gt; Reference Bible: it&amp;rsquo;s built on the ideals
of the English reformation of the 17th century.  The Westminster Reference Bible
is as Reformed as the Westminster Confession of Faith.&lt;/p&gt;
&lt;p&gt;Another example is that the title page of the Old Testament reads &lt;em&gt;The Old
Testament of Jesus Christ&lt;/em&gt;.  And as mentioned above, many of the Old Testament
chapter summaries mention Christ or the church.  The whole bible is about him,
and the Westminster Reference Bible reminds you of it every now and then.&lt;/p&gt;
&lt;h3 id="sizes"&gt;Sizes&lt;/h3&gt;
&lt;p&gt;The Westminster Reference Bible comes in three size: large print, compact, and standard.  This offers the diligent student of the word of God flexibility: running to the hospital on a pastoral visit?  Grab the compact version.  Do you have folks in your church with aging eyes?  Pick up some large print editions.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;If you want a premium bible for not-much money, a reformed bible with high
standards, a pure text, and a great set of study features, look no further than
the Westminster Reference Bible.&lt;/p&gt;</description><author>Honza Pokorný</author><pubDate>Fri, 30 Oct 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://honza.pokorny.ca/2020/10/why-the-westminster-reference-bible-is-the-best-all-around-bible-you-can-buy/</guid></item><item><title>New book, same story.</title><link>http://evantravers.com/articles/2020/10/30/new-book-same-story/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/10/journal.jpg" /&gt;&lt;/p&gt;&lt;p&gt;On the left is a journal I started the day before I asked my future father-in-law for his blessing to marry Sarah. It's been with me &lt;em&gt;every&lt;/em&gt; night I was single, two trips to Europe, cross-country flights, camping trips… it's chock full of pictures, love notes, the frustrated scrawl of dark nights of the soul and delighted depictions of sunrises. In it I planned our wedding, prayed for my future children, celebrated every anniversary and birthday. It's scarred, tear-stained, rained on, prayed over, scratched out…&lt;/p&gt;
&lt;p&gt;It's probably the most precious physical object I own… and it's &lt;em&gt;full&lt;/em&gt;. It is time to pass the baton to the next journal.&lt;/p&gt;
&lt;p&gt;The timing could not be better.&lt;/p&gt;
&lt;p&gt;Each time I finish a journal I leave the last few pages blank. I then read through the whole thing noting down blessings and important moments in those spare pages. I revisit old prayer requests that have been answered, dreams that were realized, goals met. I will sing of God's goodness in marriage. I will rejoice again at the birth of my children. I will again weep over old sins and conflicts. I will see God's sovereign hand over the past five years compressed into a few pages of my handwritten thoughts.&lt;/p&gt;
&lt;p&gt;Journaling isn't just therapeutic. &lt;strong&gt;It's an opportunity to glance behind the tapestry of history to see what God has been weaving.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When I started the journal, I stood at a precipice: all I hoped for and held dear was in the hands of a loving and almighty God. In the years since, I have found him to be faithful. And I wrote it down.&lt;/p&gt;
&lt;p&gt;I'm starting this new journal tomorrow close to &lt;em&gt;another&lt;/em&gt; precipice of history: much that I hope for and hold dear in the balance. I'm grateful that God has ordained &lt;em&gt;this&lt;/em&gt; moment to remind me to look back on my little leather ebenezer… to remind me that &lt;strong&gt;He has not changed&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;New page. Same King. 🙏&lt;/p&gt;</description><author>trv.rs</author><pubDate>Fri, 30 Oct 2020 11:23:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/10/30/new-book-same-story/</guid></item><item><title>Restic backups to B2 without delete</title><link>https://pricey.uk/blog/restic-backups-without-delete/</link><description>&lt;p&gt;&lt;strong&gt;Update 2023-03-28:&lt;/strong&gt; Restic now supports limited keys by default, and also recommends the B2 S3 api instead. See &lt;a href="https://pricey.uk/blog/restic-backups-without-delete-in-2023/"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="original-post"&gt;Original Post:&lt;/h1&gt;
&lt;p&gt;Since setting up restic to back up to b2 I had embarassingly missunderstood the following UI wording around lifecycle settings:

&lt;a href="https://pricey.uk/blog/restic-backups-without-delete/Screenshot_2020-10-30 B2 Cloud Storage Buckets.png"&gt;
    &lt;img src="https://pricey.uk/blog/restic-backups-without-delete/&amp;#x2F;&amp;#x2F;pricey.uk&amp;#x2F;processed_images&amp;#x2F;Screenshot_2020-10-30 B2 Cloud Storage Buckets.d75d93b40fad08df.png" /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I had assumed that this meant that all versions of the file would be maintained, no matter what clients did. &lt;a href="https://www.backblaze.com/b2/docs/lifecycle_rules.html" rel="external"&gt;The B2 docs&lt;/a&gt; are much clearer, explaining that these rules are really only automation on your existing files. They're not blocks/holds/locks which can take any action before or affect api calls.&lt;/p&gt;
&lt;p&gt;In short: Lifecycle Rules schedule cleaning up version history, they don't prevent you deleting that version history.&lt;/p&gt;
&lt;p&gt;One of the capabilities I want from my backup system is that the system backing data up should not also be able to destroy existing backups. (I'm not bothered about it reading previous backups) I had assumed lifecycle rules gave me this, I was wrong, time for a quick fix...&lt;/p&gt;
&lt;p&gt;The obvious solution is to &lt;a href="https://www.backblaze.com/b2/docs/b2_create_key.html" rel="external"&gt;restrict the capabilities of the b2 api key&lt;/a&gt; during creation, specifically to omit &lt;code&gt;deleteFiles&lt;/code&gt;. Unfortunately, restic doesn't currently handle this well, for example during basic backups it requires the ability to delete files in the &lt;code&gt;locks/&lt;/code&gt; directory and will complain loudly. There are a few &lt;a href="https://github.com/restic/restic/issues/2134" rel="external"&gt;open issues&lt;/a&gt; and &lt;a href="https://github.com/restic/restic/pull/2887" rel="external"&gt;existing&lt;/a&gt; [PR]https://github.com/restic/restic/pull/2398(https://github.com/restic/restic/pull/2398)'s but nothing yet merged.&lt;/p&gt;
&lt;h2 id="enter-rclone"&gt;Enter rclone&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://restic.net/blog/2018-04-01/rclone-backend/" rel="external"&gt;A few years ago rclone gained support for serving storage to restic via it's api&lt;/a&gt; and since rclone &lt;a href="https://rclone.org/b2/#b2-hard-delete" rel="external"&gt;supports using soft delete by default&lt;/a&gt; swapping to this backend is pretty trivial.&lt;/p&gt;
&lt;p&gt;One of the best bits is that you can continue to use your existing config, the repository format is unchanged.&lt;/p&gt;
&lt;p&gt;The first thing to do is to generate a new key without &lt;code&gt;deleteFiles&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ b2 authorize-account
Using https://api.backblazeb2.com
Backblaze application key ID: &amp;lt;account key id&amp;gt;
Backblaze application key: 

$ b2 create-key --bucket bucketname keyname listBuckets,listFiles,readFiles,writeFiles
&amp;lt;app key id&amp;gt; &amp;lt;app key secret&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and then take that output to set up an rclone backend. You can either go through &lt;code&gt;rclone config&lt;/code&gt; (See &lt;a href="https://rclone.org/b2/#b2-hard-delete" rel="external"&gt;their docs&lt;/a&gt; for an example) or just drop a file into place:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cat ~/.config/rclone/rclone.conf
[b2]
type = b2
account = &amp;lt;app key id&amp;gt;
key = &amp;lt;app key secret&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then all that's left is to update your backup script:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;e.g. if previously it was&lt;pre&gt;&lt;code&gt;b2:bucketname:foldername
&lt;/code&gt;&lt;/pre&gt;
then now it'll be&lt;pre&gt;&lt;code&gt;rclone:b2:bucketname/foldername
&lt;/code&gt;&lt;/pre&gt;
(Note that the second part (&lt;code&gt;b2&lt;/code&gt;) now refers to the name of the rclone backend, not the type. e.g. the bit within the square brackets of rclone.conf config)&lt;/li&gt;
&lt;li&gt;Alter the options rclone is called with. Annoyingly, even though rclone uses soft delete in b2 by default, &lt;a href="https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html#other-services-via-rclone" rel="external"&gt;restic sets --b2-hard-delete by default...&lt;/a&gt; so add the following option whenever you run restic:&lt;pre&gt;&lt;code&gt;-o rclone.args=&amp;quot;serve restic --stdio&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="back-to-the-lifecycle"&gt;Back to the lifecycle...&lt;/h2&gt;
&lt;p&gt;Beyond &lt;code&gt;restic forget&lt;/code&gt;/&lt;code&gt;prune&lt;/code&gt; to manage old snapshots, we've now got to consider cleaning up soft deleted files. Given my backups are largely additive, &lt;code&gt;forget&lt;/code&gt; rarely frees much space so it's not my biggest priority.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://rclone.org/b2/#versions" rel="external"&gt;rclone provides a handy &lt;code&gt;cleanup&lt;/code&gt; command&lt;/a&gt;, but it's very tempting to go back to where I began and let Backblaze b2 lifecycles clean them up without any extra scheduling on your own infrastructure.&lt;/p&gt;
&lt;p&gt;Obligatory https://restic.readthedocs.io/en/stable/045_working_with_repos.html#checking-integrity-and-consistency reminder.&lt;/p&gt;</description><author>Joseph Price</author><pubDate>Fri, 30 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://pricey.uk/blog/restic-backups-without-delete/</guid></item><item><title>Linux Upskill Challenge</title><link>https://heitorpb.github.io/bla/linuxupskill/</link><description>My notes about the Linux Upskill Challenge.</description><author>Heitor's log</author><pubDate>Fri, 30 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://heitorpb.github.io/bla/linuxupskill/</guid></item><item><title>Once Upon a Snowman</title><link>https://blog.yiningkarlli.com/2020/10/once-upon-a-snowman.html</link><description>&lt;div style="display: none;"&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2 id="table-of-contents"&gt;Table of Contents&lt;/h2&gt;

&lt;div class="tableofcontents"&gt;
    &lt;div class="tableofcontents-row"&gt;
        &lt;div class="tableofcontents-column3"&gt;
            &lt;div class="tableofcontents-content"&gt;
                1. &lt;a href="/2020/10/once-upon-a-snowman.html#2020-10-30-notes"&gt;Making Once Upon a Snowman&lt;/a&gt;&lt;br /&gt;
                2. &lt;a href="/2020/10/once-upon-a-snowman.html#2020-10-30-frames"&gt;Frames from the Short&lt;/a&gt;&lt;br /&gt;
                3. &lt;a href="/2020/10/once-upon-a-snowman.html#2020-10-30-references"&gt;References&lt;/a&gt;&lt;br /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="tableofcontents-column3"&gt;
        &lt;/div&gt;
        &lt;div class="tableofcontents-column3"&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id="2020-10-30-notes"&gt;&lt;/div&gt;

&lt;p&gt;For the holiday season this year, &lt;a href="http://www.disneyanimation.com/"&gt;Walt Disney Animation Studios&lt;/a&gt; has a small surprise release!
Last month the studio announced the release of &lt;em&gt;Once Upon a Snowman&lt;/em&gt;, which is now out on Disney+ as of last week.
&lt;em&gt;Once Upon a Snowman&lt;/em&gt; is a short film that takes place during the events of &lt;em&gt;Frozen&lt;/em&gt; (2014) and follows Olaf between when Elsa creates him and when he runs into Anna and Kristoff.
The short fills in the gap to show how Olaf initially comes to learn who he is and the hijinks he gets up to along the way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_009.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_009.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From a technical perspective, &lt;em&gt;Once Upon a Snowman&lt;/em&gt; shares pretty much all of its tooling and tech with &lt;em&gt;Frozen 2&lt;/em&gt;, because &lt;em&gt;Once Upon a Snowman&lt;/em&gt; was made using the exact same pipeline and toolset version &lt;a href="/2019/11/froz2.html"&gt;that &lt;em&gt;Frozen 2&lt;/em&gt; was made with&lt;/a&gt;.
In fact, &lt;em&gt;Once Upon a Snowman&lt;/em&gt; was made overlapping with the end of production on &lt;em&gt;Frozen 2&lt;/em&gt; and completed a few months after &lt;em&gt;Frozen 2&lt;/em&gt; and has simply been waiting for release since then.
The thinking was that rather than spin down the &lt;em&gt;Frozen 2&lt;/em&gt; pipeline upon completion of the movie, why not keep it going for a bit longer to make a short?&lt;/p&gt;

&lt;p&gt;However, one enormous difference between &lt;em&gt;Once Upon a Snowman&lt;/em&gt; and &lt;em&gt;Frozen 2&lt;/em&gt; is the time period the story is set in, and therefore the versions of characters and sets that had to be built.
Since &lt;em&gt;Once Upon a Snowman&lt;/em&gt; is set during the events of &lt;em&gt;Frozen&lt;/em&gt;, the versions of Anna, Elsa, and Kristoff have to be the younger versions of themselves in their outfits from the first film.
In my &lt;em&gt;Frozen 2&lt;/em&gt; post, I wrote about all of the ways that &lt;em&gt;Frozen 2&lt;/em&gt; is an interesting benchmark for what we are capable of making today using Disney’s Hyperion Renderer &lt;a href="https://doi.org/10.1145/3182159"&gt;[Burley et al. 2018]&lt;/a&gt; versus what the studio was capable of back on the original &lt;em&gt;Frozen&lt;/em&gt; using RenderMan 17.
&lt;em&gt;Once Upon a Snowman&lt;/em&gt; is an even more direct comparison between Disney Animation’s modern tech and its 2014-era tech since all of the characters and sets are directly one-for-one matched to the original &lt;em&gt;Frozen&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Because Hyperion uses an evolved version &lt;a href="https://doi.org/10.1145/2776880.2787670"&gt;[Burley 2015]&lt;/a&gt; of the same Disney BSDF that &lt;em&gt;Frozen&lt;/em&gt; used an earlier version of &lt;a href="https://doi.org/10.1145/2343483.2343493"&gt;[Burley 2012]&lt;/a&gt;, porting assets forward from &lt;em&gt;Frozen&lt;/em&gt; to the modern pipeline doesn’t require a full rebuild from scratch.
The port isn’t just a direct copy either; a considerable amount of remastering and improvement has to be carried out to bring &lt;em&gt;Frozen&lt;/em&gt;-era assets up to our modern standard, but the work required is also still much less than starting over completely.
Oaken is a great example; the &lt;em&gt;Once Upon a Snowman&lt;/em&gt; version of Oaken is recognizably the same Oaken from &lt;em&gt;Frozen&lt;/em&gt;, but looking closely reveals a number of upgrades.
The &lt;em&gt;Once Upon a Snowman&lt;/em&gt; version has vastly more convincing subsurface scattering &lt;a href="https://doi.org/10.1145/2897839.2927433"&gt;[Chiang et al. 2016a]&lt;/a&gt;, various subtle global illumination effects, vastly better hair shading, and even some improved geometric details such as far more detailed fuzz on his sweater:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/compare_001.png"&gt;&lt;img alt="Left: Oaken in &amp;lt;em&amp;gt;Frozen&amp;lt;/em&amp;gt;. Right: Oaken in &amp;lt;em&amp;gt;Once Upon a Snowman&amp;lt;/em&amp;gt;, in the same time period and setting as &amp;lt;em&amp;gt;Frozen&amp;lt;/em&amp;gt;." src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/compare_001.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The impact of the modern-day &lt;em&gt;Zootopia&lt;/em&gt;-era fur/hair shader is really apparent on the wolves that are seen in both &lt;em&gt;Frozen&lt;/em&gt; and &lt;em&gt;Once Upon a Snowman&lt;/em&gt;.
In &lt;em&gt;Frozen&lt;/em&gt;, these wolves are seen chasing Anna and Kristoff’s sled, and in &lt;em&gt;Once Upon a Snowman&lt;/em&gt; we see them shortly after the events of &lt;em&gt;Frozen&lt;/em&gt;, this time interacting with Olaf.
During &lt;em&gt;Zootopia&lt;/em&gt; we learned an enormous amount about making white fur look convincingly fluffy and soft &lt;a href="https://dl.acm.org/doi/10.1145/2936733.2936736"&gt;[Burkard et al 2016]&lt;/a&gt;; the look comes entirely from high-order multiple scattering.
&lt;em&gt;Frozen&lt;/em&gt; used a version of our &lt;em&gt;Tangled&lt;/em&gt;-era hair shader &lt;a href="https://doi.org/10.1145/1778765.1778793"&gt;[Sadeghi et al. 2010]&lt;/a&gt; and point-based hair lighting &lt;a href="https://doi.org/10.1145/1899950.1899967"&gt;[Montoya-Vozmediano 2010]&lt;/a&gt;, for which high-order multiple scattering effects were simply impossible to practically achieve, but today using Hyperion and our modern &lt;em&gt;Zootopia&lt;/em&gt;-era fur/hair model &lt;a href="https://doi.org/10.1111/cgf.12830"&gt;[Chiang et al. 2016b]&lt;/a&gt;, this is now easy for us to achieve.
The version of the wolves in &lt;em&gt;Once Upon a Snowman&lt;/em&gt; also sports a considerably higher curve count and far more advanced groom:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/compare_002.png"&gt;&lt;img alt="Left: Wolves in &amp;lt;em&amp;gt;Frozen&amp;lt;/em&amp;gt;. Right: The same wolves in &amp;lt;em&amp;gt;Once Upon a Snowman&amp;lt;/em&amp;gt;, in the same time period and setting as &amp;lt;em&amp;gt;Frozen&amp;lt;/em&amp;gt;." src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/compare_002.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The interesting artistic challenge of porting assets from older shows to the modern pipeline is that they simultaneously need to be upgraded but still look recognizable when compared with the original.
They don’t need to look &lt;em&gt;identical&lt;/em&gt;, but should look similar enough that they feel the same in the viewer’s memory.
One way I’ve heard artists describe it that I really like is: things always look better in our memories than they actually did at the time, and the match we have to aim for is as good as our memories’ retroactively improved version.
A great example of this is the establishing shot of Wandering Oaken’s Trading Post; this is one of the closest matching shots between &lt;em&gt;Frozen&lt;/em&gt; and &lt;em&gt;Once Upon a Snowman&lt;/em&gt;.
Looking closely there are a bunch of apparent visual improvements in the &lt;em&gt;Once Upon a Snowman&lt;/em&gt; version: the &lt;em&gt;Frozen&lt;/em&gt; version is very clearly lacking multi-bounce global illumination between the snow and the structure and a lot of the colors on the structure look simultaneously more muted and higher contrast than one would expect, whereas the &lt;em&gt;Once Upon a Snowman&lt;/em&gt; version has richer colors from multi-bounce global illumination, softer light scattering through the snow on the trees, more detailed and richer shadowing, and so on and so forth.
However, if you just glance between the two versions, they are definitely recognizably the same place at nearly the same moment in time:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/compare_003.png"&gt;&lt;img alt="Left: Wandering Oaken's Trading Post in &amp;lt;em&amp;gt;Frozen&amp;lt;/em&amp;gt;. Right: The same Trading Post in &amp;lt;em&amp;gt;Once Upon a Snowman&amp;lt;/em&amp;gt;, in the same time period and setting as &amp;lt;em&amp;gt;Frozen&amp;lt;/em&amp;gt;." src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/compare_003.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In general, an interesting thing about the shift to fully physically based shading and path-traced rendering is that many effects that previously were extraordinarily difficult to achieve in the old ad-hoc rasterized world are now really easy to achieve &lt;a href="https://jo.dreggn.org/path-tracing-in-production/2017/index.html"&gt;[Burley et al. 2017]&lt;/a&gt;.
Another great example in addition to everything above is Elsa’s ice palace; for the original &lt;em&gt;Frozen&lt;/em&gt;, rendering the ice palace’s complex layers of refractive ice was an enormous challenge that took a wide combination of specialized rendering and compositing tricks to achieve &lt;a href="https://doi.org/10.1145/2614106.2614137"&gt;[Siegel 2014]&lt;/a&gt;, but with our modern renderer, all we have to do is assign a standard Disney BSDF material, make it refractive, and hit render, and it all just works.
The ice palace is only seen in one shot in &lt;em&gt;Once Upon a Snowman&lt;/em&gt;, but even that single shot in the pre-Hyperion world would have taken considerable effort to put together, whereas in the modern workflow it didn’t merit any special consideration at all to achieve.&lt;/p&gt;

&lt;p&gt;Normally I’d write that the entire short was rendered using Disney’s Hyperion Renderer, but there’s actually a special quirk about &lt;em&gt;Once Upon a Snowman&lt;/em&gt;: the first seven shots are directly edited in from the original &lt;em&gt;Frozen&lt;/em&gt;’s final footage, so they predate Hyperion.
However, one shot is actually &lt;em&gt;extended&lt;/em&gt; from the original &lt;em&gt;Frozen&lt;/em&gt;; the third shot in &lt;em&gt;Once Upon a Snowman&lt;/em&gt; is much longer than in the original &lt;em&gt;Frozen&lt;/em&gt;.
For &lt;em&gt;Once Upon a Snowman&lt;/em&gt;, this shot was extended to stay on Olaf much longer to shift the story focus from Elsa to Olaf, but had to maintain a consistent look with the surrounding shots pulled directly from &lt;em&gt;Frozen&lt;/em&gt;.
Just re-rendering this single shot by itself using Hyperion would have made for a bit of a jarring jump between older-style RenderMan 17 visuals, a richer looking shot with modern global illumination using Hyperion, and then back to older-style visuals for a few more shots.
However, re-rendering all of the &lt;em&gt;Frozen&lt;/em&gt; footage using Hyperion was also not a great solution, since it would have entailed a lot of extraneous extra work just to reproduce footage that we already had.
Instead, the right solution was to extend, re-animate, and then re-render the shot &lt;em&gt;in the original Frozen pipeline&lt;/em&gt;, which is a much harder thing to do than one might think!&lt;/p&gt;

&lt;p&gt;In the six years since the original &lt;em&gt;Frozen&lt;/em&gt;’s release, the studio’s hardware standard and software stack has evolved considerably, and RenderMan hasn’t been run in-house for many, many years.
Instead of trying to get the original &lt;em&gt;Frozen&lt;/em&gt;’s pipeline up and running on the latest hardware and operating system version, the easier approach was just to resurrect a handful of mothballed workstations from the &lt;em&gt;Frozen&lt;/em&gt;-era and do everything using the &lt;em&gt;Frozen&lt;/em&gt;-era pipeline running on the same operating system version used during &lt;em&gt;Frozen&lt;/em&gt;.
Essentially we built a little time capsule just to create the extended version of that shot.
I wasn’t involved with this effort, but it was great fun to watch it unfold a few offices down the hall from the Hyperion team’s office.
Starting with the shot of Elsa’s cloak knocking Olaf down the hill, all shots in the rest of the short are rendered using Hyperion, and if you compare the shot immediately before the first Hyperion shot with the first Hyperion shot, you can see a clear jump in visual quality.&lt;/p&gt;

&lt;p&gt;I think it’s pretty interesting and cool how Anna, Elsa, Olaf, Sven, Kristoff, and the rest of the &lt;em&gt;Frozen&lt;/em&gt; cast and world have become a sort of de facto benchmark for Hyperion and Disney Animation’s continued animation and graphics tech capabilities over time.
The original &lt;em&gt;Frozen&lt;/em&gt; marked the studio’s last RenderMan show and therefore represents the farthest the studio was able to push visual quality before path tracing, and since then, &lt;em&gt;Frozen Fever&lt;/em&gt;, &lt;em&gt;Olaf’s Frozen Adventure&lt;/em&gt;, &lt;em&gt;Frozen 2&lt;/em&gt;, and &lt;em&gt;Once Upon a Snowman&lt;/em&gt; were all made using successively more capable versions of Hyperion, with all of the characters and sets being ported forward to use the latest tech each time.
The history of Frozen’s core characters is also a series of snapshots in the history of modern Disney Animation’s continuously advancing technology and CG production capabilities.&lt;/p&gt;

&lt;p&gt;Here are some frames from &lt;em&gt;Once Upon a Snowman&lt;/em&gt; from Disney+, presented in no particular order.
You can stream &lt;em&gt;Once Upon a Snowman&lt;/em&gt; &lt;a href="https://www.disneyplus.com/browse/entity-44235067-134c-4229-a095-f2866b8260af"&gt;on Disney+&lt;/a&gt;; as always I suggest seeing it on the biggest screen you can!&lt;/p&gt;

&lt;div id="2020-10-30-frames"&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_002.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_002.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_011.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_011.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_017.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_017.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_003.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_003.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_014.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_014.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_005.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_005.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_007.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_007.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_020.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_020.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_013.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_013.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_008.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_008.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_001.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_001.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_006.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_006.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_012.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_012.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_018.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_018.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_010.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_010.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_015.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_015.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_004.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_004.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_021.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_021.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_016.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_016.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_019.jpg"&gt;&lt;img alt="" src="https://blog.yiningkarlli.com/content/images/2020/Oct/frolaf/FROLAF_019.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All images in this post are courtesy of and the property of Walt Disney Animation Studios.&lt;/p&gt;

&lt;div id="2020-10-30-references"&gt;&lt;/div&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;

&lt;p&gt;Nicholas Burkard, Hans Keim, Brian Leach, Sean Palmer, Ernest J. Petti, and Michelle Robinson. 2016. &lt;a href="https://dl.acm.org/doi/10.1145/2936733.2936736"&gt;From Armadillo to Zebra: Creating the Diverse Characters and World of &lt;em&gt;Zootopia&lt;/em&gt;&lt;/a&gt;. In &lt;em&gt;ACM SIGGRAPH 2016 Production Sessions&lt;/em&gt;. Article 24.&lt;/p&gt;

&lt;p&gt;Brent Burley. 2012. &lt;a href="https://doi.org/10.1145/2343483.2343493"&gt;Physically Based Shading at Disney&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2012-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2012 Course Notes: Practical Physically-Based Shading in Film and Game Production&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Brent Burley. 2015. &lt;a href="https://doi.org/10.1145/2776880.2787670"&gt;Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2015-shading-course"&gt;&lt;em&gt;ACM SIGGRAPH 2015 Course Notes: Physically Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Brent Burley, David Adler, Matt Jen-Yuan Chiang, Ralf Habel, Patrick Kelly, Peter Kutz, Yining Karl Li, and Daniel Teece. 2017. &lt;a href="https://drive.google.com/file/d/1kFpp_7I8vH8LHsf1Si94pqMkHxwinMSU/view"&gt;Recent Advancements in Disney’s Hyperion Renderer&lt;/a&gt;. In &lt;em&gt;ACM SIGGRAPH 2017 Course Notes: &lt;a href="https://jo.dreggn.org/path-tracing-in-production/2017/index.html"&gt;Path Tracing in Production Part 1&lt;/a&gt;&lt;/em&gt;. 26-34.&lt;/p&gt;

&lt;p&gt;Brent Burley, David Adler, Matt Jen-Yuan Chiang, Hank Driskill, Ralf Habel, Patrick Kelly, Peter Kutz, Yining Karl Li, and Daniel Teece. 2018. &lt;a href="https://doi.org/10.1145/3182159"&gt;The Design and Evolution of Disney’s Hyperion Renderer&lt;/a&gt;. &lt;em&gt;ACM Transactions on Graphics&lt;/em&gt; 37, 3 (Jul. 2018), Article 33.&lt;/p&gt;

&lt;p&gt;Matt Jen-Yuan Chiang, Benedikt Bitterli, Chuck Tappan, and Brent Burley. 2016. &lt;a href="https://doi.org/10.1111/cgf.12830"&gt;A Practical and Controllable Hair and Fur Model for Production Path Tracing&lt;/a&gt;. &lt;em&gt;Computer Graphics Forum (Proc. of Eurographics)&lt;/em&gt; 35, 2 (May 2016), 275-283.&lt;/p&gt;

&lt;p&gt;Matt Jen-Yuan Chiang, Peter Kutz, and Brent Burley. 2016. &lt;a href="https://doi.org/10.1145/2897839.2927433"&gt;Practical and Controllable Subsurface Scattering for Production Path Tracing&lt;/a&gt;. In &lt;em&gt;ACM SIGGRAPH 2016 Talks&lt;/em&gt;. Article 49.&lt;/p&gt;

&lt;p&gt;Ramón Montoya-Vozmediano. 2010. &lt;a href="https://doi.org/10.1145/1899950.1899967"&gt;Point-Based Hair Global Illumination&lt;/a&gt;. In &lt;em&gt;ACM SIGGRAPH Asia 2010 Sketches&lt;/em&gt;. Article 17.&lt;/p&gt;

&lt;p&gt;Iman Sadeghi, Heather Pritchett, Henrik Wann Jensen, and Rasmus Tamstorf. 2010. &lt;a href="https://doi.org/10.1145/1778765.1778793"&gt;An Artist Friendly Hair Shading System&lt;/a&gt;. &lt;em&gt;ACM Transactions on Graphics (Proc. of SIGGRAPH)&lt;/em&gt; 29, 4 (Jul. 2010), Article 56.&lt;/p&gt;

&lt;p&gt;Lewis Siegel. 2014. &lt;a href="https://doi.org/10.1145/2614106.2614137"&gt;Frozen on Ice: Rendering Frost and Ice on Frozen&lt;/a&gt;. In &lt;em&gt;ACM SIGGRAPH 2014 Talks&lt;/em&gt;. Article 8.&lt;/p&gt;</description><author>Code &amp;amp; Visuals</author><pubDate>Fri, 30 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.yiningkarlli.com/2020/10/once-upon-a-snowman.html</guid></item><item><title>Just More Color</title><link>https://benovermyer.com/blog/2020/10/just-more-color/</link><description>&lt;p&gt;Today I reworked my site's CSS a bit to add more color.&lt;/p&gt;
&lt;p&gt;This is a work in progress. Over time I plan to do more to liven the site up, while still trying to keep the overall size small.&lt;/p&gt;
&lt;p&gt;Next, I'm considering whether to add more images to some parts of the site.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Fri, 30 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/10/just-more-color/</guid></item><item><title>Google new easter egg!</title><link>https://thatxliner.github.io/posts/google-new-easter-egg/</link><description>Just Google "is the earth flat".</description><author>ThatXliner's Blog</author><pubDate>Fri, 30 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://thatxliner.github.io/posts/google-new-easter-egg/</guid></item><item><title>Sabertooth Motor Drivers in Julia and Javascript</title><link>https://macleodsawyer.com/tech/sabertooth/</link><description>&lt;p&gt;Julia &amp;amp; Javascript Libraries to control the Sabertooth motor controller&lt;/p&gt;
&lt;p&gt;Simple to use Julia and Javascript APIs for Sabertooth motor controllers (made by Dimension Engineering) - The official API only has support for Python, C#, and Arduino - I needed one for quick prototyping and this was born.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sabertooth.jl repo can be found &lt;a href="https://github.com/drannex42/Sabertooth.jl"&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Sabertooth.js repo can be found &lt;a href="https://github.com/drannex42/Sabertooth.js"&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sabertooth.jl---repo" tabindex="-1"&gt;&lt;a class="header-anchor" href="#sabertooth.jl---repo"&gt;
          &lt;span&gt;#&lt;/span&gt;
        &lt;/a&gt; Sabertooth.jl - &lt;a href="https://github.com/drannex42/Sabertooth.jl"&gt;Repo&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="source" tabindex="-1"&gt;&lt;a class="header-anchor" href="#source"&gt;
          &lt;span&gt;#&lt;/span&gt;
        &lt;/a&gt; Source&lt;/h3&gt;
&lt;pre class="language-julia"&gt;&lt;code class="language-julia"&gt;&lt;span class="token keyword"&gt;module&lt;/span&gt; Sabertooth&lt;br /&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;using&lt;/span&gt; SerialPorts&lt;br /&gt;&lt;span class="token comment"&gt;# Motor commands&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; forward_m1 &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x00&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; reverse_m1 &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x01&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; forward_m2 &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x04&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; reverse_m2 &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x05&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; forward_mixed &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x08&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; reverse_mixed &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x09&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; right_mixed &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x0A&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; left_mixed &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x0B&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; ramp &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;0x10&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;&lt;span class="token comment"&gt;# Modify the serial port configs as needed&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; portname &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token string"&gt;"/dev/ttyACM0"&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; baudrate &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;115200&lt;/span&gt; &lt;span class="token comment"&gt;#Default baudrate for Sabertooth (115200)&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; address &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;128&lt;/span&gt; &lt;span class="token comment"&gt;# The address of the Sabertooth. By default, this is 128.&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; mask &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;127&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;s &lt;span class="token operator"&gt;=&lt;/span&gt; SerialPort&lt;span class="token punctuation"&gt;(&lt;/span&gt;portname&lt;span class="token punctuation"&gt;,&lt;/span&gt; baudrate&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;# Instantiate the serial port&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;# sendCommand(command, data): Core motor controller function, this sends an update out to the motor controller hardware, all other functions should call this function instead of rewriting. &lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;function&lt;/span&gt; sendCommand&lt;span class="token punctuation"&gt;(&lt;/span&gt;command&lt;span class="token punctuation"&gt;,&lt;/span&gt; data&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        checksum &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;address &lt;span class="token operator"&gt;+&lt;/span&gt; command &lt;span class="token operator"&gt;+&lt;/span&gt; data&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;&amp;amp;&lt;/span&gt; &lt;span class="token number"&gt;127&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;# Calculate the required checksum with the bitwise operator for the bytesize (mask)&lt;/span&gt;&lt;br /&gt;        newUpdate &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;UInt8&lt;span class="token punctuation"&gt;(&lt;/span&gt;address&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; UInt8&lt;span class="token punctuation"&gt;(&lt;/span&gt;command&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; UInt8&lt;span class="token punctuation"&gt;(&lt;/span&gt;data&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; UInt8&lt;span class="token punctuation"&gt;(&lt;/span&gt;checksum&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;span class="token comment"&gt;# Create an array buffer of bytes to send to the motor controller hardware &lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        write&lt;span class="token punctuation"&gt;(&lt;/span&gt;s&lt;span class="token punctuation"&gt;,&lt;/span&gt; newUpdate&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token comment"&gt;# Write to the motor controller hardware&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;&lt;span class="token comment"&gt;# drive(motor, speed): This controls one motor at a time&lt;/span&gt;&lt;br /&gt;     &lt;span class="token keyword"&gt;function&lt;/span&gt; drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;motor&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="token comment"&gt;# Reverse commands are equal to forward + 1&lt;/span&gt;&lt;br /&gt;        cmds &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;forward_m1&lt;span class="token punctuation"&gt;,&lt;/span&gt; forward_m2&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;        &lt;span class="token keyword"&gt;try&lt;/span&gt;&lt;br /&gt;            command &lt;span class="token operator"&gt;=&lt;/span&gt; cmds&lt;span class="token punctuation"&gt;[&lt;/span&gt;motor&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class="token keyword"&gt;catch&lt;/span&gt;&lt;br /&gt;            @warn &lt;span class="token string"&gt;"Drive error, invalid motor number: $motor"&lt;/span&gt;&lt;br /&gt;        &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class="token keyword"&gt;if&lt;/span&gt; speed &lt;span class="token operator"&gt;&amp;lt;&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt; &lt;br /&gt;            speed &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;speed&lt;br /&gt;            command &lt;span class="token operator"&gt;=&lt;/span&gt; command &lt;span class="token operator"&gt;+&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt; &lt;br /&gt;        &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class="token keyword"&gt;if&lt;/span&gt; speed &lt;span class="token operator"&gt;&gt;&lt;/span&gt; &lt;span class="token number"&gt;100&lt;/span&gt; &lt;br /&gt;            @warn &lt;span class="token string"&gt;"Drive error, invalid speed: $speed"&lt;/span&gt;&lt;br /&gt;        &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        calculatedspeed &lt;span class="token operator"&gt;=&lt;/span&gt; round&lt;span class="token punctuation"&gt;(&lt;/span&gt;Int&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token operator"&gt;*&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;127&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token operator"&gt;/&lt;/span&gt; &lt;span class="token number"&gt;100&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        sendCommand&lt;span class="token punctuation"&gt;(&lt;/span&gt;command&lt;span class="token punctuation"&gt;,&lt;/span&gt; calculatedspeed&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;# stop(): Stops both motors&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;function&lt;/span&gt; stop&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;br /&gt;        drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;0&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;# driveBoth(speed_m1, speed_m2):&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;function&lt;/span&gt; driveBoth&lt;span class="token punctuation"&gt;(&lt;/span&gt;speed_m1&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed_m2&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed_m1&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed_m2&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="token comment"&gt;# driveTank(speed)&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;function&lt;/span&gt; driveTank&lt;span class="token punctuation"&gt;(&lt;/span&gt;speed&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;        drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="token keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="usage" tabindex="-1"&gt;&lt;a class="header-anchor" href="#usage"&gt;
          &lt;span&gt;#&lt;/span&gt;
        &lt;/a&gt; Usage&lt;/h3&gt;
&lt;pre class="language-julia"&gt;&lt;code class="language-julia"&gt;&lt;br /&gt;&lt;span class="token operator"&gt;//&lt;/span&gt; drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;number&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;::&lt;/span&gt; number&lt;span class="token punctuation"&gt;:&lt;/span&gt; &lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt; &lt;span class="token punctuation"&gt;::&lt;/span&gt; speed&lt;span class="token punctuation"&gt;:&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;100&lt;/span&gt; to &lt;span class="token number"&gt;100&lt;/span&gt; &lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;50&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;drive&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;75&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token operator"&gt;//&lt;/span&gt; driveBoth&lt;span class="token punctuation"&gt;(&lt;/span&gt;speed_m1&lt;span class="token punctuation"&gt;,&lt;/span&gt; speed_m2&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;driveBoth&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;50&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;80&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token operator"&gt;//&lt;/span&gt; driveTank&lt;span class="token punctuation"&gt;(&lt;/span&gt;speed&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;::&lt;/span&gt; speed&lt;span class="token punctuation"&gt;:&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;100&lt;/span&gt; to &lt;span class="token number"&gt;100&lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;driveTank&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;50&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token operator"&gt;//&lt;/span&gt; Stop&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;stop&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="sabertooth.js-(javascript)---repo" tabindex="-1"&gt;&lt;a class="header-anchor" href="#sabertooth.js-(javascript)---repo"&gt;
          &lt;span&gt;#&lt;/span&gt;
        &lt;/a&gt; Sabertooth.js (Javascript) - &lt;a href="https://github.com/drannex42/Sabertooth.js"&gt;Repo&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="install" tabindex="-1"&gt;&lt;a class="header-anchor" href="#install"&gt;
          &lt;span&gt;#&lt;/span&gt;
        &lt;/a&gt; Install&lt;/h3&gt;
&lt;pre class="language-bash"&gt;&lt;code class="language-bash"&gt;&lt;span class="token function"&gt;npm&lt;/span&gt; &lt;span class="token function"&gt;install&lt;/span&gt; sabertoothjs&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="usage-1" tabindex="-1"&gt;&lt;a class="header-anchor" href="#usage-1"&gt;
          &lt;span&gt;#&lt;/span&gt;
        &lt;/a&gt; Usage&lt;/h3&gt;
&lt;pre class="language-js"&gt;&lt;code class="language-js"&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt; Sabertooth &lt;span class="token punctuation"&gt;}&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;require&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;'sabertoothjs'&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// Sabertooth(port, baudrate, address) (default: 128)&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;var&lt;/span&gt; saber &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token keyword"&gt;new&lt;/span&gt; &lt;span class="token class-name"&gt;Sabertooth&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;'/dev/ttyACM0'&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;115200&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// drive(number, speed) :: number: 1-2 :: speed: -100 to 100 &lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;drive&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;1&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;50&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;drive&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;2&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token operator"&gt;-&lt;/span&gt;&lt;span class="token number"&gt;75&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// driveBoth(speed_m1, speed_m2)&lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;driveBoth&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;50&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token number"&gt;80&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// driveTank(speed) :: speed: -100 to 100&lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;driveTank&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token number"&gt;50&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="token comment"&gt;// Stop&lt;/span&gt;&lt;br /&gt;saber&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;stop&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;</description><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Fri, 30 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/tech/sabertooth/</guid></item><item><title>Unevenness at the edges</title><link>https://bytepawn.com/unevenness-at-the-edges.html</link><description>&lt;p&gt;Sometimes we look at the top performers in a field and see obviously uneven representations of groups (gender, ethnicity, etc). There a multitude of factors that can lead to it, such as unfair bias in access to opportunities. Here I will show one unintuitive mathematical effect that can contribute to such unevenness in the case of normal distributions. &lt;br /&gt;&lt;br /&gt; &lt;img src="/images/mean_shift_02.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 30 Oct 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/unevenness-at-the-edges.html</guid></item><item><title>COVID19 accelerates dispersion of private health data</title><link>https://stop.zona-m.net/2020/10/covid19-accelerates-dispersion-of-private-health-data/</link><description>&lt;p&gt;Here is something unsuprising, but NEVER repeated enough.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 29 Oct 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/covid19-accelerates-dispersion-of-private-health-data/</guid></item><item><title>How to get the real PHP memory usage on macOS</title><link>https://swag.industries/get-real-memory-usage-of-php-under-macos/</link><description>&lt;p&gt;PHP provides the function &lt;a href="https://www.php.net/manual/fr/function.memory-get-usage.php?ref=swag.industries"&gt;memory_get_usage()&lt;/a&gt;, this is very helpful whenever you find your code using a lot of RAM. But this method has a significant limitation: it only counts memory used by your code directly &lt;strong&gt;and nothing out of the zend engine&lt;/strong&gt;.&lt;/p&gt;&lt;p&gt;The problem is that you may&lt;/p&gt;</description><author>Swag Industries</author><pubDate>Thu, 29 Oct 2020 13:02:25 GMT</pubDate><guid isPermaLink="true">https://swag.industries/get-real-memory-usage-of-php-under-macos/</guid></item><item><title>Mastering TorchScript: Tracing vs Scripting, Device Pinning, Direct Graph Modification</title><link>https://paulbridger.com/posts/mastering-torchscript/</link><description>TorchScript is one of the most important parts of the Pytorch ecosystem, allowing portable, efficient and nearly seamless deployment. With just a few lines of &lt;code&gt;torch.jit&lt;/code&gt; code and some simple model changes you can export an asset that runs anywhere &lt;code&gt;libtorch&lt;/code&gt; does. It&amp;rsquo;s an important toolset to master if you want to run your models outside the lab at high efficiency. This article is a collection of topics going beyond the basics of your first export.</description><author>Machine Learning Articles on paulbridger.com</author><pubDate>Thu, 29 Oct 2020 08:43:23 GMT</pubDate><guid isPermaLink="true">https://paulbridger.com/posts/mastering-torchscript/</guid></item><item><title>Problem Solving</title><link>https://denvaar.dev/posts/problem_solving_example.html</link><description>Going meta - Working through a programming problem to understand problem solving techniques.</description><author>denvaar's website</author><pubDate>Thu, 29 Oct 2020 07:40:09 GMT</pubDate><guid isPermaLink="true">https://denvaar.dev/posts/problem_solving_example.html</guid></item><item><title>APEX 20.2: improve Dropzone UX with CSS</title><link>https://hartenfeller.dev/blog/apex-dropzone-ux</link><description>Great News: APEX 20.2 is finally out and adds a Dropzone component. For me, it does not look as intuitive as the Plug-In did, so I tried to improve the UX of it with a few lines of CSS.</description><author>Philipp Hartenfeller Blog RSS Feed</author><pubDate>Thu, 29 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://hartenfeller.dev/blog/apex-dropzone-ux</guid></item><item><title>Notes on Serverless GraphQL with AWS AppSync</title><link>https://www.swyx.io/serverless-graphql-appsync</link><description>My Notes on Slobodan Stojanovic's Serverless GraphQL with AppSync talk</description><author>swyx's site RSS Feed</author><pubDate>Thu, 29 Oct 2020 01:28:50 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/serverless-graphql-appsync</guid></item><item><title>Users Council for breaking up web giants?</title><link>https://oo.svbtle.com/users-council-for-breaking-up-web-giants</link><description>&lt;p&gt;One day thinking about privacy issues lead me to the idea applying of works councils, but just for users.&lt;/p&gt;
&lt;h3 id="what-is-a-works-council_3"&gt;What is a Works Council? &lt;a class="head_anchor" href="#what-is-a-works-council_3"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In some countries, a &lt;a href="https://en.wikipedia.org/wiki/Works_council"&gt;works council&lt;/a&gt; can be formed if a company has reached a certain amount of employees. These employees then get to vote for representatives that get stake within the company for representing worker rights. This was needed to counteract company interest over their employees basic needs.&lt;/p&gt;
&lt;h3 id="how-could-this-work-for-users_3"&gt;How could this work for users? &lt;a class="head_anchor" href="#how-could-this-work-for-users_3"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Well, why shouldn’t we extend something like this for users?&lt;/p&gt;

&lt;p&gt;The idea is basically, if a web company reaches a certain size (by users/countries/…) - users &lt;em&gt;somehow magically&lt;/em&gt; get to initialize the process for electing a users council.&lt;/p&gt;

&lt;p&gt;This council would then become more included within organizational structure, would get special insights/space within the organization (including seeing more what happens behind the curtains, …) and get to decide certain decisions within that company that would then hopefully lead to more user oriented needs over profits and data mining.&lt;/p&gt;
&lt;h3 id="why_3"&gt;Why? &lt;a class="head_anchor" href="#why_3"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So that’s it. Very simple idea, which will most likely never work out. Yet, I do believe we really have to keep thinking about how we can get back control over the web giants.&lt;/p&gt;</description><author>Syd Norpol</author><pubDate>Thu, 29 Oct 2020 01:26:55 GMT</pubDate><guid isPermaLink="true">https://oo.svbtle.com/users-council-for-breaking-up-web-giants</guid></item><item><title>2020–10–29: New p-boot features – reboot to FEL/eMMC, 60FPS fix</title><link>https://xnux.eu/log/#023</link><author>megi's PinePhone Development Log</author><pubDate>Thu, 29 Oct 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#023</guid></item><item><title>Horizon Europe does the right thing</title><link>https://stop.zona-m.net/2020/10/horizon-europe-does-the-right-thing/</link><description>&lt;p&gt;Who says the EU is always bad???&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 28 Oct 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/horizon-europe-does-the-right-thing/</guid></item><item><title>Building Local Legends</title><link>https://medium.com/strava-engineering/building-local-legends-290879265c83</link><description>&lt;p&gt;In late 2019, Strava’s product development team began forming ideas about a new way to compete
on Strava. Strava segments have always provided a way to recognize athletic achievement through
a form of racing. Now, we wanted to also recognize the grit that goes into training. Those
athletes who are out on the trail every day, rain or shine, striving for more. Local Legends is
the result of these ideas, recognizing the athlete who’s completed a segment the most times in
the last 90 days. I was lucky enough to play an important role in building this feature, and in
this blog post, I want to tell the story of how we developed Local Legends and explore some of
the technical challenges we faced along the way.&lt;/p&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Wed, 28 Oct 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://medium.com/strava-engineering/building-local-legends-290879265c83</guid></item><item><title>Battlestation bookmarks</title><link>https://xenodium.com/battlestation-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/twostraws/status/1321064772276789248"&gt;Hacking with Swift's battlestation.&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/battlestations/"&gt;/r/battlestations&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Wed, 28 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/battlestation-bookmarks</guid></item><item><title>Let's Fix the News</title><link>https://tiltingatwindmills.dev/lets-fix-the-news/</link><description>As another US presidential election draws near, the brokenness of the media is
becoming ever more glaring. It's not exactly a new phenomenon…</description><author>Tilting at Windmills</author><pubDate>Wed, 28 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://tiltingatwindmills.dev/lets-fix-the-news/</guid></item><item><title>On Forever Projects</title><link>https://benovermyer.com/blog/2020/10/on-forever-projects/</link><description>&lt;p&gt;I just finished reading a blog post entitled &lt;a href="https://heredragonsabound.blogspot.com/2020/02/the-forever-project.html" rel="external"&gt;The Forever Project&lt;/a&gt; by Scott Turner of Here Dragons Abound. It made me reflect on Iron Arachne and what I'm trying to do with it.&lt;/p&gt;
&lt;p&gt;Lately I've been taking a break from Iron Arachne, and while on that break, I've found that I lack motivation or interest in continuing it. But this blog post made me reconsider that. It's not that I lack motivation or interest in &lt;em&gt;Iron Arachne&lt;/em&gt;, but rather that I've been too focused on developing the site as a tool for others to use and not near enough on what I originally started it for.&lt;/p&gt;
&lt;p&gt;Iron Arachne is my "forever project," as the article calls it. It's an endless creative exploration meant to delve into many, many different topics at the drop of a hat. It's not meant to be complete, or bug-free, or even useful. I had forgotten that.&lt;/p&gt;
&lt;p&gt;In the context of this revelation, I'm taking a look at what Iron Arachne is currently and where I'd like to take it. I definitely don't want to do another rewrite. However, I think I would like to start exploring more random concepts. To that end, I'm going to follow some of the advice from Scott and write a bunch of new issues in GitLab that are just ideas of things to try - small ones, medium ones, big ones, and pie-in-the-sky ones.&lt;/p&gt;
&lt;p&gt;I also will need to reinstate my weekly ritual of coding on Sunday mornings, but I think I'll broaden the scope of that a bit to be "work on Iron Arachne" instead of coding. That means anything that falls within that context is fair game - so, I could code, or I could do artwork, or read about geology, or write issues, or write a blog post, or anything else that fits the mold.&lt;/p&gt;
&lt;p&gt;Now that I'm getting this down in writing, I'm finally getting excited about Iron Arachne again. That's a tremendous sign that I'm on the right track.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Wed, 28 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/10/on-forever-projects/</guid></item><item><title>How free is the internet in 2020?</title><link>https://stop.zona-m.net/2020/10/how-free-is-the-internet-in-2020/</link><description>&lt;p&gt;Less than before. Don&amp;rsquo;t let the pandemic hide that.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 27 Oct 2020 20:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/how-free-is-the-internet-in-2020/</guid></item><item><title>Why We Will Never Have Enough Software Developers</title><link>https://whoisnnamdi.com/never-enough-developers/</link><description>Developers are dropping out of the profession in large numbers</description><author>Who is Nnamdi?</author><pubDate>Tue, 27 Oct 2020 19:55:02 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/never-enough-developers/</guid></item><item><title>Differences Between Camera Sensors</title><link>https://bastibe.de/2020-10-26-differences-between-cameras.html</link><description>&lt;h1&gt;get sRGB coordinates here: https://www.babelcolor.com/index_htm_files/RGB%20Coordinates%20of%20the%20Macbeth%20ColorChecker.pdf&lt;/h1&gt;
&lt;p&gt;Most cameras have the option to capture &lt;em&gt;raw&lt;/em&gt; images, i.e. un-processed image data right from the image sensor. In theory, these images are pure physical measurements of light, and should therefore be very comparable between cameras. But are they? To investigate, I took a &lt;em&gt;raw&lt;/em&gt; picture of &lt;a href="https://en.wikipedia.org/wiki/ColorChecker"&gt;a color target&lt;/a&gt; with each of my five cameras, and compared their output.&lt;/p&gt;
&lt;p&gt;Capturing accurate colors is a surprisingly intricate matter, as the color depends on the spectrum of the illumination, the reflective spectrum of the colored object, and the color filters in the camera. I normalized the illumination by taking pictures on an overcast day outside&lt;sup class="footnote-ref" id="fnref-1"&gt;&lt;a href="#fn-1"&gt;1&lt;/a&gt;&lt;/sup&gt;, and used a standard color target with 24 colored patches of a certified color.&lt;/p&gt;
&lt;p&gt;The resulting colored spectra are captured on the camera sensor by photon counters behind three color filters “red”, “green”, and “blue”&lt;sup class="footnote-ref" id="fnref-2"&gt;&lt;a href="#fn-2"&gt;2&lt;/a&gt;&lt;/sup&gt;, which differ from camera to camera in their spectral sensitivity. The recorded colors then get projected on a computer screen with another set of “red”, “green”, and “blue” LEDs of some different spectral makeup, or printed in three or more inks on paper. And this is then seen with eyes of yet another set of “red”, “green”, and “blue” retinal cells. Let's leave it at &lt;em&gt;color is complicated&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;At any rate, I took pictures at base ISO in &lt;em&gt;raw&lt;/em&gt;, white-balanced and exposed for the third grey patch, and adjusted in saturation on the red patch. Here are the colors on the color checker and the recorded colors of my cameras:&lt;/p&gt;
&lt;img src="/static/2020-10/Colorchecker.svg" style="width: 70%; padding-left: 15%; padding-top: 5px; padding-bottom: 10px;" /&gt;

&lt;p&gt;The image shows the 24 colored patches of the color target&lt;sup class="footnote-ref" id="fnref-3"&gt;&lt;a href="#fn-3"&gt;3&lt;/a&gt;&lt;/sup&gt;. Within each patch, five rectangles show the recorded color of (in reading order) the Pentax Q7, the Ricoh GR, the Panasonic LX100, the Fujifilm X-T2, and the Google Pixel 2.&lt;/p&gt;
&lt;p&gt;Due to my exposure and white balance calibration, the third grey patch is completely equalized and shows no difference between the cameras and the target. The “Light Skin” patch (second on the first row) is also very close to equal, which is an important sanity check for my measurement procedure, as skin tones are optimized by all cameras. Seeing that the skin color patch is one of the most similar hopefully indicates that I did not do anything gravely wrong.&lt;/p&gt;
&lt;p&gt;The last row shows greys, which are very similar across cameras (excluding the white patch for now). This indicates that RAW values indeed correspond to photon counts, with little additional processing. I have no idea why the white patch is off. Perhaps due to specular reflections on the white patch? Color is complicated.&lt;/p&gt;
&lt;p&gt;As for the other colors, the Panasonic LX100 (center) and the Fujifilm X-T2 (bottom left) seem to record somewhat more accurate colors than the other three cameras. The Pentax Q7 (top left) and Ricoh GR (top right) seem comparatively weak across the board. The Panasonic (center) is great in darker blues and reds and greens, but somewhat weaker in yellows and pastels. The Fujifilm (bottom left) is very good in almost all colors, with pastels somewhat weaker than darker colors. The Google Pixel 2 (bottom right) is better in reds and greens and yellows than in blues and oranges. Pastel colors in general seem weaker than darker colors, which might be due to the same process that affected the white patch as well.&lt;/p&gt;
&lt;p&gt;I think I learned something from this experiment: There are indeed color differences between cameras even when shooting RAW, but they are relatively minor. Whenever I see larger differences in my pictures, they are likely (easily correctible) white balance differences, and not sensor differences. When in doubt however, my Panasonic LX100 and Fujifilm X-T2 do capture more lifelike colors than my other cameras.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;&lt;p&gt;any kind of artificial light is comparatively terrible for color reproduction!&lt;a class="footnote" href="#fnref-1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn-2"&gt;&lt;p&gt;in quotes, because colors are three-channel information, and we're talking about single channels here.&lt;a class="footnote" href="#fnref-2"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn-3"&gt;&lt;p&gt;encoded as sRGB, which might or might not be displayed correctly on your screen, depending on your OS, your browser, your settings, your room's illumination, and your screen. Color is complicated.&lt;a class="footnote" href="#fnref-3"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>bastibe.de</author><pubDate>Tue, 27 Oct 2020 12:00:00 GMT</pubDate><guid isPermaLink="true">https://bastibe.de/2020-10-26-differences-between-cameras.html</guid></item><item><title>Download your podcasts</title><link>https://voussoir.net/writing/download_podcasts</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Download your podcasts&lt;/h1&gt;&lt;ol id="table_of_contents"&gt;Table of contents&lt;li&gt;&lt;a href="#introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#downloading"&gt;Downloading&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#tagging"&gt;Tagging&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#cutting_ads"&gt;Cutting ads&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#listen_enjoy"&gt;Listen &amp;amp; enjoy&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;a class="header_anchor_link" href="#introduction"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the past year or two, more and more podcasts have been moving to Spotify and pulling their material from their other outlets. This is because Spotify wants to pump up their subscriber counts and is offering cash incentives to podcasters for exclusivity. The only situation in which this can possibly be interpreted as a benefit for the listener is when the exclusivity deal literally saves the podcast from going bust, and even this has caveats. Any other messaging that depicts Spotify-exclusivity in a positive light is pure spin and marketing, as the deal invariably removes control and choice from the listener. You can ignore the "oh, but Spotify's not that bad" crowd, because that's not the point. The point is that &lt;em&gt;being corralled into Spotify&lt;/em&gt; is bad, and the same would apply to any other exclusive distribution point no matter how technically good it is.&lt;/p&gt;
&lt;p&gt;Not to mention, as with any other material on the Internet, every day that passes is a day your favorite show might disappear for any number of reasons. You should also download your favorite Youtube videos and forum threads, too, but let's save that for another article.&lt;/p&gt;
&lt;p&gt;Podcasts are often distributed as 128 kbps mp3 or thereabouts. At this bitrate, you can fit 100 hours of audio in 5.5 GiB. Just do it.&lt;/p&gt;
&lt;h2 id="downloading"&gt;Downloading&lt;a class="header_anchor_link" href="#downloading"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I am actually a bad ambassador for this kind of thing, because I like writing my own scrapers and downloaders, which most people won't want to do.&lt;/p&gt;
&lt;p&gt;Let's start here: the podcast culture has traditionally used RSS for publishing episodes. Until recently, I never had a use for RSS, but now I see it as an important open format in the fight to keep data out of walled gardens like Spotify.&lt;/p&gt;
&lt;p&gt;At this point, you can either search the Internet for "RSS podcast downloader" and find a pre-existing software solution to this problem, or you can continue reading and see how I do it. As you'll find, the nature of RSS does often require getting dirty and putting in some extra labor.&lt;/p&gt;
&lt;p&gt;With no background experience in RSS readers, I tried &lt;a href="https://quiterss.org/"&gt;QuiteRSS&lt;/a&gt; and have been happy with it. QuiteRSS uses SQLite to store the feeds and news items. With a tool like &lt;a href="https://github.com/sqlitebrowser/sqlitebrowser/releases"&gt;sqlitebrowser&lt;/a&gt;, or just the &lt;a href="https://www.sqlite.org/download.html"&gt;command line sqlite3&lt;/a&gt;, it's then trivial to get the &lt;code&gt;published&lt;/code&gt; date and &lt;code&gt;enclosure_url&lt;/code&gt; fields which I then throw into my own &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/threaded_dl.py"&gt;&lt;code&gt;threaded_dl.py&lt;/code&gt;&lt;/a&gt; by preparing a file that looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://example.com/episode1.mp3 Podcastname 2015-10-31.mp3
https://example.com/episode2.mp3 Podcastname 2016-12-25.mp3
https://example.com/episode3.mp3 Podcastname 2017-04-01.mp3
https://example.com/episode4.mp3 Podcastname 2018-05-05.mp3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and calling &lt;code&gt;threaded_dl links.txt 3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/quiterss_feeds_db1.png" title="QuiteRSS db containing feeds." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/quiterss_feeds_db2.png" title="QuiteRSS db sql query to isolate dates and urls." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/quiterss_feeds_db3.png" title="QuiteRSS db copying results of query." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/quiterss_feeds_db4.png" title="QuiteRSS db pasting results into text editor for further manipulation." /&gt;&lt;/p&gt;
&lt;p&gt;To be clear, I only do this for the initial download of the historical posts. After that, when new episodes are released, I just right-click &amp;amp; save file.&lt;/p&gt;
&lt;p&gt;However, you'll find that many or most RSS feeds don't contain the entire history of the show. Squarespace, for example, only publishes the 300 most recent items in an RSS feed. Why? Because that's the number &lt;a href="https://support.squarespace.com/hc/en-us/articles/205814338-Podcasting-with-Squarespace-overview#:~:text=Squarespace%20podcast%20feeds%20display%20up,episodes%20that%20Apple%20Podcasts%20supports."&gt;Apple uses&lt;/a&gt; and apparently it's easier to follow Apple's lead than to realize that RSS is an open format for a variety of consumers. I have seen other feeds that show only 10 items, which surely must be a result of poor configuration &lt;a class="footnote_link" href="#footnote_text_1" id="footnote_link_1" title="[1] Looks like the market has an opening for an &amp;quot;RSS rebroadcasting service&amp;quot; that archives feeds and gives clients the whole history every time."&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One thing you can try is searching the &lt;a href="https://web.archive.org/"&gt;Wayback machine&lt;/a&gt; for the RSS url. If you're lucky, it will have been scraped in the past often enough so as to contain the entire history, though perhaps in piecemeal. You could download the snapshots, combine them into a single xml file, serve it out of a &lt;a href="https://git.voussoir.net/voussoir/else/src/branch/master/SimpleServer"&gt;webserver&lt;/a&gt;, and temporarily point your RSS client at localhost so it ingests all those historical posts before pointing it back at the real url. Convoluted, perhaps, but I'd rather do this than inject the posts into the db myself. Then, you can pull the enclosures out of QuiteRSS's database (or from the xml file you just made).&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/wayback_archives.png" title="Finding archived RSS feeds on Wayback" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/wayback_crossreference.png" title="Cross-referencing the last item on the web feed (right) with more items on the wayback archive (left) to construct a single xml file with all items." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/wayback_timetravel1.png" title="Serving the xml file out of a local webserver and configuring QuiteRSS to pull the localhost url." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/wayback_timetravel2.png" title="QuiteRSS pulled the local xml file and now has 149 items instead of 100." /&gt;&lt;/p&gt;
&lt;p&gt;But, in the worst case scenario, you'll find that Wayback doesn't have archives of the feed you want. At this point I write a web scraper in Python to find all the episode dates and links, or I just hit the CTRL+C, CTRL+V gym for twenty minutes, copying each link from the website manually. You may also try &lt;a href="http://home.snafu.de/tilman/xenulink.html"&gt;Xenu's Link Sleuth&lt;/a&gt; or &lt;a href="https://www.httrack.com/"&gt;HTTrack&lt;/a&gt; to see if they can find all of the MP3 urls automatically. I figure it's an effort I'll only have to do once as long as RSS keeps getting new posts after that.&lt;/p&gt;
&lt;p&gt;If the podcaster has already taken the Faustian bargain, you can try using &lt;a href="https://spotifeed.timdorr.com/"&gt;spotifeed.timdorr.com&lt;/a&gt; to pull Spotify as RSS, but this will give very limited history and only serves to stem the bleeding.&lt;/p&gt;
&lt;p&gt;&lt;a class="footnote_text" href="#footnote_link_1" id="footnote_text_1"&gt;[1]&lt;/a&gt; Looks like the market has an opening for an "RSS rebroadcasting service" that archives feeds and gives clients the whole history every time.&lt;/p&gt;
&lt;h2 id="tagging"&gt;Tagging&lt;a class="header_anchor_link" href="#tagging"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some podcasters add metadata to their distribution files, others don't. Most don't. At least not to my tastes. I recommend &lt;a href="https://mp3tag.de/en/"&gt;MP3Tag&lt;/a&gt; for tagging and renaming the files.&lt;/p&gt;
&lt;p&gt;Tagging podcasts is a little different than tagging music. Firstly, podcasters sometimes release "bonus episodes" or "0.5" episodes, which cause track numbers to deviate from the episode number as listed in the title. Secondly, music files can usually be named &lt;code&gt;artist - album - track.mp3&lt;/code&gt; without much issue, but podcast titles are often much longer and contain unsafe characters like &lt;code&gt;:&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, etc. So, to keep things simple, I just use &lt;code&gt;podcastname - releasedate.mp3&lt;/code&gt; as the filename.&lt;/p&gt;
&lt;p&gt;If the mp3 files don't have the &lt;code&gt;ALBUM&lt;/code&gt; or &lt;code&gt;YEAR&lt;/code&gt; field set, you can use MP3Tag's "filename to tag" feature to fix that.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/filename_to_tag.png" title="filename to tag: album - year" /&gt;&lt;/p&gt;
&lt;p&gt;MP3Tag is great for batch renaming. In your MP3Tag actions, create a &lt;code&gt;Format value&lt;/code&gt; action with the parameters Field=&lt;code&gt;_FILENAME&lt;/code&gt;, Format string=&lt;code&gt;%album% - %year%&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/mp3tag_rename_action.png" title="MP3Tag rename action." /&gt;&lt;/p&gt;
&lt;p&gt;Clean up all the files' tags to your heart's content, then select them and run your rename action.&lt;/p&gt;
&lt;h2 id="cutting_ads"&gt;Cutting ads&lt;a class="header_anchor_link" href="#cutting_ads"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I don't listen to &lt;a href="/writing/advertixing"&gt;ads&lt;/a&gt;. I recommend &lt;a href="https://mpesch3.de/"&gt;mp3DirectCut&lt;/a&gt; for cutting them out. If you're going to listen to the podcasts on your PC anyway, you can kill two birds with one stone by listening to the entire podcast within mp3DC and cutting the ads as you go. If you just want to kill one bird at a time, you can skim through the file with the arrow keys and page up / page down. Most people speak differently when they read an ad, or record the ad in a separate take. You can hear these difference as you skim even when jumping 10-30 seconds at a time. Listen for differences in intonation, room noise, or long segments of a single speaker instead of the show's usual back-and-forth dialogue. You will get faster as you get familiar with the podcaster's ad spacing and speech habits.&lt;/p&gt;
&lt;p&gt;It is important to use a tool that does lossless copying, which means it doesn't re-encode the audio when saving the new file. If you use Audacity, for example, you are loading the mp3 into a wave in memory at the beginning, then encoding that wave back to mp3 at the end. Re-encoding will cause a slight loss in quality, though I admit it will not usually be noticeable. mp3DC copies the mp3 data directly. This comes with the limitation that you can only cut at frame boundaries, but that's ok because mp3 frames are usually &lt;a href="https://stackoverflow.com/a/12650386"&gt;~26ms&lt;/a&gt; long, unlike video formats where keyframes might be many seconds apart.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/download_podcasts/mp3dc_demo.png" title="Turning the clock back to 2006 with this expertly annotated MSPaint job demonstrating the key features of mp3dc." /&gt;&lt;/p&gt;
&lt;h2 id="listen_enjoy"&gt;Listen &amp;amp; enjoy&lt;a class="header_anchor_link" href="#listen_enjoy"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The final step is to rest easy in the knowledge that no one can take the show away from you at this point. You can take as much time as you need to listen through it, and it'll always be right where you left it. As it should be.&lt;/p&gt;
&lt;p&gt;If you do not have the tools or resources to perform these steps, I wouldn't mind doing it for you once or twice. Send me an email via writing@voussoir.net.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/download_podcasts/download_podcasts.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/3475cb0abf63172e6392487ffaf41755f71a18e3"&gt;&lt;time datetime="2023-09-18T21:01:09-07:00"&gt;2023-09-18&lt;/time&gt; Replace github links with git.voussoir.net.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/aa6f5dfae739d2b628a4916660fecc790aaaf856"&gt;&lt;time datetime="2022-03-15T18:00:09-07:00"&gt;2022-03-15&lt;/time&gt; Add advertixing.md.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/9cce9f9ef055a5e268a9b913871ff8d0473cf3eb"&gt;&lt;time datetime="2021-06-07T19:08:19-07:00"&gt;2021-06-07&lt;/time&gt; Move S3 images to my domain.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/e9529b73c644660c91a8f197e33de6aaffd785c1"&gt;&lt;time datetime="2020-12-08T15:35:21-08:00"&gt;2020-12-08&lt;/time&gt; Add links to Xenu, HTTrack; improve QuiteRSS db screenshots.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/6363e0f3ab2c56b5c97bacd6541e70c2fef412f7"&gt;&lt;time datetime="2020-10-27T01:57:05-07:00"&gt;2020-10-27&lt;/time&gt; Add download_podcasts.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Tue, 27 Oct 2020 10:57:05 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/download_podcasts</guid></item><item><title>Emacs: chaining org babel blocks</title><link>https://xenodium.com/emacs-chaining-org-babel-blocks</link><description>&lt;p&gt;Recently wanted to chain org babel blocks. That is, aggregate separate source blocks and execute as one combined block.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-chaining-org-babel-blocks/chain.gif" /&gt;&lt;/p&gt;
&lt;p&gt;I wanted the chaining primarily driven through header arguments as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-org"&gt;#+name: block-0
#+begin_src swift
  print(&amp;quot;hello 0&amp;quot;)
#+end_src

#+name: block-1
#+begin_src swift :include block-0
  print(&amp;quot;hello 1&amp;quot;)
#+end_src

#+RESULTS: block-1
: hello 0
: hello 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I didn't find the above syntax and behaviour supported out of the box (or didn't search hard enough?). Fortunately, this is our beloved and malleable editor, so we can always bend it our way! Wasn't quite sure how to go about it, so I looked at other babel packages for inspiration. &lt;a href="https://github.com/astahlman/ob-async"&gt;ob-async&lt;/a&gt; was great for that.&lt;/p&gt;
&lt;p&gt;Turns out, advicing &lt;em&gt;org-babel-execute-src-block&lt;/em&gt; did the job:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun adviced:org-babel-execute-src-block (&amp;amp;optional orig-fun arg info params)
  (let ((body (nth 1 info))
        (include (assoc :include (nth 2 info)))
        (named-blocks (org-element-map (org-element-parse-buffer)
                          'src-block (lambda (item)
                                       (when (org-element-property :name item)
                                         (cons (org-element-property :name item)
                                               item))))))
    (while include
      (unless (cdr include)
        (user-error &amp;quot;:include without value&amp;quot; (cdr include)))
      (unless (assoc (cdr include) named-blocks)
        (user-error &amp;quot;source block \&amp;quot;%s\&amp;quot; not found&amp;quot; (cdr include)))
      (setq body (concat (org-element-property :value (cdr (assoc (cdr include) named-blocks)))
                         body))
      (setf (nth 1 info) body)
      (setq include (assoc :include
                           (org-babel-parse-header-arguments
                            (org-element-property :parameters (cdr (assoc (cdr include) named-blocks)))))))
    (funcall orig-fun arg info params)))

(advice-add 'org-babel-execute-src-block :around 'adviced:org-babel-execute-src-block)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before I built my own support, I did find that &lt;a href="https://orgmode.org/manual/Noweb-Reference-Syntax.html"&gt;noweb&lt;/a&gt; got me most of what I needed, but required sprinkling blocks with placeholder references.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-chaining-org-babel-blocks/noweb.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Combining &lt;a href="https://orgmode.org/manual/Noweb-Reference-Syntax.html"&gt;:noweb&lt;/a&gt; and &lt;a href="https://org-babel.readthedocs.io/en/latest/header-args/#prologue"&gt;:prologue&lt;/a&gt; would have been a great match, if only prologue did expand the noweb reference. I'm sure there's an alternative I'm missing. Either way, it was fun to poke at babel blocks and build my own chaining support.&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Tue, 27 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-chaining-org-babel-blocks</guid></item><item><title>The X in MDX</title><link>https://youtu.be/xEu3t-KJVVg</link><description>— at NextJS Conf 2020</description><author>Rodrigo Pombo</author><pubDate>Tue, 27 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://youtu.be/xEu3t-KJVVg</guid></item><item><title>Youtube-dl git repo in ipfs</title><link>https://b.agilob.net/random/yt-dl-on-ipfs/</link><description>Following this simple tutorial I put youtube-dl on IPFS.
Git repo ends on commit 48c5663c5f7dd9ecc4720f7c1522627665197939.
You can see the git files using any gateway under hash QmQ8rwm3guU76oSsfQpo3rYfW91MXhmZ4jZLqKpHVTR4uE.
and clone ipfs repo using git command using
git clone https://ipfs.io/ipfs/QmQ8rwm3guU76oSsfQpo3rYfW91MXhmZ4jZLqKpHVTR4uE :)</description><author>Random Notes by agilob</author><pubDate>Tue, 27 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://b.agilob.net/random/yt-dl-on-ipfs/</guid></item><item><title>The Social Dilemma</title><link>https://lambdaland.org/posts/2020-10-27-social-dilemma/</link><description>&lt;p&gt;I just finished watching &lt;a class="link-external" href="https://www.thesocialdilemma.com/" rel="external"&gt;The Social Dilemma&lt;/a&gt;, and here’s my hot take: &lt;em&gt;The Social Dilemma&lt;/em&gt; is an emotive, accessible introduction to problems that, without exaggeration, pose an existential threat to life as we know it. If you can, watch it.&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Tue, 27 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-10-27-social-dilemma/</guid></item><item><title>Nextdoor is not messy. It's just too fast</title><link>https://stop.zona-m.net/2020/10/nextdoor-is-not-messy.-its-just-too-fast/</link><description>&lt;p&gt;It is. Trust me.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 27 Oct 2020 01:50:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/nextdoor-is-not-messy.-its-just-too-fast/</guid></item><item><title>TrueNAS Configuration and Maintenance</title><link>https://kevin.deldycke.com/2020/truenas-configuration</link><description>&lt;p&gt;
 A collection of personal notes on the setup, configuration and maintenance of a home-office TrueNAS&amp;nbsp;appliance.
&lt;/p&gt;



&lt;section id="hardware"&gt;
 &lt;h1&gt;
  🖥 Hardware
  &lt;a class="headerlink" href="#hardware" title="Link to this heading"&gt;&amp;nbsp;¶
  &lt;/a&gt;
 &lt;/h1&gt;
 &lt;p&gt;
  I dedicated a whole post on
  &lt;a class="reference external" href="https://kevin.deldycke.com/2020/nas-hardware"&gt;
   building the machine
  &lt;/a&gt;
  , in which you’ll get the detailed bill of material, cost breakdown and parts selection&amp;nbsp;process.
 &lt;/p&gt;
 &lt;section id="reset-bmc-password"&gt;
  &lt;h2&gt;
   Reset &lt;span class="caps"&gt;BMC&lt;/span&gt; password
   &lt;a class="headerlink" href="#reset-bmc-password" title="Link to this heading"&gt;&amp;nbsp;¶
   &lt;/a&gt;
  &lt;/h2&gt;
  &lt;p&gt;
   If you have one of …&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;</description><author>Kevin Deldycke</author><pubDate>Tue, 27 Oct 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://kevin.deldycke.com/2020/truenas-configuration</guid></item><item><title>Emotional Budgeting</title><link>http://evantravers.com/articles/2020/10/26/emotional-budgeting/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/10/budget.png" /&gt;&lt;/p&gt;&lt;p&gt;A wise steward budgets resources with limited quantities because humans tend to spend &lt;strong&gt;all&lt;/strong&gt; their resources on the immediate problem.&lt;/p&gt;
&lt;p&gt;Budgeting is twofold: an acknowledgement that a resource is finite and a plan predetermining priorities. When a decision arrives we can say yes to the best and no to what is lesser.&lt;/p&gt;
&lt;p&gt;I have been budgeting my money for about five years now. I've budgeted my time for three. Deep Work taught me that willpower or focus is a similarly limited resource&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I have come to realize that &lt;em&gt;emotional strength&lt;/em&gt; is a limited quantity as well. A long day of stressful interactions and decisions reduces my ability to delight in and engage with my family at the end of the day. In quarantimes, when I am working from home and living at work, the symptoms of emotional drain have been greater. Without the natural rhythms of hallway banter my experience with work can become a constant eight hour stream of possibly stressful interactions. Even on a &lt;em&gt;great&lt;/em&gt; day, the weight of potential problems can be enough to deplete my emotional energy. I leave my home office exhausted more often than I'd like to admit.&lt;/p&gt;
&lt;p&gt;I should take a moment to say: &amp;quot;emotional budgeting&amp;quot; is a phrase that I've been using in my head. There may be existing books and articles using a different name, or someone using this name for a differenct concept. I like the phrase because I believe in a stewardship model of resource management, and while I applaud aspects of the &amp;quot;self-care&amp;quot; movement, I find the phrasing and movement to be too self-focused for my faith.&lt;/p&gt;
&lt;p&gt;What I refer to as my &amp;quot;emotional energy&amp;quot; may be simply &amp;quot;empathy.&amp;quot; It is the limited resource that allows us to listen intently to others, to concern ourselves with how others think, and give us the power to place ourselves in their shoes. When you have a difficult conversation with someone about a point of conflict and you end up drained, lethargic… unwilling even to commit to light-weight, pleasant conversation… that's what I define as &amp;quot;low emotional energy.&amp;quot;&lt;/p&gt;
&lt;p&gt;To fight this drain I took the same approach as with any budgeting problem: I started by tracking my &amp;quot;expenses&amp;quot; and &amp;quot;income,&amp;quot; I predetermined my priorities, and I continue to adjust and learn.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#tracking" id="tracking"&gt;&lt;/a&gt;Tracking&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#journaling" id="journaling"&gt;&lt;/a&gt;Journaling&lt;/h3&gt;
&lt;p&gt;To track emotional energy I employed a &lt;em&gt;simple&lt;/em&gt; journaling and review practice. Just noting in a journal or text-file that &amp;quot;difficult conversation about Project Y, feeling tired&amp;quot; is sufficient to teach us what topics drain us.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-4" id="fnref-4"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I still practice bullet journaling. As I go through the day I list out meetings, projects, and events. At the end of the day… I'll typically prepend a smiley based on how different notes made me feel.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;3&lt;/a&gt;&lt;/sup&gt; One trend I've noticed is that whatever mood I start the day in is typically the mood that will define &lt;strong&gt;the entire day&lt;/strong&gt;. This is a &lt;em&gt;powerful&lt;/em&gt; insight… and really speaks to the importance of starting my day in scripture and prayer &lt;em&gt;before&lt;/em&gt; I grab my phone. If you start tracking your mood with an open mind you may discover similar patterns. There are many similar tools, and many wiser folks with counsel on this.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#budget-busters" id="budget-busters"&gt;&lt;/a&gt;Budget Busters&lt;/h3&gt;
&lt;p&gt;Returning to the metaphor of financial budgeting: When my wife and I started budgeting, we programmed into our budget all the categories and recurring transactions we could think of. We were surprised by &lt;em&gt;all the things we forgot to consider&lt;/em&gt;… tires wear out, registering our cars, that wedding gift, etc. Over time, we learned to count on all the &amp;quot;budget busters&amp;quot; and make allowances.&lt;/p&gt;
&lt;p&gt;Two of my emotional &amp;quot;budget busters&amp;quot;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Career Review season&lt;/em&gt;. Whether the reviews are trending good or bad &amp;quot;review season&amp;quot; still is a vulnerable time with the potential for stressful conversations. So I've learned to build into my schedule more &amp;quot;supply&amp;quot; of emotional energy when review season comes around, and to forgive myself for being a little drained.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Social Media &amp;quot;doom-scrolling.&amp;quot;&lt;/em&gt; It doesn't matter how good the day is, if I drift into the infinity pool of sadness that is social media around election season… I'll lose a lot of energy. I'm sure I'm not the only one.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;a class="anchor" href="#predetermine-your-priorities" id="predetermine-your-priorities"&gt;&lt;/a&gt;Predetermine Your Priorities&lt;/h2&gt;
&lt;p&gt;Once I was tracking my energy I realized I was losing more energy in my workday than I thought. &lt;strong&gt;I'm going to assume that most people expend the most emotional energy into what is immediately in front of them… which is work&lt;/strong&gt;. I therefore assume most folks would need to re-prioritize towards their health, friends, and family.&lt;/p&gt;
&lt;p&gt;You may need to take some time with your tracking information and determine what area of your life is lacking the emotional attention that it deserves. If you have a trusted friend or family member they can help you determine which relationships or aspects of your life need more attention.&lt;/p&gt;
&lt;p&gt;There are different ways to represent this new priority, but simply knowing it is sufficient as we move into the next phase of adjusting and learning.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#adjusting-and-learning" id="adjusting-and-learning"&gt;&lt;/a&gt;Adjusting and Learning&lt;/h2&gt;
&lt;p&gt;Having learned a little bit about myself through tracking my emotional energy and how it's affected by &amp;quot;budget busters,&amp;quot; and having rekindled desire to give my little family the best of my emotional energy&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-5" id="fnref-5"&gt;4&lt;/a&gt;&lt;/sup&gt;, I started devising strategies.&lt;/p&gt;
&lt;p&gt;The strategies that have helped me can be largely grouped into two categories: &amp;quot;refilling the tank&amp;quot; to give me more energy, and &amp;quot;limiting the leaks&amp;quot; to help me maintain energy.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-3" id="fnref-3"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#refilling-the-tank" id="refilling-the-tank"&gt;&lt;/a&gt;Refilling the Tank&lt;/h3&gt;
&lt;p&gt;Through my journaling, I've learned that if I have certain meetings back to back (especially in the morning!), I'll be pretty drained by lunch and have very little energy going into the evening. I'm still able to work… I just have less &amp;quot;words&amp;quot; to share with my family. 😓 Therefore I've started intentionally planning to refill the tank.&lt;/p&gt;
&lt;p&gt;Here are some examples:&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#gratitude" id="gratitude"&gt;&lt;/a&gt;Gratitude&lt;/h4&gt;
&lt;p&gt;A very important strategy for staying positive throughout the day is logging any and all positive interactions for which I am grateful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a colleague shares some encouraging words.&lt;/li&gt;
&lt;li&gt;my daughter brings me a crayon-scrawled gift.&lt;/li&gt;
&lt;li&gt;quiet time is particularly fruitful.&lt;/li&gt;
&lt;li&gt;lunch is delicious.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these are &lt;em&gt;great&lt;/em&gt; things to remember! At the end of the day, I'm looking into the next day with more positivity if the log of the previous day is filled with blessings… otherwise I tend to remember only the bad. This is a high-value activity that &lt;em&gt;also&lt;/em&gt; lines up with the need to track your emotional state, so definitely try this.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#rest-and-play" id="rest-and-play"&gt;&lt;/a&gt;Rest and Play&lt;/h4&gt;
&lt;p&gt;At the office I'd automatically refill the tank by visiting with colleagues, playing ping pong, taking walks. Perversely, while working at home I feel guilty enjoying the &lt;em&gt;same&lt;/em&gt; activities! Intentionally giving myself permission to leave my desk for a restful activity has been critical to having a balanced day with emotional energy left at the end.&lt;/p&gt;
&lt;p&gt;Being on &amp;quot;work premises&amp;quot; allowed me to embrace restful pauses in the workday while not feeling like I was &amp;quot;abandoning my post.&amp;quot; Leaving my desk at home feels like treachery? I don't think this thought pattern is healthy, and I'm trying to fight it. Worse still it affects the way I treat my &amp;quot;coworkers&amp;quot; at home. At the office I happily invest in relationships because I am &amp;quot;at work.&amp;quot; If a colleague needs me to help them move a desk I happily drop what I'm doing… however at home I feel guilty for leaving my keyboard to help my wife move a dresser! It's irrational.&lt;/p&gt;
&lt;p&gt;My ultimate contribution to work is focused effort resulting in positive progress… not keeping my butt in seat for the whole day. If I allow myself to spend time on the most important people in my life, (i.e. step away to have a dance-party with my daughter for fifteen minutes) I'll wind up with more energy to expend on work &lt;em&gt;and&lt;/em&gt; family.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#intentional-conversation" id="intentional-conversation"&gt;&lt;/a&gt;Intentional Conversation&lt;/h4&gt;
&lt;p&gt;In a remote work situation there is a lot of &lt;em&gt;responding&lt;/em&gt; to task-based communication: meetings, email, chat … but not much opportunity for informal visiting. Without the intermittent chit-chat colleague relationships can warp into viewing people as a list of their demands. We forget to check on other people instead of the projects they owe us.&lt;/p&gt;
&lt;p&gt;I've found intentionally engaging in &amp;quot;just visit&amp;quot; time to be a great reminder of why I like working with such nice and interesting folks. It relieves some of the emotional drain by rekindling friendships. I no longer just dread your list of demands… I want to continue our conversations and see how you are doing.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#limit-the-draining-interactions" id="limit-the-draining-interactions"&gt;&lt;/a&gt;Limit the Draining Interactions&lt;/h3&gt;
&lt;p&gt;This strategy is a &lt;em&gt;little&lt;/em&gt; harder. Depending on your role at work you may not have much control over your schedule.&lt;/p&gt;
&lt;p&gt;Thanks to journaling I have learned to predict if a day could be an emotional &amp;quot;budget buster.&amp;quot; If I have any control of my schedule, I'll try to insert some rest time or use one of the other techniques above to recover.&lt;/p&gt;
&lt;p&gt;A simple tactic: I try schedule date night on a &lt;em&gt;different&lt;/em&gt; day than the &amp;quot;heavy&amp;quot; day. It's just wise: if I'm going to prioritize listening and loving on my wife I should choose to select an evening where I'll have as much as possible to give.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#intentional-practice" id="intentional-practice"&gt;&lt;/a&gt;Intentional Practice&lt;/h3&gt;
&lt;p&gt;While I'm honestly not sure how to do this perfectly… I have been attempting to deliberately practice this skill and get better at it.&lt;/p&gt;
&lt;p&gt;When I realize that I've had a &amp;quot;draining&amp;quot; day, this is a great opportunity to practice my listening and not default to my selfish relaxation habits. As a christian, the command to love on my wife is not relaxed simply because I had a difficult day at work. 😝 One mini-habit that has helped me is to quickly and quietly set an intention for the next interaction or meeting: how do I want the next person to perceive me? I choose my demeanor and consider how I can serve that person. It's been helpful to me and rescued me from defaulting to whatever my tired face depicts.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is all something I'm still thinking about and working on… so I'd appreciate any thoughts you have about it. I highly doubt that this is a new idea… there are probably whole books and genres dedicated to this.&lt;/p&gt;
&lt;p&gt;If you have any thoughts or research, &lt;a href="/contact"&gt;I'd love to hear about it&lt;/a&gt;.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;Cal Newport. &lt;em&gt;Deep Work&lt;/em&gt;. Grand Central Publishing, 2016. A large part of being an effective worker is limiting the distracting environmental leaks that reduce my daily supply of willpower, and spending it first on the work that most deserves my best focus. Over the past year I've sought to increase my supply of focus by deliberate practice and decrease the amount of distraction. &lt;a href="/articles/2019/02/09/review-deep-work-by-cal-newport/"&gt;My full review from 2019&lt;/a&gt;. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-4"&gt;
&lt;p&gt;To identify distractions from focus, Cal Newport recommended simply noting the sources of distraction on a sticky note, forgiving ourselves, and trying again. Very similar thing. &lt;a class="footnote-backref" href="#fnref-4"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;I actually have several systems for tracking my emotional energy both on a daily, weekly, and monthly level… but start &lt;em&gt;small&lt;/em&gt; and learn from yourself. Everyone is different. &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-5"&gt;
&lt;p&gt;I'm going to focus on my particular journey of trying to refocus on my family in a stressful work season, but pretty much any self-care advice could apply here as long as it aligns with your priorities. &lt;a class="footnote-backref" href="#fnref-5"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-3"&gt;
&lt;p&gt;You could basically use the same categories that Shawn Blanc uses for margin: increasing ability and decreasing commitment. It's same thing. &lt;a class="footnote-backref" href="#fnref-3"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Mon, 26 Oct 2020 23:28:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/10/26/emotional-budgeting/</guid></item><item><title>Found-Money Startups</title><link>https://www.swyx.io/found-money</link><description>'I will find free money for you' is one of my favorite business models. Here's a quick definition of Found-Money Startups and a short list I've been keeping.</description><author>swyx's site RSS Feed</author><pubDate>Mon, 26 Oct 2020 17:02:59 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/found-money</guid></item><item><title>How complex is modern web development</title><link>https://omarabid.com/modern-web-dev/</link><description>Visualizing the complexity of modern web development</description><author>Omar Abid - Personal Blog</author><pubDate>Mon, 26 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://omarabid.com/modern-web-dev/</guid></item><item><title>Waking Up: A Guide to Spirituality Without Religion</title><link>https://apurva-shukla.me/bookshelf/waking-up/</link><description>⭐ ⭐ ⭐ ⭐ A great introduction to spirituality and meditation for a Western audience, best suited towards those who have been conditioned to…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Sun, 25 Oct 2020 09:00:00 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/bookshelf/waking-up/</guid></item><item><title>Migrating Data When You Never Erase History</title><link>https://jorin.me/migrating-data-when-you-never-erase-history/</link><description>Let's explore the considerations necessary when evolving temporal data over time.</description><author>jorin.me</author><pubDate>Sun, 25 Oct 2020 08:00:00 GMT</pubDate><guid isPermaLink="true">https://jorin.me/migrating-data-when-you-never-erase-history/</guid></item><item><title>Emacs: quote wrap all in region</title><link>https://xenodium.com/emacs-quote-wrap-all-in-region</link><description>&lt;p&gt;As I find myself moving more shell commands into Emacs interactive commands to &lt;a href="http://xenodium.com/emacs-create-a-swift-packageproject/"&gt;create a Swift package/project&lt;/a&gt;, &lt;a href="http://xenodium.com/enrich-your-dired-batching-toolbox/"&gt;enrich dired's featureset&lt;/a&gt;, or &lt;a href="http://xenodium.com/emacs-searchplay-music-macos/"&gt;search/play Music (macOS)&lt;/a&gt;, I often need to take a single space-separated string, make an elisp list of strings, and feed it to functions like &lt;em&gt;process-lines&lt;/em&gt;. No biggie, but I thought it'd be a fun little function to write: take the region and wrap all items in quotes. As a bonus, made it toggable.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-quote-wrap-all-in-region/wrap-toggle-region.gif" /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun ar/toggle-quote-wrap-all-in-region (beg end)
  &amp;quot;Toggle wrapping all items in region with double quotes.&amp;quot;
  (interactive (list (mark) (point)))
  (unless (region-active-p)
    (user-error &amp;quot;no region to wrap&amp;quot;))
  (let ((deactivate-mark nil)
        (replacement (string-join
                      (mapcar (lambda (item)
                                (if (string-match-p &amp;quot;^\&amp;quot;.*\&amp;quot;$&amp;quot; item)
                                    (string-trim item &amp;quot;\&amp;quot;&amp;quot; &amp;quot;\&amp;quot;&amp;quot;)
                                  (format &amp;quot;\&amp;quot;%s\&amp;quot;&amp;quot; item)))
                              (split-string (buffer-substring beg end)))
                      &amp;quot; &amp;quot;)))
    (delete-region beg end)
    (insert replacement)))
&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 25 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-quote-wrap-all-in-region</guid></item><item><title>Communication with Blender via Python RPC</title><link>https://ciesie.com/post/blender_python_rpc/</link><description>&lt;p&gt;My current 3D graphics setup revolves around &lt;em&gt;Blender&lt;/em&gt;, &lt;em&gt;ZBrush&lt;/em&gt; and, less often, &lt;em&gt;Marmoset Toolbag 3&lt;/em&gt;.
Transferring the meshes between &lt;em&gt;ZBrush&lt;/em&gt; and &lt;em&gt;Blender&lt;/em&gt; is the constant dance of exporting and
importing (yes, I know about &lt;em&gt;GoB&lt;/em&gt; but it&amp;rsquo;s not good enough for me). I strongly dislike this
back and forth. I feel it adds a lot of friction, throws me off and wastes a lot of time.
That makes me experiment with inter process communication. This is one of those experiments.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Sun, 25 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/blender_python_rpc/</guid></item><item><title>Messages from afar</title><link>http://spirals.blog/articles/messages-from-afar/</link><description>&lt;p&gt;&lt;em&gt;Herein lies a collection of poems that came to me one evening. I do not claim to
have written them, more that I was fortunate enough for them to pass through me.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;May you reflect on these as I did when they arose.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Teacher on a sinking ship&lt;/h2&gt;
&lt;p&gt;Surrender.&lt;br /&gt;
Surrender to the crashing waves.&lt;br /&gt;
And let each breath be a prayer.&lt;br /&gt;
Breathe in this world, and breathe out god.&lt;br /&gt;
Let go!&lt;br /&gt;
Let in the darkness,&lt;br /&gt;
Let out the light!&lt;br /&gt;
Our fragile minds delight,&lt;br /&gt;
For that which is, on this good night.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Who are you?&lt;/h2&gt;
&lt;p&gt;I am the teacher that is learning,&lt;br /&gt;
The constructor of your destruction,&lt;br /&gt;
And the seed in your womb.&lt;br /&gt;
I am the silence in the crowd,&lt;br /&gt;
And the voice that grows ever softer as you wander into this true world.&lt;br /&gt;
Are you listening?&lt;br /&gt;
My name cannot be spoken.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;From whence it came&lt;/h2&gt;
&lt;p&gt;Give in to the endless river that flows within us all.&lt;br /&gt;
Drink from its sweet waters, and sail!&lt;br /&gt;
Fear not of destination,&lt;br /&gt;
Or biting hesitation,&lt;br /&gt;
For all rivers travel rightly to the source.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 25 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/messages-from-afar/</guid></item><item><title>Standard ML in 2020</title><link>http://notes.eatonphil.com/standard-ml-in-2020.html</link><description>&lt;p&gt;Incredibly, Standard ML implementations are still actively
developed. &lt;a href="http://mlton.org/"&gt;MLton&lt;/a&gt;, &lt;a href="https://polyml.org"&gt;Poly/ML&lt;/a&gt;,
&lt;a href="https://elsman.com/mlkit/"&gt;MLKit&lt;/a&gt;,
&lt;a href="https://www.pllab.riec.tohoku.ac.jp/smlsharp/"&gt;SML#&lt;/a&gt; and
&lt;a href="http://smlnj-gforge.cs.uchicago.edu/scm/viewvc.php/?root=smlnj"&gt;SML/NJ&lt;/a&gt;
are the most prominent. Discussion on the future direction of Standard
ML &lt;a href="https://github.com/SMLFamily/Successor-ML/issues"&gt;remains healthy as
well&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And somehow OCaml's lesser known cousin still beats out OCaml for
multicore threading support (in Poly/ML).&lt;/p&gt;
&lt;p&gt;While MLton hasn't merged with
&lt;a href="https://github.com/kayceesrk/multiMLton"&gt;MultiMLton&lt;/a&gt; or
&lt;a href="https://github.com/UBMLtonGroup/RTMLton"&gt;RTMLton&lt;/a&gt; to support
multicore, a &lt;a href="https://github.com/mpllang/mpl"&gt;new fork of MLton with
parallelism&lt;/a&gt; is pretty far along and
in active development at CMU.&lt;/p&gt;
&lt;p class="note"&gt;
  A commentor shared
  &lt;a href="https://github.com/ManticoreProject/manticore"&gt;Manticore&lt;/a&gt;,
  another implementation with parallelism support in active
  development at UChicago.
&lt;/p&gt;&lt;p&gt;Furthermore, the last few years have welcomed some entirely new
implementations. &lt;a href="https://github.com/KeenS/webml"&gt;WebML&lt;/a&gt;, by a
prominent open source hacker, is written in Rust and compiles Standard
ML to WebAssembly. &lt;a href="https://sosml.org/"&gt;SOSML&lt;/a&gt; is an interpreter
written in TypeScript by former students of Saarland University. It
features &lt;a href="https://sosml.org/editor"&gt;a nifty online
IDE&lt;/a&gt;.&lt;/p&gt;
&lt;p class="note"&gt;
  A commenter
  shared &lt;a href="https://github.com/SomewhatML/sml-compiler"&gt;SomewhatML&lt;/a&gt;,
  an actively developing compiler for Standard ML written in Rust.
&lt;/p&gt;&lt;p&gt;There have also been some new experimental spins on Standard ML in
the last few years. &lt;a href="https://github.com/julianhyde/morel"&gt;Morel&lt;/a&gt; is an
interpreter with some nice syntax extensions written in Java by the
author of Apache Calcite. And &lt;a href="https://github.com/elpinal/bright-ml"&gt;Bright
ML&lt;/a&gt; is a spin on Standard ML and
OCaml written in Standard ML (and using the abandoned &lt;a href="https://mosml.org/"&gt;Moscow
ML&lt;/a&gt; compiler of all implementations).&lt;/p&gt;
&lt;p&gt;So if you're looking for an easy intro to the ML family of languages,
I still recommend the simplicity and performance of Standard ML and
its small but definitely, surprisingly, not dead community. :)&lt;/p&gt;
&lt;p&gt;Additional resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://smlfamily.github.io/"&gt;SML Family Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://smlfamily.github.io/Basis/index.html"&gt;SML Standard Library (Basis Library) Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reddit.com/r/sml"&gt;/r/sml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Are you using Standard ML? &lt;a href="mailto:me@eatonphil.com"&gt;Let me know how/why!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Standard ML implementations are still in active development! There have even been some interesting new implementations pop up in the last few years.&lt;a href="https://t.co/6kOcMKVfQa"&gt;https://t.co/6kOcMKVfQa&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1320487302418845696?ref_src=twsrc%5Etfw"&gt;October 25, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 25 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/standard-ml-in-2020.html</guid></item><item><title>The story of udemy-dl</title><link>https://gaganpreet.in/posts/udemy-dl-story/</link><description>&lt;p&gt;The recent takedown of the &lt;a href="https://github.com/github/dmca/blob/master/2020/10/2020-10-23-RIAA.md" rel="noreferrer" target="_blank"&gt;youtube-dl&lt;/a&gt; project resurfaced memories of a similar project, udemy-dl, that I worked on years ago. I also had to abandon the project due to a DMCA notice. In light of what happened to youtube-dl this felt like the right time to write about it.&lt;/p&gt;
&lt;h2 class="relative group" id="beginnings"&gt;Beginnings &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#beginnings"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;Back in 2013 when I was starting off as a software consultant, I landed a project to build a desktop GUI application. I found a Udemy course for Python GUI development using Qt. After I started the course I ran into an obstacle. My internet was awful. It was slow (4 Mb/s, if I remember correctly) and disconnected frequently making streaming videos a painful experience.&lt;/p&gt;</description><author>Gaganpreet Arora</author><pubDate>Sun, 25 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://gaganpreet.in/posts/udemy-dl-story/</guid></item><item><title>Culture wars:for minorities, but still relevant</title><link>https://stop.zona-m.net/2020/10/culture-warsfor-minorities-but-still-relevant/</link><description>&lt;p&gt;Point is: do you know WHY they are relevant?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sun, 25 Oct 2020 02:54:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/culture-warsfor-minorities-but-still-relevant/</guid></item><item><title>A Practical Guide to Gaussian Mixture Models</title><link>https://blog.lukesalamone.com/posts/gmm-practical-guide/</link><description>&lt;code&gt;

&lt;p&gt;Are you studying machine learning and want to know more about Gaussian Mixture Models? You&amp;rsquo;ve come to the right place. I have found other online resources to be difficult to approach and/or lacking crucial details. Here I will try to explain GMMs in plain language.&lt;/p&gt;</description><author>Luke Salamone's Blog</author><pubDate>Sun, 25 Oct 2020 02:10:29 GMT</pubDate><guid isPermaLink="true">https://blog.lukesalamone.com/posts/gmm-practical-guide/</guid></item><item><title>Managing Python Environments</title><link>https://blog.lukesalamone.com/posts/managing-python-environments/</link><description>&lt;p&gt;Need to switch between python versions often? Use &lt;a href="https://github.com/pyenv/pyenv"&gt;&lt;code&gt;pyenv&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="installing-pyenv"&gt;Installing pyenv&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;# install pyenv
curl https://pyenv.run | bash

# check pyenv install location
which pyenv
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="install-another-python-version"&gt;Install another python version&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;# see a list of available python versions
pyenv install --list

# check installed python versions
pyenv versions

# installs python 3.7.5
pyenv install 3.7.5
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="switch-python-versions"&gt;Switch python versions&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;# use python 3.7.5 everywhere on your machine
pyenv global 3.7.5

# use python 3.7.5 in current directory
pyenv local 3.7.5

# use python 3.7.5 in current shell session
pyenv shell 3.7.5
&lt;/code&gt;&lt;/pre&gt;</description><author>Luke Salamone's Blog</author><pubDate>Sun, 25 Oct 2020 01:45:41 GMT</pubDate><guid isPermaLink="true">https://blog.lukesalamone.com/posts/managing-python-environments/</guid></item><item><title>How much specification does a developer need?</title><link>https://lucasfcosta.com/blog/specification-and-rest-apis/</link><description>Specifications work in two ways: they inform developers what needs to be built, and they constrain the problem space so that tasks become approachable.

Without clear specifications, developers may b...</description><author>Lucas F. Costa - Blog</author><pubDate>Sat, 24 Oct 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://lucasfcosta.com/blog/specification-and-rest-apis/</guid></item><item><title>Disposability - the Missing ility</title><link>https://blog.herlein.com/post/disposability/</link><description>&lt;p&gt;You will get the most bang for the buck from cloud by destroying it.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 24 Oct 2020 11:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/disposability/</guid></item><item><title>Unsubscribe Me: How to Disconnect from Internet Chaos</title><link>https://www.mikekasberg.com/blog/2020/10/23/unsubscribe-me.html</link><description>&lt;p&gt;&lt;a href="https://www.thesocialdilemma.com/"&gt;The Social Dilemma&lt;/a&gt; came out about a month
ago and got a lot of people thinking about the influence the internet and social
media have on their daily lives. I’m a programmer, and I’ve worked for an
internet advertising company, so none of this was new information to me. But for
a lot of the American public, watching The Social Dilemma was an eye-opening
experience into the ways that internet companies try to track and manipulate
people. Many of my friends used words like “unsettling” and “eerie” to describe
how they felt after seeing the film, but most of them also weren’t really sure
what to do about it. They weren’t sure how to make positive changes in their own
lives.&lt;/p&gt;

&lt;p&gt;So in this blog post, I want to explore some simple changes that I’ve made, and
that you might think about making too. I’ve been doing some of these things for
years and I’ve started some much more recently, but with these issues at the
front of my mind recently, and I think I have a reasonable approach to at least
heading in the right direction. The Social Dilemma website provides its own
&lt;a href="https://www.thesocialdilemma.com/take-action/"&gt;Take Action&lt;/a&gt; page, and most of
the advice there isn’t bad as a starting point. Most of my own suggestions are
minimally invasive and relatively simple. I haven’t completely stopped using
social media, and I wouldn’t necessarily recommend that as a solution, unless
you want to of course. I think it’s important to be pragmatic about what you can
do in a way that still allows you to maximise the personal value you get from
online services.&lt;/p&gt;

&lt;h2 id="your-time-is-valuable-to-companies"&gt;Your Time is Valuable to Companies&lt;/h2&gt;

&lt;p&gt;When people ask me about the movie, I always say that I think it’s a really
well-done visualization of the competition for your time. Companies want your
attention because your attention is valuable. This isn’t new. In the 80s and
90s, you saw ads on televisions, billboards, newspapers, and magazines.
Companies want you to notice them so they can sell you a product. And for the
most part, people have been pretty happy to make that trade. Who among us
doesn’t get excited for a 20% off coupon at your favorite store?&lt;/p&gt;

&lt;p&gt;In addition to straight-up ads, your time is valuable to companies in other
ways. Have you ever used a free app that didn’t have ads? Instagram &lt;a href="https://www.thesocialdilemma.com/take-action/"&gt;didn’t have
ads&lt;/a&gt; before late 2013, for
example. So why did Instagram care about your time if they weren’t showing you
ads? Your time is valuable to companies even if they’re not directly advertising
to you. Instagram is valuable as a company, in part, because of the size of its
user base. Apps with a big user base are valuable because they can monetize that
user base in a variety of different ways – from showing ads to selling data or
getting you hooked on a service they’ll charge for.&lt;/p&gt;

&lt;h2 id="the-competition-for-your-time"&gt;The Competition for Your Time&lt;/h2&gt;

&lt;p&gt;So apps want your time and they’re willing to compete for it. But they’re not
the only thing that’s competing for your time. Think about all your interactions
with media in a typical day. Maybe you listen to a podcast in the morning or on
the way to work. Does the podcast have ads? What about the app you use to play
it? Early in the workday, you notice a few notifications from your favorite
social apps. A couple likes, maybe a comment. Also, a notification from one of
your restaurant apps that they’re running a promotion today. Later, your phone
rings. It’s a spam call. You also notice a couple spam text messages that you
delete. In the afternoon, you check your email. Out of all the unread emails in
your inbox, you delete about half without reading them. When you get home, you
turn on your Fire TV where you see ads for a bunch of TV shows or movies. Then
you open the Netflix app where they’re promoting today’s top new shows. Everyone
is competing for your attention all the time.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Unwanted app notifications" src="https://www.mikekasberg.com/images/unsubscribe-me/notifications.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;Ads aren’t new, but the intensity of the competition for your attention and time
is higher than it’s ever been before. It’s in companies’ interest to have as
much of your attention as they can, but it’s in &lt;em&gt;your&lt;/em&gt; interest to give them the
minimal amount of attention necessary to get the value you want from them.
Companies are ruthless and aggressive in their pursuit of your attention, and
they’ll win the battle if you don’t put in any effort. Fortunately, there are
some low effort solutions that can produce very beneficial results, and my
approach is focused on this.&lt;/p&gt;

&lt;h2 id="optimize-your-digital-life"&gt;Optimize Your Digital Life&lt;/h2&gt;

&lt;h3 id="email"&gt;Email&lt;/h3&gt;

&lt;p&gt;Companies love email. Sending emails for marketing purposes is a billion-dollar
industry. For anyone who wants to promote something to you, email is a way for
them to get your attention. Your email address itself is valuable to many
companies because it allows them to (possibly) show you ads when they otherwise
wouldn’t be able to show something to you. (This is why companies will do things
like giveaways in exchange for your email address.) They will hire marketing
professionals whose job is to write a clickbait subject line to get you to open
the email so they can show you their ad. And they will track when you open the
email so they know if it’s working. (Images are used to track views, which is
one reason Gmail blocks images from unknown senders by default.) Unfortunately,
spam is a hard problem to solve, and there isn’t a perfect solution. But there
are some steps you can consider that might help reduce the way email intrudes
into your life.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Unsubscribe from anything you don’t really need. If you’re not sure, it’s
probably best to unsubscribe. You don’t really need to be bothered by your
college alumni newsletter, and you don’t really need to be bothered by that
mailing list you signed up for 2 years ago. In fact, you probably don’t need
any sort of regular communication except perhaps from an organization you
actually interact with on a very regular basis.&lt;/li&gt;
  &lt;li&gt;Try to avoid giving out your email address. It’s really not worth it for
whatever one-time promotion you’re getting. Or perhaps use a second email just
for spam.&lt;/li&gt;
  &lt;li&gt;Turn off &lt;strong&gt;all&lt;/strong&gt; your email notifications. Email is asynchronous
communication. It should not ever send you a notification to interrupt
whatever you were doing. Not on your phone, not on your computer. Check your
email on your own schedule at your leisure.&lt;/li&gt;
  &lt;li&gt;Keep an eye out for better email services. &lt;a href="https://hey.com/"&gt;Hey&lt;/a&gt; is trying
to make email better and they have some interesting solutions to the spam
problem. Maybe they will help, or maybe the industry as a whole will come up
with some new solutions based on their ideas. We can be hopeful!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="social-media"&gt;Social Media&lt;/h3&gt;

&lt;p&gt;Like email, social media is another place companies fight for your attention.
You want to log on to Facebook to see your friends pictures, companies want to
show you their ads instead. Some of this is obvious – like an advertisement in
your news feed. Sometimes, it’s less obvious – like an athlete you follow
posting a photo with a big logo in it or a band you like posting about a show in
a far-away city. Whatever the case, it’s likely that you’re not getting the most
value from whatever social media platform you’re trying to use.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Unfollow things you don’t want to see. You don’t necessarily have to
“unfriend” someone to “unfollow” them (depending on the platform). But if
you’re following things you’re not interested in (whether it’s people, movies,
companies, or brands), you’re just giving away space in your news feed that
doesn’t even count as an ad.&lt;/li&gt;
  &lt;li&gt;Like email, disable &lt;strong&gt;all&lt;/strong&gt; notifications. For 99% of the people in the world,
the ideal way to use social media is on your own schedule, like email. You
don’t need to be notified on your phone or computer when a friend posts or even
replies to a comment. It will be there in your feed when you decide you want to
look at it.&lt;/li&gt;
  &lt;li&gt;Consider using &lt;a href="https://www.mozilla.org/en-US/firefox/facebookcontainer/"&gt;Facebook
Container&lt;/a&gt; for
Firefox. It prevents Facebook from tracking your activity across many
non-Facebook websites.&lt;/li&gt;
  &lt;li&gt;Be aware of the ways you might be targeted by advertisers. When you share
information with Facebook (likes, interests, your profile page), they can use
that information to show you specific ads. This isn’t necessarily the worst
thing in the world, but it’s good to be aware that they’re using the info you
give them to do this.&lt;/li&gt;
  &lt;li&gt;Consider ditching social media completely. Do you really need to use Facebook
and Instagram, or can you just email your friends some pictures from your last
trip instead?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="other-apps"&gt;Other Apps&lt;/h3&gt;

&lt;p&gt;Apps are the new email. Shortly after email was born, companies began figuring
out how to use it to advertise. Now, companies are figuring out how to advertise
on phone apps. Most of the time, “ads” on phone apps come in the form of
notifications. Have you ever installed a new app and been surprised about all
the notifications you start getting? “Welcome to so-and-so, let us show you
around.” “5 tips to get started quickly.” “Add this to your account.” “We
noticed you didn’t log in yesterday.” “Act now for a 10% discount.” You don’t
need any of this. Notifications on your phone make a noise to interrupt you.
They cut off the real-world conversation you might be having, or they break your
train of thought. As such, &lt;strong&gt;you should only get notifications for things you’d
actually want to interrupt you&lt;/strong&gt;. Namely, things that require immediate action.
A phone call. Perhaps a text message. Maybe meeting reminders from your calendar.
Of all the apps on your phone that can send you notifications, I bet about 90%
of them can wait ‘til later. I think it’s one of the biggest failures of UX
design on both Android and iOS that notifications are enabled and noisy by
default. Instead, they should probably be opt-in per app (off by default), and
silent by default (or even have a better mechanism for a “notification inbox”
that can be dealt with at your leisure). Regardless, there are some things you
can do that make a really big difference here.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Disable notifications for any app that doesn’t need to interrupt you. On both
Android and iOS, it’s possible to remove the app’s notification permission.
Any time an app sends you a notification that you don’t care about, do this.&lt;/li&gt;
  &lt;li&gt;If you can’t disable all notifications for an app, see if you can turn off all
but the type you care about. For example, maybe you want to be notified of
direct messages on Twitter, but you can still turn off all other notification
types for that app.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you can’t disable a notification (for whatever reason), would it make sense
to silence it? Silencing a notification means no vibration or noise, but you
can check it at your convenience in the notification bar. You should be able to
do this for any app from the system settings.&lt;/p&gt;

    &lt;p&gt;&lt;img alt="Silence a notification" src="https://www.mikekasberg.com/images/unsubscribe-me/silent-notification.jpg" /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Can you just uninstall the app? Sometimes that’s an easier solution for
badly-behaved apps than trying to figure out the notification permissions.
Your phone is your space, don’t let companies/apps intrude into it who don’t
need to be there.&lt;/li&gt;
  &lt;li&gt;Do you need to limit your screen time? It’s pretty well documented that people
will spend hours using phone apps because of the dopamine hit the apps
provide. Like many things, it’s probably fine to use apps in moderation, but be
wary of becoming sucked in. Maybe talk to someone in real life or go outside
instead. And if you need help breaking the habit,
&lt;a href="https://support.apple.com/en-us/HT208982"&gt;iOS&lt;/a&gt; and
&lt;a href="https://www.android.com/digital-wellbeing/"&gt;Android&lt;/a&gt; come with tools to monitor
and limit the time you spend on your phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="internet-ads"&gt;Internet Ads&lt;/h3&gt;

&lt;p&gt;As long as people have been using the internet, there have been ads on it. These
days, ads have become much more sophisticated. Large companies – including
Facebook and Google – gather data about nearly every website you visit. Even if
it’s the website of your local news station or a blog you like to read, it’s
likely that at least one big company knows about that visit, and they use this
information primarily to figure out what your interests are. This is why, at
times, some websites seem to have an uncanny ability to advertise whatever you
were just searching for or shopping for. It’s probably impossible to get rid of
100% of ads on the internet, but there are some simple things you can do to
protect your data and reduce the number of ads you see.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Use &lt;a href="https://www.mozilla.org/en-US/firefox/new/"&gt;Firefox&lt;/a&gt; instead of Chrome.
Chrome is owned by Google, a large advertising company. Firefox will protect
you from things like FLoC that Google is integrating with Chrome.&lt;/li&gt;
  &lt;li&gt;Use an ad blocker browser extension. I use &lt;a href="https://ublockorigin.com/"&gt;uBlock
Origin&lt;/a&gt; and I think it’s the best because it’s open
source and not controlled by a company.&lt;/li&gt;
  &lt;li&gt;Google collects info about what you type into the search box, so consider
using a search engine other than Google and changing your browser’s default.
&lt;a href="https://duckduckgo.com/"&gt;DuckDuckGo&lt;/a&gt; is a good alternative to try.&lt;/li&gt;
  &lt;li&gt;If you’re tech-savvy, install a &lt;a href="https://pi-hole.net/"&gt;Pi-hole&lt;/a&gt; on your home
network. This is the best generic ad-blocking solution I’ve found.
Installation and configuration is somewhat tricky (you need to understand some
basics about your home network), but there are guides available that make it
easy enough to do.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="protect-your-data"&gt;Protect Your Data&lt;/h3&gt;

&lt;p&gt;If you’re worried about protecting your data online, you’re probably also
worried about geting hacked. One of the most common ways someone might hack you
is from a major data breach. Let’s say you have an account on LinkedIn. And
let’s suppose &lt;a href="https://www.troyhunt.com/observations-and-thoughts-on-the-linkedin-data-breach/"&gt;LinkedIn gets
hacked&lt;/a&gt;.
Maybe you’re not worried about this - what’s a thief going to do, steal your
resume??? Well, one of the problems with large data breaches is that people can
use that data to figure out the password you used on LinkedIn. And then they can
try to use that password with your email on hundreds of other sites. Amazon,
your bank, your email, Facebook, the list goes on. So how do you protect your
data online?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.mikekasberg.com/blog/2017/03/25/how-i-manage-passwords-with-keepass.html"&gt;Use a password manager&lt;/a&gt;. A password manager helps
you use a different password on every site, so a hack on one site doesn’t
compromise your information on all the others.&lt;/li&gt;
  &lt;li&gt;Use a strong master password that’s never been used anywhere else. There are
two pretty good options for making up a password:
    &lt;ul&gt;
      &lt;li&gt;Think of a sentence with at least 14 words. Maybe a favorite quote. (But not
something you say all the time!) Use the first letter of each word. Even
better if you include capitalization and punctuation in the sentence.&lt;/li&gt;
      &lt;li&gt;Generate a random &lt;a href="https://www.useapassphrase.com/"&gt;Passphrase&lt;/a&gt;.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="whos-paying"&gt;Who’s Paying?&lt;/h2&gt;

&lt;p&gt;If there’s one important thing to remember from this whole article, it’s that
&lt;strong&gt;nothing is free, even on the internet&lt;/strong&gt;. If you can’t figure out who’s paying
for something, &lt;em&gt;it’s you&lt;/em&gt;. You’re exchanging your time (or the ability of
companies to show you ads) for the use of a service. Many people have come to
expect free services on the internet (like email, Facebook, Twitter, YouTube,
etc.). But I think people are finally beginning to realize that they don’t want
to trade their time and attention to companies in the way that they have in the
past. So I think it’s likely that we’ll see a shift in the coming years, where
more online services do away with ads and data tracking and will charge a
nominal fee for their use, and many people will be happy to pay this fee to have
their privacy protected and be free from ads. If you’re paying a company for
their service, the company can focus on building things in a way that benefits
you, the user, rather than looking for ways to benefit their advertisers.&lt;/p&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Sat, 24 Oct 2020 05:15:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/10/23/unsubscribe-me.html</guid></item><item><title>CSS Box Model</title><link>https://dylanpaulus.com/posts/2020/css-box-model/</link><description>&lt;p&gt;CSS is one of those technologies that has a low barrier to entry (good thing 🎉), but because of this sometimes how it works can seem like magic. It's easy to get started writing CSS, so we dive head first into it. Sometimes we smash our face into the concrete with frustration. Why won't my text move over yonder? Where did that scroll bar come from? How do I center this junk?&lt;/p&gt;
&lt;p&gt;This is a series I'm starting called, "CSS: The Important Stuff". The goal is to take a dive into the mechanics of CSS so we can get a better intuition when styling and positioning elements. In part one we'll take a look at Box Model; the underlying layout of the web.&lt;/p&gt;
&lt;h2&gt;What is the Box Model?&lt;/h2&gt;
&lt;p&gt;It comes with great danger to myself to tell you that the web is made of boxes. Yes, it's boxes all the way down. Take a look at this website—open the Element Inspector in the browser's dev tools and add &lt;code&gt;* { border: 1px solid red; }&lt;/code&gt;. Look at all those fine boxes.&lt;/p&gt;
&lt;div&gt;
  &lt;img alt="The dylanpaulus.com website with visible borders around each box element." src="./css-box-model-red-boxes.png" /&gt;
&lt;/div&gt;
&lt;p&gt;The browser uses boxes to layout and render our websites. Within each box there are four properties: content, padding, border, and margin. &lt;a href="https://youtu.be/-FtCTW2rVFM?t=44"&gt;Boxes are like onions, they have layers.&lt;/a&gt; Each property defines the size of our box (ie. width and height), styling, and how content around the box flows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Content&lt;/strong&gt; is what we're usually thinking of when we create HTML elements. Text, images, video, etc. This is at the center of the box&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Padding&lt;/strong&gt; gives space around the edges of the content. Separating the content from the border&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Borders&lt;/strong&gt; are used to separate boxes from each other—as seen in our red border example above&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Margin&lt;/strong&gt; is non-stylistic spacing &lt;em&gt;around&lt;/em&gt; the box. This is useful to separate boxes from each other and position boxes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Showing the layout of content, padding, border, and margin to make up a box." src="./css-box-model.png" /&gt;&lt;/p&gt;
&lt;h2&gt;Why does this matter?&lt;/h2&gt;
&lt;h3&gt;Dimensions&lt;/h3&gt;
&lt;p&gt;There are different ways to determine the width and height of a box. Is the box's dimensions determined by all its layers (margin, border, padding, content)? Or is it determined by the content?&lt;/p&gt;
&lt;p&gt;The browser made a choice in &lt;code&gt;box-sizing&lt;/code&gt; and the default is &lt;code&gt;content-box&lt;/code&gt;. When we give our element a width and height, lets say &lt;code&gt;.box { width: 100px; height: 100; }&lt;/code&gt; , the default behavior with &lt;code&gt;content-box&lt;/code&gt; is to give the content layer the width and height of 100px. But, the box still has extra layers with padding and border. We would assume if we gave the element of 100px that it would be 100px, but the browser needs to add the values of padding and border on top of the content to get its "rendered dimensions".&lt;/p&gt;
&lt;p&gt;Given the styling on our moon icon below, what would you expect the width and height to be on the box?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.moon {
  box-sizing: content-box;
  width: 100px;
  height: 100px;
  padding: 10px;
  border: 1px solid #FFF;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="Showing a moon icon using box sizing content-box." src="./css-box-model-content-box.png" /&gt;&lt;/p&gt;
&lt;p&gt;That's easy it's 100px... wait, 122px, what? How did we get 122px? Remember when we gave the width and height of 100px it only applies to the &lt;strong&gt;content&lt;/strong&gt; layer. We also applied a &lt;strong&gt;padding&lt;/strong&gt; of 10px on &lt;em&gt;each&lt;/em&gt; side of the box and a 1px &lt;strong&gt;border&lt;/strong&gt; around it. If we were to calculate the width of the box, we start with 100px, add 10px for the left padding, add 10px for the right padding, add 1px for the left border, and finally 1px for the right border.&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
100px + 10px + 10px + 1px + 1px = 122px&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;Seems a little counter intuitive—if I set my box to have a 100px width then it should be 100px darn-it! Luckily, there are more ways for the browser to calculate a box's size. When I think of the size of a box, I think of &lt;code&gt;border-box&lt;/code&gt; . Think of the layers of a box, and when assigning box-sizing think of the value as being cascading. When an element has &lt;code&gt;content-box&lt;/code&gt; that means the browser determines the size of a box starting from content and adding any child layers. Since there are no children to content width/height only applies to content. When using &lt;code&gt;border-box&lt;/code&gt;, width/height is set for the border, padding, and content.&lt;/p&gt;
&lt;p&gt;Let's take a look at the same moon icon, but apply &lt;code&gt;border-box&lt;/code&gt; instead.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.moon {
  box-sizing: border-box;
  width: 100px;
  height: 100px;
  padding: 10px;
  border: 1px solid #FFF;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="Showing a moon icon using box sizing as border-box." src="./css-box-model-border-box.png" /&gt;&lt;/p&gt;
&lt;p&gt;What we see is something quite different, the width and height of the moon is now a hard 100x100. This isn't magic though, the missing dimensions have to come from somewhere. Using &lt;code&gt;border-box&lt;/code&gt; the &lt;strong&gt;content&lt;/strong&gt; layer gets shrunk to make room for &lt;strong&gt;padding&lt;/strong&gt; and &lt;strong&gt;border&lt;/strong&gt;. With &lt;code&gt;content-box&lt;/code&gt; our width was guaranteed to be 100px, but what is the width of our content now with &lt;code&gt;border-box&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;$$&lt;br /&gt;
100px - 10px - 10px - 1px - 1px = 78px&lt;br /&gt;
$$&lt;/p&gt;
&lt;p&gt;To me &lt;code&gt;border-box&lt;/code&gt; is easier to intuit and reason around, and becomes my default, but if the width and height of the content matters more than the visible box itself, use &lt;code&gt;content-box&lt;/code&gt;.&lt;/p&gt;
&lt;br /&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model"&gt;Introduction to the CSS basic box model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model"&gt;The box model&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Dylan Paulus' Blog</author><pubDate>Sat, 24 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dylanpaulus.com/posts/2020/css-box-model/</guid></item><item><title>SQL Injection Overview</title><link>https://thomascountz.com/2020/10/24/sql-injection</link><description>&lt;p&gt;&lt;img alt="" src="/assets/images/sql_injection/sql-injection-owasp.png" /&gt;&lt;/p&gt;

&lt;p&gt;An SQL Injection &lt;strong&gt;occurs when untrusted input is used directly in the construction of an SQL query&lt;/strong&gt;. This attack is commonly executed by introducing a meta character (such as a comment) into a data plane in such a way that allows an attacker to add commands to the control plane. Essentially, when building a SQL query from user input, an attacker can insert SQL instructions that cause the application to behave in unintended ways.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;SQL Injection flaws are introduced when software developers create dynamic database queries that include user supplied input.&lt;/p&gt;

  &lt;p&gt;—&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"&gt;OWASP SQL Injection Prevention Cheat Sheet&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="authentication-form-example"&gt;Authentication Form Example&lt;/h2&gt;

&lt;p&gt;Let’s take a login form that requires a user enter a username and password to log in.&lt;/p&gt;

&lt;p&gt;&lt;img alt="" src="/assets/images/sql_injection/login-long-password.png" /&gt;&lt;/p&gt;

&lt;p&gt;In the happy-path case, a user enters in their details, presses “Login,” and a request is sent to a server where we take what the user enters, search the database for that user, and then log that user into our web application.&lt;/p&gt;

&lt;div class="language-ruby highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;# SQL Injection Vulnerable Pseudocode&lt;/span&gt;
&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;

&lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ORM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;"SELECT * 
    FROM users 
    WHERE username = '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'
    AND password = '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;';"&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;# -- snip -- &lt;/span&gt;

&lt;span class="n"&gt;log_in_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using a tool like &lt;a href="http://sqlfiddle.com"&gt;SQL Fiddle&lt;/a&gt;, you can see how a query like this will behave in PostgreSQL 9.6. Here’s is the schema and seed data for our example:&lt;/p&gt;

&lt;div class="language-sql highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;id&lt;/span&gt;        &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;   &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;username&lt;/span&gt;  &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;           &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;password&lt;/span&gt;  &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;           &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sarah'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'good-password'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'thomas'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password123'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'patrice'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'palm-kumquat-futon-padden'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After the user submits the username:&lt;/p&gt;

&lt;div class="language-text highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;thomas
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and password:&lt;/p&gt;

&lt;div class="language-text highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;password123
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;the resulting query will look like this:&lt;/p&gt;

&lt;div class="language-sql highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'thomas'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'password123'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and the following results will be returned:&lt;/p&gt;

&lt;div class="language-text highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;| id | username |    password |
|----|----------|-------------|
|  2 |  tcountz | password123 |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As expected, our backend code then takes this result, and calls the &lt;code class="language-plaintext highlighter-rouge"&gt;log_in_user()&lt;/code&gt; function which authorizes the user to access certain parts of the application.&lt;/p&gt;

&lt;h3 id="authentication-attack"&gt;Authentication Attack&lt;/h3&gt;

&lt;p&gt;The vulnerability here will allow an attacker to log in as any user.&lt;/p&gt;

&lt;p&gt;Because user input is interpolated directly into the SQL query, we can have the server execute arbitrary SQL statements. Let’s take a look at an example that would allow us to log into any user, given we have their username.&lt;/p&gt;

&lt;p&gt;After the user submits the username:&lt;/p&gt;

&lt;div class="language-text highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;patrice'; --
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and a blank (or arbitrary) password, the resulting query looks like this&lt;/p&gt;

&lt;div class="language-sql highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'patrice'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;--' AND password='&amp;lt;anything&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and the results:&lt;/p&gt;

&lt;div class="language-text highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;| id | username |                         password |
|----|----------|----------------------------------|
|  3 |  patrice | 26e9053a783f364d949b4e400dd2f68c |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, our application, again, takes the 0th results (this time the user &lt;code class="language-plaintext highlighter-rouge"&gt;patrice&lt;/code&gt;) and logs them in.&lt;/p&gt;

&lt;h4 id="what-happened"&gt;What Happened?&lt;/h4&gt;

&lt;p&gt;Even though we hashed Patrice’s password, our query was vulnerable to interpreting the &lt;code class="language-plaintext highlighter-rouge"&gt;'&lt;/code&gt;, &lt;code class="language-plaintext highlighter-rouge"&gt;;&lt;/code&gt;, and &lt;code class="language-plaintext highlighter-rouge"&gt;--&lt;/code&gt; PostgreSQL meta characters.&lt;/p&gt;

&lt;p&gt;Firstly, the single quote: &lt;code class="language-plaintext highlighter-rouge"&gt;'&lt;/code&gt;, ends the string (or &lt;code class="language-plaintext highlighter-rouge"&gt;VARCHAR&lt;/code&gt;) that we’re searching for; in this case the username &lt;code class="language-plaintext highlighter-rouge"&gt;patrice&lt;/code&gt;. Next, the semi-colon &lt;code class="language-plaintext highlighter-rouge"&gt;;&lt;/code&gt; represents the end of the SQL statement. Finally, the &lt;code class="language-plaintext highlighter-rouge"&gt;--&lt;/code&gt; represents a comment and tells PostgreSQL to ignore everything that comes after.&lt;/p&gt;

&lt;p&gt;This effectively makes our query look like this:&lt;/p&gt;

&lt;div class="language-sql highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'patrice'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which, as we’ve seen, and as we expect, returns the &lt;code class="language-plaintext highlighter-rouge"&gt;patrice&lt;/code&gt; user and logs them in. Now our attacker has been authenticated and has access to Patrice’s account!&lt;/p&gt;

&lt;p&gt;This combination: &lt;code class="language-plaintext highlighter-rouge"&gt;'; --&lt;/code&gt;, and others like it, show up often in SQL injection attacks and it works by prematurely ending a SQL statement.&lt;/p&gt;

&lt;h3 id="data-destruction-attack"&gt;Data Destruction Attack&lt;/h3&gt;

&lt;p&gt;In the example above, the 0th row of the results returned from the query will be passed into the &lt;code class="language-plaintext highlighter-rouge"&gt;log_in_user()&lt;/code&gt; function, but the scope of this attack vector isn’t limited to logging in.&lt;/p&gt;

&lt;p&gt;As an example of how we can attack the server to execute &lt;em&gt;any&lt;/em&gt; SQL, take this example where we destroy the &lt;code class="language-plaintext highlighter-rouge"&gt;users&lt;/code&gt; table.&lt;/p&gt;

&lt;p&gt;If we enter a username of:&lt;/p&gt;

&lt;div class="language-text highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;'; DROP TABLE users; --
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and a blank (or arbitrary) password, the resulting query looks like this&lt;/p&gt;

&lt;div class="language-sql highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;--' AND password='&amp;lt;anything&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The user-facing effect of this query might not tell us exactly what has happened, but a developer might see something like this show up in the logs:&lt;/p&gt;

&lt;div class="language-text highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;ERROR: relation "users" does not exist
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id="what-happened-1"&gt;What Happened?&lt;/h4&gt;

&lt;p&gt;Similar to the first attack, we’ve cut the original query short and this time, we’ve injected our own query to drop the &lt;code class="language-plaintext highlighter-rouge"&gt;users&lt;/code&gt; table.&lt;/p&gt;

&lt;h2 id="prevention"&gt;Prevention&lt;/h2&gt;

&lt;h3 id="parameterized-queries"&gt;Parameterized Queries&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;The use of prepared statements with variable binding (aka parameterized queries) is how all developers should first be taught how to write database queries.&lt;/p&gt;

  &lt;p&gt;Parameterized queries force the developer to first define all the SQL code, and then pass in each parameter to the query later. This coding style allows the database to distinguish between code and data, regardless of what user input is supplied.&lt;/p&gt;

  &lt;p&gt;— &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"&gt;OWASP SQL Injection Prevention Cheat Sheet&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our code was vulnerable because we use string interpolation to build an SQL statement directly from user input. Instead, we should “parameterize” our query by using whatever tools our language gives us to separate the data plane (input) from the control plane (SQL). This is the idea of using variable binding (placing user input into a type of variable) with prepared statements (the rest of the SQL that we don’t want the user to be able to alter).&lt;/p&gt;

&lt;p&gt;The way to code this varies depending on the language you’re working with, so check out the OWASP SQL Injection Prevention Cheat Sheet section on &lt;a href="https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.md#defense-option-1-prepared-statements-with-parameterized-queries"&gt;parameterized queries&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="other-defenses"&gt;Other Defenses&lt;/h3&gt;

&lt;p&gt;Another defense against SQL injection are stored procedures, which are predefined SQL statements stored in the data table. These procedures can have parameters and can effectively be similar to constructs from different languages. Read more &lt;a href="https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.md#defense-option-2-stored-procedures"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To read more about allow-listing or escaping user input, see the rest of the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"&gt;OWASP SQL Injection Prevention Cheat Sheet&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="next-steps"&gt;Next Steps&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Research SQL injection prevention for your ORM/database
    &lt;ul&gt;
      &lt;li&gt;e.g. &lt;a href="https://guides.rubyonrails.org/security.html#sql-injection"&gt;https://guides.rubyonrails.org/security.html#sql-injection&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Aim to separate queries and data (parameterized queries)
    &lt;ul&gt;
      &lt;li&gt;e.g. &lt;a href="https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Query_Parameterization_Cheat_Sheet.md"&gt;https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Query_Parameterization_Cheat_Sheet.md&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Consider SQL Injection when reviewing code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="code-review"&gt;Code Review&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Aim to validate user input by testing type, length, format, and range.&lt;/li&gt;
  &lt;li&gt;Avoid building SQL statements directly from user input.&lt;/li&gt;
  &lt;li&gt;Implement multiple layers of validation.&lt;/li&gt;
  &lt;li&gt;Avoid concatenating user input that is not validated; this is the primary point of entry for script injection.&lt;/li&gt;
  &lt;li&gt;You should review all code that calls execute(), exe(), and any SQL calls or commands that can call out outside resources or the command line.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="example-code-snippets"&gt;Example Code Snippets&lt;/h2&gt;

&lt;h3 id="rubyactiverecord"&gt;Ruby/ActiveRecord&lt;/h3&gt;

&lt;div class="language-ruby highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;# SQL Injection Vulnerable Ruby/ActiveRecord&lt;/span&gt;
&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;

&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;"username = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:username&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; AND "&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
    &lt;span class="s2"&gt;"password = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;

&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class="language-ruby highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;# SQL Injection Safe Ruby/ActiveRecord&lt;/span&gt;
&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;

&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:username&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;

&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id="elixirecto"&gt;Elixir/Ecto&lt;/h3&gt;

&lt;div class="language-elixir highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;# SQL Injection Vulnerable Elixir/Ecto&lt;/span&gt;
&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;

&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sd"&gt;"""
  SELECT *
  FROM users
  WHERE username = \'#{params["username"]}\'
  AND password = \'#{params["pasword"]}\';
"""&lt;/span&gt;

&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Adapters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;SQL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="ss"&gt;:rows&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class="language-elixir highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;# SQL Injection Safe Elixir/Ecto&lt;/span&gt;
&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;

&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sd"&gt;"""
  SELECT * 
  FROM users 
  WHERE username = $1 
  AND password = $2;
"""&lt;/span&gt;

&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Ecto&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Adapters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;SQL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="ss"&gt;:rows&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# -- snip --&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id="java"&gt;Java&lt;/h3&gt;

&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SQL Injection Vulnerable Java&lt;/span&gt;
&lt;span class="c1"&gt;// -- snip --&lt;/span&gt;

&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM users WHERE username = "&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" AND password = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;";"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Statement&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createStatement&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;statement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// -- snip --&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SQL Injection Safe Java&lt;/span&gt;
&lt;span class="c1"&gt;// -- snip --&lt;/span&gt;

&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getParameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM users WHERE username = ? AND password = ?"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nc"&gt;PreparedStatement&lt;/span&gt; &lt;span class="n"&gt;pstmt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prepareStatement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pstmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pstmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pstmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;executeQuery&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// -- snip --&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id="resources"&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://github.com/OWASP/railsgoat/wiki/R5-A1-SQL-Injection-Concatentation"&gt;https://github.com/OWASP/railsgoat/wiki/R5-A1-SQL-Injection-Concatentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html"&gt;https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.websec.ca/kb/sql_injection"&gt;https://www.websec.ca/kb/sql_injection&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://owasp.org/www-community/attacks/SQL_Injection"&gt;https://owasp.org/www-community/attacks/SQL_Injection&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.websec.ca/kb/sql_injection"&gt;https://www.websec.ca/kb/sql_injection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img alt="https://xkcd.com/327/" src="/assets/images/sql_injection/exploits_of_a_mom.png" /&gt;&lt;/p&gt;</description><author>Thomas Countz</author><pubDate>Sat, 24 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thomascountz.com/2020/10/24/sql-injection</guid></item><item><title>Angrynomics, and my two cents to fix it</title><link>https://stop.zona-m.net/2020/10/angrynomics-and-my-two-cents-to-fix-it/</link><description>&lt;p&gt;Don&amp;rsquo;t know angrynomics yet? You really should.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 23 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/angrynomics-and-my-two-cents-to-fix-it/</guid></item><item><title>Running FastAPI applications in production</title><link>https://stribny.name/posts/fastapi-production/</link><author>Posts by Petr Stribny</author><pubDate>Fri, 23 Oct 2020 19:06:27 GMT</pubDate><guid isPermaLink="true">https://stribny.name/posts/fastapi-production/</guid></item><item><title>On Earth We're Briefly Gorgeous</title><link>https://apurva-shukla.me/bookshelf/on-earth-were-briefly-gorgeous/</link><description>⭐ ⭐ ⭐ ⭐ Vuong is someone who uses words in a way that I haven’t seen before. His words are raw, loving, violent, kind, hurt, political, but…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Fri, 23 Oct 2020 14:57:08 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/bookshelf/on-earth-were-briefly-gorgeous/</guid></item><item><title>GitHub Actions - Copy to S3 on Commit to Master</title><link>https://blog.herlein.com/post/github-to-s3/</link><description>&lt;p&gt;GitHub Actions can be for more than CI/CD.  You can also use them to just simply publish to S3.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Fri, 23 Oct 2020 11:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/github-to-s3/</guid></item><item><title>Broken Femur, Mutual Care, ROI</title><link>https://yasha.solutions/broken-femur-civilisation-creative-brief/</link><description>Margaret Mead was a controversial anthropologist from the 60&amp;rsquo;s in america. One thing not controversial though, and maybe that has made more famous recently than any of her research or publications - is the story of a short annecdote, which has become viral all over the internet.
The story goes like this:
 “A student once asked anthropologist Margaret Mead, “What is the earliest sign of civilization?” The student expected her to say a clay pot, a grinding stone, or maybe a weapon.</description><author>Yasha Solutions</author><pubDate>Fri, 23 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://yasha.solutions/broken-femur-civilisation-creative-brief/</guid></item><item><title>Lang. Identification in Code Mixed Text - Lit. Review 2</title><link>https://trigonaminima.github.io/2020/10/lang-id-2/</link><description>I am reviewing the literature available on language identification for multilingual documents, focusing on Indic languages. I’ll try to cover it in chronological order, but there might be a few misses here and there. After a decent coverage of the research, I expect to have enough understanding to discuss the challenges present in this task in a code-switched setting and its importance.</description><author>Playground</author><pubDate>Fri, 23 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://trigonaminima.github.io/2020/10/lang-id-2/</guid></item><item><title>Rewilding half the planet? OK, if WE do it</title><link>https://stop.zona-m.net/2020/10/rewilding-half-the-planet-ok-if-we-do-it/</link><description>&lt;p&gt;Where &amp;ldquo;WE&amp;rdquo; means ALL humans, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 22 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/rewilding-half-the-planet-ok-if-we-do-it/</guid></item><item><title>30-year Illusion of a Conscious Effort</title><link>https://rohitjha.com/blog/30-year-illusion-of-a-conscious-effort/</link><description>&lt;p&gt;&lt;em&gt;I turned 32 yesterday and I wanted to do this last year but Transcelestial&amp;apos;s Series A raise kept me busy. &lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;Below is a non-comprehensive list of elements from my personal framework that I have built over the years. It&amp;apos;s a glimpse of how I think, what&lt;/em&gt;&lt;/p&gt;</description><author>THINK@RJ</author><pubDate>Thu, 22 Oct 2020 17:44:00 GMT</pubDate><guid isPermaLink="true">https://rohitjha.com/blog/30-year-illusion-of-a-conscious-effort/</guid></item><item><title>Golang Unikernel Is Reality!</title><link>https://blog.herlein.com/post/golang-enabled-microkernel-reality/</link><description>&lt;p&gt;Back in January of 2018 I &lt;a href="https://www.linkedin.com/pulse/golang-enabling-unikernels-greg-herlein/"&gt;blogged on LinkedIn&lt;/a&gt; asking the question if golang would enable development of micro-kernels.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Thu, 22 Oct 2020 10:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/golang-enabled-microkernel-reality/</guid></item><item><title>COVID-19's Impact on IPv6 Traffic</title><link>https://ivymike.dev/covid-19s-impact-on-ipv6-traffic.html</link><description>&lt;h3&gt;COVID-19 has had a significant impact on IPv6 traffic.&lt;/h3&gt;
&lt;p&gt;Among all of the other crazy impacts that COVID-19 has had in 2020, I did not expect COVID-19 to change the fundamental protocol mix of packets on the internet.  But it did!  Read on to find out how.&lt;/p&gt;
&lt;h3&gt;IPv6 primer&lt;/h3&gt;
&lt;p&gt;A …&lt;/p&gt;</description><author>IvyMike.dev</author><pubDate>Thu, 22 Oct 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://ivymike.dev/covid-19s-impact-on-ipv6-traffic.html</guid></item><item><title>Versioning large files in git with DVC</title><link>https://stribny.name/posts/versioning-large-files-in-git-with-dvc/</link><author>Posts by Petr Stribny</author><pubDate>Wed, 21 Oct 2020 13:06:27 GMT</pubDate><guid isPermaLink="true">https://stribny.name/posts/versioning-large-files-in-git-with-dvc/</guid></item><item><title>Internet centralization is inevitable, and may even be good</title><link>https://stop.zona-m.net/2020/10/internet-centralization-is-inevitable-and-may-even-be-good/</link><description>&lt;p&gt;Here is something about the &amp;ldquo;logic&amp;rdquo; of the Internet that we should not ignore.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 21 Oct 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/internet-centralization-is-inevitable-and-may-even-be-good/</guid></item><item><title>How to Improve Interface Responsiveness With Web Workers</title><link>https://www.dannyguo.com/blog/how-to-improve-interface-responsiveness-with-web-workers</link><author>Danny Guo</author><pubDate>Wed, 21 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.dannyguo.com/blog/how-to-improve-interface-responsiveness-with-web-workers</guid></item><item><title>Adapting types to fix SQLAlchemy's "can't adapt type" error</title><link>https://gaganpreet.in/posts/sqlalchemy-cant-adapt-type/</link><description>&lt;p&gt;I have recently been using Pydantic a lot, which is pretty cool since it lets me specify concrete types on my previously untyped data.&lt;/p&gt;
&lt;p&gt;Until I ran into an error when I was inserting data stored in a Pydantic model to my postgres database using SQLAlchemy.&lt;/p&gt;
&lt;h2 class="relative group" id="problem"&gt;Problem &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#problem"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;I have a Pydantic model like this to define my incoming data from a request:&lt;/p&gt;</description><author>Gaganpreet Arora</author><pubDate>Wed, 21 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://gaganpreet.in/posts/sqlalchemy-cant-adapt-type/</guid></item><item><title>My Wireless Internet Setup</title><link>https://adriano.fyi/posts/2020-10-21-my-wireless-internet-setup/</link><description>&lt;p&gt;If you&amp;rsquo;re reading this, you&amp;rsquo;re probably familiar with the fact that I&amp;rsquo;m &lt;a href="https://adriano.fyi/post/2020-08-26-roaming/"&gt;permanently roaming&lt;/a&gt;, and I&amp;rsquo;d be foolish not to acknowledge the importance of my wireless setup in making that possible. Getting &amp;ndash; and staying &amp;ndash; connected while permanently roaming is nothing like paying the local cable cabal to get your house or apartment connected.&lt;/p&gt;
&lt;p&gt;Remember the last show you binged on Netflix over the weekend? That consumed 20x most mobile users&amp;rsquo; monthly data allotment, but you never had to think about data because when you&amp;rsquo;re wired you generally don&amp;rsquo;t pay for consumption. How many hours of video conferencing do you do every day? That&amp;rsquo;ll be ~1GB/hr, please.&lt;/p&gt;
&lt;p&gt;Let me make one thing clear from the outset: I&amp;rsquo;m by no means an expert in wireless technology, and there may be &lt;em&gt;many&lt;/em&gt; better ways to get connected than the one(s) I&amp;rsquo;ve chosen. So if you spot a flaw or have suggestions for me, be sure to get in touch and let me know. I&amp;rsquo;ll keep this post up to date as reasonably possible as I get more feedback and make changes in the future.&lt;/p&gt;
&lt;p&gt;I also feel compelled to call out &lt;strong&gt;&amp;ldquo;Unlimited Data&amp;rdquo;&lt;/strong&gt; plans before we get started. For us mere mortals who are not grandfathered into legacy plans: unlimited data plans no longer exist. You may find a fly-by-night company offering unlimited data plans for a short time, but you&amp;rsquo;ll probably soon realize that they&amp;rsquo;re doing it in violation of their agreement with the upstream provider when they get shut down. In the best case scenario, you&amp;rsquo;ll need to get a new SIM card if they&amp;rsquo;re able to remain in operation and switch to a new upstream provider. These fly-by-nights are more commonly known as MVNOs (Mobile Virtual Network Operators). They&amp;rsquo;re the likes of Cricket Wireless, Boost Mobile, etc. These companies are piggybacked on AT&amp;amp;T, Verizon, T-Mobile, and Sprint. As a result, they&amp;rsquo;re subject to the true operator&amp;rsquo;s rules and the terms of their agreement.&lt;/p&gt;
&lt;p&gt;Figuring all this out was a bit of a journey for me and I&amp;rsquo;ve had a ton of conversations with friends and acquaintances about the details. So I figured it was time to finally capture the details.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id="choices"&gt;Choices&lt;/h1&gt;
&lt;p&gt;Between equipment and service providers, there&amp;rsquo;s no shortage of choices to be made early in the wireless setup journey. I&amp;rsquo;ll try to capture a non-exhaustive list of pros and cons for a few options before getting into the choices I&amp;rsquo;ve personally made, and the motivation for having made them. However, be sure to consider your data needs and access patterns before taking my opinions and choices as gospel, because if you won&amp;rsquo;t be working or streaming media &amp;ndash; your choice might be quite simple: &lt;strong&gt;cell phone hotspot&lt;/strong&gt;.&lt;/p&gt;
&lt;h1 id="equipment"&gt;Equipment&lt;/h1&gt;
&lt;p&gt;Equipment is the most technical aspect of getting yourself connected while roaming. For the time being, I&amp;rsquo;ll forego talking at all about dedicated antennas, because that&amp;rsquo;s a topic that is both very deep, and one I cannot speak very intelligently about. However, if you want a serious setup, you&amp;rsquo;ll want to buy a dedicated antenna; trust me.&lt;/p&gt;
&lt;h2 id="cell-phone-hotspot"&gt;Cell Phone Hotspot&lt;/h2&gt;
&lt;p&gt;This is the most obvious choice if you&amp;rsquo;re just dipping your toes in the roaming waters. It doesn&amp;rsquo;t require any equipment or service that you don&amp;rsquo;t already have, and is actually quite fast and versatile. If cell phone antennas were as good as external, dedicated antennas, and the wireless cabals would stop pretending that anyone who wants to hotspot from their phone is some kind deviant, phone hotspots would be a fantastic option. And for many people, they still can be.&lt;/p&gt;
&lt;h3 id="pros"&gt;Pros&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No new equipment or service required&lt;/li&gt;
&lt;li&gt;Cheap&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cons"&gt;Cons&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Cell phone antennas don&amp;rsquo;t have enough gain to pick up the weak radio signals that whisper across BLM (Bureau of Land management), National Forest, and other public lands. &amp;ldquo;No bars&amp;rdquo; will quickly render those lands uninhabitable.&lt;/li&gt;
&lt;li&gt;The wireless cabals often place very low &amp;ldquo;Hotspot&amp;rdquo; data caps on their &amp;ldquo;Unlimited&amp;rdquo; plans. While on-device data may be relatively unlimited, you&amp;rsquo;ll find that hotspot data is capped at 5-15GB.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="signal-boosters"&gt;Signal Boosters&lt;/h2&gt;
&lt;p&gt;Signal boosters can be great, especially if you&amp;rsquo;re using your cell phone as a hotspot. Boosters can range from tens of dollars to several hundred. These can be thought of as cell signal re-transmitters; they make a weak signal stronger &amp;ndash; which is why they&amp;rsquo;re a good complement to a cell phone hotspot. I&amp;rsquo;ve never owned one, so be aware that my opinion is of limited value here.&lt;/p&gt;
&lt;h3 id="pros-1"&gt;Pros&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Usually cheaper than dedicated wireless routers.&lt;/li&gt;
&lt;li&gt;Can be used in conjunction with your existing equipment (cell phone)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cons-1"&gt;Cons&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Don&amp;rsquo;t provide connectivity to non-cell devices (laptops, tablets, smart TVs, etc.)&lt;/li&gt;
&lt;li&gt;The range over which they amplify cell signal can be quite small. Sometimes less than a 10 feet.&lt;/li&gt;
&lt;li&gt;Not all allow for external antennas, so their gain (ability to pick up signal) and placement can be limited.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wireless-routers"&gt;Wireless Routers&lt;/h2&gt;
&lt;p&gt;Wireless routers are the most versatile option. And generally the most expensive.&lt;/p&gt;
&lt;h3 id="pros-2"&gt;Pros&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Usually provide a WiFi network, allowing you to bring non-cell devices online.&lt;/li&gt;
&lt;li&gt;Have external antennas, allowing for optimal placement/gain.&lt;/li&gt;
&lt;li&gt;Can be purchased directly from your wireless provider or 3rd party.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cons-2"&gt;Cons&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Many wireless providers only &lt;em&gt;officially&lt;/em&gt; support their own &amp;ldquo;hotspot&amp;rdquo; devices. E.g. &amp;ldquo;Nighthawks&amp;rdquo; and &amp;ldquo;MIFIs&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Can be quite expensive&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="wireless-providers"&gt;Wireless Providers&lt;/h1&gt;
&lt;p&gt;This section could become &lt;em&gt;very long&lt;/em&gt;. So instead of providing all the details here, I&amp;rsquo;ll point you to the &lt;a href="https://www.rvmobileinternet.com"&gt;Mobile Internet Resource Center&lt;/a&gt;, which is an invaluable resource for understanding the current mobile service provider landscape. Things change &lt;em&gt;fast&lt;/em&gt; when it comes to providers, so by the time you read this there may be a new kid on the block. I used Mobile Internet Resource Center extensively when I was researching both gear and providers.&lt;/p&gt;
&lt;h2 id="quick-summary"&gt;Quick Summary&lt;/h2&gt;
&lt;p&gt;Instead of getting into the details here, I&amp;rsquo;ll leave you with the most important thing that you should take away:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Redundant service providers is essential&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I cannot stress that enough. If you can afford it, and you know you&amp;rsquo;ll move locations often &amp;ndash; have at lease two service providers at all times. Whether it&amp;rsquo;s Verzion, Sprint, T-Mobile, or AT&amp;amp;T &amp;ndash; have at least two. If you can afford more, get more than two; especially if you don&amp;rsquo;t have a direct relationship with the provider and one is at risk of going out of business (i.e. you&amp;rsquo;re connecting through an MVNO).&lt;/p&gt;
&lt;h2 id="throttling-and-deprioritization"&gt;Throttling and Deprioritization&lt;/h2&gt;
&lt;p&gt;You&amp;rsquo;ll &lt;strong&gt;need&lt;/strong&gt; to know the difference between throttling and deprioritization before purchasing a data plan. Every wireless provider engages in one, if not both of these two practices, and the difference between them are stark.&lt;/p&gt;
&lt;h2 id="throttling"&gt;Throttling&lt;/h2&gt;
&lt;p&gt;Providers may refer to throttling by some other name, but the details are generally the same.&lt;/p&gt;
&lt;p&gt;Scenario:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You have an &amp;ldquo;unlimited&amp;rdquo; data plan with some fine print that says after &lt;code&gt;X&lt;/code&gt; gigabytes of usage, you&amp;rsquo;ll be throttled to &lt;code&gt;2G&lt;/code&gt; speed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You&amp;rsquo;re half way through the month and you&amp;rsquo;ve already consumed &lt;code&gt;X&lt;/code&gt; gigabytes of data. You try to load &lt;a href="https://reuters.com"&gt;https://reuters.com&lt;/a&gt; to see what insanity the US cheeto-in-chief has been spewing, but the page won&amp;rsquo;t load.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now it&amp;rsquo;s important to know how fast &amp;ldquo;2G speed&amp;rdquo; is. Almost all providers throttle to 2G speed when they throttle, so make no mistake: &lt;strong&gt;2G SPEED IS WAY TOO SLOW&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re not getting anything done at &lt;code&gt;2G&lt;/code&gt; speed. Specifically, it&amp;rsquo;s &lt;code&gt;128Kbps&lt;/code&gt;, or an ISDN line, or &lt;code&gt;~2x&lt;/code&gt; the speed of your childhood AOL dialup connection. Scientifically, it&amp;rsquo;s the speed at which you test a web page in your browser and you give up saying: &amp;ldquo;Nope, no internet here&amp;rdquo;. So if you&amp;rsquo;re getting throttled, you&amp;rsquo;re neither playing nor working on the interwebs. And let me be clear, if you&amp;rsquo;re getting throttled to &lt;code&gt;128Kbps/2G&lt;/code&gt; speed, you&amp;rsquo;re &lt;em&gt;lucky&lt;/em&gt; if you see that kind of speed. You&amp;rsquo;re probably running at 1995 &lt;code&gt;56K&lt;/code&gt; dialup at best.&lt;/p&gt;
&lt;p&gt;Throttling to &lt;code&gt;2G&lt;/code&gt; speed on a &lt;code&gt;4G&lt;/code&gt; data plan should be &lt;em&gt;illegal&lt;/em&gt;. That&amp;rsquo;s not hyperbole.&lt;/p&gt;
&lt;h2 id="deprioritization"&gt;Deprioritization&lt;/h2&gt;
&lt;p&gt;This is the lesser of two evils.&lt;/p&gt;
&lt;p&gt;Scenario:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You have an &amp;ldquo;unlimited&amp;rdquo; data plan with some fine print that says after &lt;code&gt;X&lt;/code&gt; gigabytes of usage, you&amp;rsquo;ll be deprioritized.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Someone who hasn&amp;rsquo;t exceeded their soft cap needs to download a file and the cell tower you&amp;rsquo;re on is already overloaded. Your Netflix stream gets a little stuttery.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This one&amp;rsquo;s a bit more ambiguous. But in my experience, and in the places I tend to stay, it&amp;rsquo;s hard to tell the difference between mediocre signal and deprioritization. Basically, your traffic gets put behind everyone else&amp;rsquo;s traffic. If you&amp;rsquo;re somewhere rural, you&amp;rsquo;re probably not going to notice because service already sucks. That&amp;rsquo;s the reality.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id="my-setup"&gt;My Setup&lt;/h1&gt;
&lt;p&gt;If you look at the pros/cons above, you&amp;rsquo;ll probably have guessed my choice. I decided to purchase a LTE Router with an omnidirectional antenna, and service provided by &lt;em&gt;Verizon&lt;/em&gt; and &lt;em&gt;AT&amp;amp;T&lt;/em&gt;.&lt;/p&gt;
&lt;h1 id="lte-router"&gt;LTE Router&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;m specifically calling out that I have a &lt;em&gt;LTE&lt;/em&gt; router and not 5G because in 2020 it&amp;rsquo;s relevant to note that we&amp;rsquo;re on the verge of a nationwide 5G rollout. There are two reasons I chose 4G LTE:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;5G is far from rolled out nation-wide and coverage in rural areas hardly exists.&lt;/li&gt;
&lt;li&gt;5G in the high frequencies does not penetrate obstacles or refract well. Making it non-ideal for hilly and wooded areas.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My router is a &lt;a href="https://www.sierrawireless.com/products-and-solutions/routers-gateways/rv55/"&gt;Sierra Wireless RV55&lt;/a&gt;. It&amp;rsquo;s not cheap, but it&amp;rsquo;s reliable and rugged as hell.&lt;/p&gt;
&lt;p&gt;Purchase Motivation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;It&amp;rsquo;s LTE-A Pro (CAT 12)&lt;/em&gt;, supporting up to 600Mbps/150Mbps (DL/UL) [But let&amp;rsquo;s be real, you&amp;rsquo;ll never see that kind of speed on &lt;em&gt;any&lt;/em&gt; provider. I think I wasted my money on this feature]&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Supports Ethernet for when it&amp;rsquo;s available&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Supports dual-mode WiFi.&lt;/em&gt; I have two 9dBi WiFi antennas attached to it &amp;ndash; one can pick up WiFi, and the other can transmit it. This way, my Kindle, Apple TV, laptops, etc. don&amp;rsquo;t need to be reconfigured to use a new WiFi provider if I&amp;rsquo;m on campground WiFi. It sees the new WiFi connection as one they&amp;rsquo;re already familiar with: &lt;code&gt;roam&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Has two SIM slots.&lt;/em&gt; This means I can switch between Verizon and AT&amp;amp;T automatically without having to replace any SIM cards. Granted, network switching is slow because it has to reload network-specific firmware any time it switches network.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Supports both AC and DC power.&lt;/em&gt; Living in an RV this is huge. The router is wired directly into the RV&amp;rsquo;s 12V DC power, drawing less than an amp of power. Not running a &lt;code&gt;DC-&amp;gt;AC&lt;/code&gt; inverter is key to saving battery.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="antennas"&gt;Antenna(s)&lt;/h1&gt;
&lt;p&gt;I actually have both directional (9 dBi) and omnidirectional (6 dBi) antennas. Now you&amp;rsquo;ve seen me talk about both &lt;em&gt;gain&lt;/em&gt; and this &lt;em&gt;dBi&lt;/em&gt; nonsense. Gain is measured in dBi. The higher the number, the more signal you can grab out of the air. 6 dBi is decent, 9 dBi is pretty good. A good &amp;ldquo;Yagi&amp;rdquo; antenna gain can be &amp;gt; 10 dBi.&lt;/p&gt;
&lt;p&gt;I use my omnidirectional antenna almost 100% of the time because I generally have no idea where the tower is and would rather not spend 20 minutes pointing my directional antenna all over creation trying to find a tower when I arrive somewhere new. Not when there&amp;rsquo;s only 3 dBi difference between my omni/directional antennas. If 3 dBi is the difference between me being connected and disconnected &amp;ndash; chances are, I&amp;rsquo;m not going to get much done on that connection anyway. It&amp;rsquo;s &lt;em&gt;going&lt;/em&gt; to be volatile. Temperature changes will affect it, humidity will affect it; maybe even star alignment. I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;My antenna is a &lt;a href="https://www.amazon.com/gp/product/B07ZBVX8VL/"&gt;Proxicast Pro-Gain 4G/LTE MIMO Antenna&lt;/a&gt;. That this antenna is a MIMO antenna is what helps me take advantage of the LTE-A tech in my router. Am I getting 600Mbps download speed? Not a chance! But it does allow the router to bond together the signal from two different channels into a more reliable connection. Neat.&lt;/p&gt;
&lt;h1 id="signal-tester"&gt;Signal Tester&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ll come back to this one. I have a signal tester, but I&amp;rsquo;m not looking at it and can&amp;rsquo;t remember what brand/model it is. These are great if you want to do some recon in a new area. Bring your signal tester and the antenna that you use with your device to get an idea of whether or not the signal is viable. I won&amp;rsquo;t bet my life on the results I get from my tester, but it&amp;rsquo;s a good gut check if I don&amp;rsquo;t want to pull the rig into a new location blind.&lt;/p&gt;
&lt;h1 id="wireless-providers-1"&gt;Wireless Providers&lt;/h1&gt;
&lt;p&gt;As I already let on earlier, I have two redundant providers: AT&amp;amp;T is my primary and Verizon is my backup. At one point, I had T-Mobile provided by a MVNO called OTR Mobile. That gravy train was great while it lasted: $80/mo for a truly unlimited plan. It lasted all of four months before (I&amp;rsquo;m guessing), T-Mobile terminated the relationship for violation of contract.&lt;/p&gt;
&lt;h2 id="att"&gt;AT&amp;amp;T&lt;/h2&gt;
&lt;p&gt;My AT&amp;amp;T service is a bit unique, and I acknowledge that this option is not available to everyone because it requires one to have either a business of their own, or a business willing to open a line on their behalf.&lt;/p&gt;
&lt;p&gt;My AT&amp;amp;T service is a &amp;ldquo;unlimited&amp;rdquo; 12Mbps Mobile Broadband plan for ~$150/mo (after taxes). This is as near unlimited as I believe possible today, as my data is simply &amp;ldquo;deprioritized&amp;rdquo; after 75GB. I&amp;rsquo;ve not been able to notice deprioritization. See the &lt;a href="https://adriano.fyi/posts/2020-10-21-my-wireless-internet-setup/#throttling-and-deprioritization"&gt;Throttling &amp;amp; Deprioritization&lt;/a&gt; for more details on what this means.&lt;/p&gt;
&lt;p&gt;UPDATE: I now have AT&amp;amp;T&amp;rsquo;s 50Mbps plan for ~$200/mo. Deprioritization may begin at &lt;code&gt;125GB&lt;/code&gt;. See AT&amp;amp;T&amp;rsquo;s &lt;a href="https://www.business.att.com/products/wireless-broadband.html"&gt;Wireless Broadband Plans here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="verizon"&gt;Verizon&lt;/h2&gt;
&lt;p&gt;My backup Verizon service is through &lt;a href="https://www.usmobile.com"&gt;US Mobile&lt;/a&gt;. It&amp;rsquo;s &amp;ldquo;Unlimited&amp;rdquo;, but they can throttle after 50GB. Granted, I&amp;rsquo;ve never noticed any throttling because it&amp;rsquo;s always fairly slow. It&amp;rsquo;s reliable though, and acceptably slow.&lt;/p&gt;
&lt;p&gt;UPDATE: US Mobile now &lt;em&gt;throttles&lt;/em&gt; at 50GB rather than deprioritizes. As I&amp;rsquo;ve mentioned, being throttled renders this plan useless, which is why this plan is only a backup plan.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1 id="conclusions"&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;I&amp;rsquo;ve glossed over &lt;em&gt;a lot&lt;/em&gt; of details and yet this post is still too long. My apologies. If there&amp;rsquo;s anything I can help clarify, or details you think I may be able to reveal, please feel free to reach out to me. I can probably feign some degree of competence in providing answers. Also, please let me know if I&amp;rsquo;ve gotten anything wrong. I researched a lot of service providers and equipment throughout this process, so if there&amp;rsquo;s a router, booster, or providers you have questions about &amp;ndash; I may know a thing or two.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;</description><author>Adriano Caloiaro's personal blog</author><pubDate>Wed, 21 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://adriano.fyi/posts/2020-10-21-my-wireless-internet-setup/</guid></item><item><title>Medical Artificial Intelligence depends on where you live</title><link>https://stop.zona-m.net/2020/10/medical-artificial-intelligence-depends-on-where-you-live/</link><description>&lt;p&gt;Especially if you live in the right places.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 20 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/medical-artificial-intelligence-depends-on-where-you-live/</guid></item><item><title>Moderating a 220k Developer Community</title><link>https://www.swyx.io/moderating-rreactjs</link><description>Reflections from two-and-a bit years helping to run /r/Reactjs</description><author>swyx's site RSS Feed</author><pubDate>Tue, 20 Oct 2020 20:19:41 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/moderating-rreactjs</guid></item><item><title>Is There a Better Way?</title><link>https://phili.pe/posts/is-there-a-better-way/</link><description>The question to keep asking yourself when using your tools</description><author>Philipe Fatio</author><pubDate>Tue, 20 Oct 2020 15:15:56 GMT</pubDate><guid isPermaLink="true">https://phili.pe/posts/is-there-a-better-way/</guid></item><item><title>Understanding when to use useMemo</title><link>https://maxrozen.com/understanding-when-use-usememo</link><description>If you've just learned what useCallback is, you might be wondering why on earth useMemo exists, and why we don't use it everywhere.</description><author>Max Rozen</author><pubDate>Tue, 20 Oct 2020 12:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/understanding-when-use-usememo</guid></item><item><title>Building Solution Architecture Teams - A Software Approach</title><link>https://blog.herlein.com/post/sa-team-software-approach/</link><description>&lt;p&gt;What actually is Solution Architecture?  How do you build and manage an Architecture team?  Can you take a software approach to that?&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Tue, 20 Oct 2020 11:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/sa-team-software-approach/</guid></item><item><title>Defining Data Intuition</title><link>https://blog.harterrt.com/data_intuition.html</link><description>&lt;p&gt;Last week, one of my peers asked me to explain what I meant by "Data Intuition",
and I realized I really didn't have a good definition.
That's a problem! I refer to data intuition all the time!&lt;/p&gt;
&lt;p&gt;Data intuition is one of the three skills I interview new data scientists …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Tue, 20 Oct 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/data_intuition.html</guid></item><item><title>Advertising is broken, and stock market-like regulations won't fix it</title><link>https://stop.zona-m.net/2020/10/advertising-is-broken-and-stock-market-like-regulations-wont-fix-it/</link><description>&lt;p&gt;Just like &amp;ldquo;breaking up Facebook&amp;rdquo;. It can&amp;rsquo;t work.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 19 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/advertising-is-broken-and-stock-market-like-regulations-wont-fix-it/</guid></item><item><title>Startup prerequisites: Part 1</title><link>https://ankitag9.substack.com/p/startup-prerequisites-part-1</link><description>Learning from my journey as an entrepreneur..</description><author>Perspective by Ankit Agarwal</author><pubDate>Mon, 19 Oct 2020 13:29:31 GMT</pubDate><guid isPermaLink="true">https://ankitag9.substack.com/p/startup-prerequisites-part-1</guid></item><item><title>No, C++ still isn't cutting it.</title><link>https://da-data.blogspot.com/2020/10/no-c-still-isnt-cutting-it.html</link><description>&lt;p&gt;&amp;nbsp;A recent blog post asked "&lt;a href="https://nibblestew.blogspot.com/2020/10/does-c-still-deserve-bad-rap-it-has-had.html"&gt;Does C++ still deserve its bad rap&lt;/a&gt;?"&lt;/p&gt;&lt;p&gt;While that title presumes the answer (after all, a "bad rap" implies that the judgement is undeserved), I think C++'s reputation for making it very difficult to achieve security or memory safety or thread-safety remains well-deserved, even though it's gotten a lot better over the years. I mean that: The c++-17 version of that program is years better than it would have been with c++0x, and it let a careful programmer write a nice program.&lt;/p&gt;&lt;p&gt;The post used a simple multi-file word count as an example:&amp;nbsp; Count all words in all ".txt" files in the current directory and all of its subdirectories, where words were defined as things matching the regexp&amp;nbsp;&lt;span style="background-color: white; color: #ba2121; font-family: monospace; font-size: 11px; white-space: pre;"&gt;"([a-z]{2,})" &lt;/span&gt;in a case-insensitive manner.&lt;/p&gt;&lt;p&gt;First, I'll walk through the example from that blog post and identify some remaining bugs.&amp;nbsp; And then we'll build up a (IMO) better version in Rust that's faster, safer, and more concise.&amp;nbsp; Let's start with the body that processes the files and adds the counts to a hash table:&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJfGz2h5sFcSF9uIn1Ak9xOTaY2tQK1ZzKsNN0ipNfYl8OVPFWCLYIQlGs3MeLHVak9WsZWp3gAOyvNtrpKGgeoHdMCeQglsgC3FEjhfhKK0onQQNVyrGGR2yAv8jh7E_vMbcC54tlskE/s1492/Screen+Shot+2020-10-17+at+2.44.23+PM.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJfGz2h5sFcSF9uIn1Ak9xOTaY2tQK1ZzKsNN0ipNfYl8OVPFWCLYIQlGs3MeLHVak9WsZWp3gAOyvNtrpKGgeoHdMCeQglsgC3FEjhfhKK0onQQNVyrGGR2yAv8jh7E_vMbcC54tlskE/w660-h270/Screen+Shot+2020-10-17+at+2.44.23+PM.png" width="660" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;A few things immediately come to mind when examining this code from a safety perspective.&amp;nbsp; First, it uses a&amp;nbsp;&lt;a href="https://en.cppreference.com/w/cpp/filesystem/recursive_directory_iterator"&gt;filesystem::recursive_directory_iterator&lt;/a&gt;&amp;nbsp;to identify the files in the current directory, testing their types and names before processing them.&amp;nbsp; It then opens the file using &lt;a href="https://en.cppreference.com/w/cpp/io/basic_ifstream"&gt;std::ifstream&lt;/a&gt;.&lt;/div&gt;&lt;p&gt;From the way I phrased this, you're probably already guessing that this is a TTCTTOU eror -- time-to-check-to-time-of-use. The program validates that the entry is a regular file, but then later opens it, and assumes that the result of the check holds. We should ask ourselves:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;What happens if the file has been deleted between the directory listing and the open?&lt;/li&gt;&lt;li&gt;What happens if the file has been replaced by, e.g., a pipe or other not regular_file?&lt;/li&gt;&lt;/ul&gt;For the second case, it's pretty clear that the program will try to open it and operate on it; this is therefore a bug with respect to the intent of the programmer. Is it a huge bug in this context? Not at all, but analogous bugs have led to serious security problems.&lt;p&gt;&lt;/p&gt;&lt;p&gt;For the first case, I wasn't sure - and I bet many other C++ programmers aren't either. The answer is that the std::ifstream is safe, and will simply behave in the same way as if EOF was reached, but I wasn't certain about that until I googled it a lot and wrote a test program to verify it. Accidental correctness is better than being wrong, but we should strive for more in our programs.&lt;br /&gt;&lt;br /&gt;Finally, the way it's written isn't very conducive to future multithreading. That's wasn't the point of the exercise, but I think it's worth thinking about as many modern data processing programs take an evolutionary path from single-threaded to multi-threaded. Constructs like this invite threading bugs:&lt;br /&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_hYuD5QCltu1rQ7x0qpJ0kdPysC8VPS7jTRhnu0fhcAI6QgzkKmp3OnLYGoSOFVlCE1dDjWntQ8cdWlEQ8hGitMfOaSU3FN1FK3y20g6WMVfPRU8DyJV0cqYBxJSROUNP_7uxy_zy1q0/s1470/Screen+Shot+2020-10-17+at+3.15.41+PM.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="70" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_hYuD5QCltu1rQ7x0qpJ0kdPysC8VPS7jTRhnu0fhcAI6QgzkKmp3OnLYGoSOFVlCE1dDjWntQ8cdWlEQ8hGitMfOaSU3FN1FK3y20g6WMVfPRU8DyJV0cqYBxJSROUNP_7uxy_zy1q0/w640-h70/Screen+Shot+2020-10-17+at+3.15.41+PM.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;(1) It separates the computation of a safe size range from the use of that range;&amp;nbsp; (2) it destructively modifies the word_array for no reason other than to make it easy to print the first 10 items.&amp;nbsp; And adding multithreading to things in C++ still remains somewhat painful.&lt;br /&gt;&lt;br /&gt;Here are some reasons I'm coming to prefer Rust as a systems language. It's not remarkably shorter - the Python or shell version of all this can be expressed in a few lines of code!&amp;nbsp; But it's a bit shorter, and it's more clear where corners have been cut or errors properly handled:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; anyhow::&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; lazysort::SortedBy;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; std::collections::HashMap;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; std::io::prelude::*;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;fn&lt;/span&gt; &lt;span style="color: #dcdcaa;"&gt;scanfiles&lt;/span&gt;() -&amp;gt; &lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;&amp;lt;()&amp;gt; {&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;mut&lt;/span&gt; wordcounts = HashMap::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;();&lt;/div&gt;&lt;br /&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; words = regex::Regex::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;r"([a-zA-Z]{2,})"&lt;/span&gt;)?;&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; file &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; globwalk::&lt;span style="color: #dcdcaa;"&gt;glob&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"*.txt"&lt;/span&gt;)?&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;::ok)&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(|dirent| std::fs::File::&lt;span style="color: #dcdcaa;"&gt;open&lt;/span&gt;(dirent.&lt;span style="color: #dcdcaa;"&gt;path&lt;/span&gt;()).&lt;span style="color: #dcdcaa;"&gt;ok&lt;/span&gt;())&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter&lt;/span&gt;(|file| {&lt;/div&gt;&lt;div&gt;            file.&lt;span style="color: #dcdcaa;"&gt;metadata&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;and_then&lt;/span&gt;(|md| Ok(md.&lt;span style="color: #dcdcaa;"&gt;is_file&lt;/span&gt;()))&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;unwrap_or&lt;/span&gt;(&lt;span style="color: #569cd6;"&gt;false&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;        })&lt;/div&gt;&lt;div&gt;    {&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; reader = std::io::BufReader::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(file);&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; line &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; reader.&lt;span style="color: #dcdcaa;"&gt;lines&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;::ok) {&lt;/div&gt;&lt;div&gt;            &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; word &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; words.&lt;span style="color: #dcdcaa;"&gt;captures_iter&lt;/span&gt;(&amp;amp;line) {&lt;/div&gt;&lt;div&gt;                &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; w = word[&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;].&lt;span style="color: #dcdcaa;"&gt;to_lowercase&lt;/span&gt;();&lt;/div&gt;&lt;div&gt;                *wordcounts.&lt;span style="color: #dcdcaa;"&gt;entry&lt;/span&gt;(w).&lt;span style="color: #dcdcaa;"&gt;or_insert&lt;/span&gt;(&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;) += &lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;            }&lt;/div&gt;&lt;div&gt;        }&lt;/div&gt;&lt;div&gt;    }&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; words_sorted = wordcounts.&lt;span style="color: #dcdcaa;"&gt;iter&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;sorted_by&lt;/span&gt;(|a, b| b.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;.&lt;span style="color: #dcdcaa;"&gt;cmp&lt;/span&gt;(a.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;));&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; kv &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; words_sorted.&lt;span style="color: #dcdcaa;"&gt;take&lt;/span&gt;(&lt;span style="color: #b5cea8;"&gt;10&lt;/span&gt;) {&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #dcdcaa;"&gt;println!&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"{} {}"&lt;/span&gt;, kv.&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;, kv.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;);&lt;/div&gt;&lt;div&gt;    }&lt;/div&gt;&lt;div&gt;    Ok(())&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;fn&lt;/span&gt; &lt;span style="color: #dcdcaa;"&gt;main&lt;/span&gt;() {&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #c586c0;"&gt;if&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; Err(e) = &lt;span style="color: #dcdcaa;"&gt;scanfiles&lt;/span&gt;() {&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #dcdcaa;"&gt;println!&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"Error:  Something unexpected happened: {:#?}"&lt;/span&gt;, e);&lt;/div&gt;&lt;div&gt;    }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Ok, that's 39 lines of code, but not counting the Cargo.toml file, which is another 4 of non-boilerplate (the four dependencies, which are fairly analogous to the #include lines in the C++ version, so should be counted).&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;A little shorter.&amp;nbsp; But what I like about the Rust version is that there's a lot less guessing about the error handling.&amp;nbsp; Did the file fail to open?&amp;nbsp; We know it's skipped, because the &lt;span style="font-family: courier;"&gt;filter_map&lt;/span&gt; will discard that file if the result of the open is not ok.&amp;nbsp; We know errors in &lt;span style="font-family: courier;"&gt;globwalk&lt;/span&gt; or constructing the regex are handled, because the &lt;span style="font-family: courier;"&gt;?&lt;/span&gt; will cause the function to return an error if they return an error.&amp;nbsp; The more functional &lt;span style="font-family: courier;"&gt;.&lt;a href="https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.take"&gt;take&lt;/a&gt;(N)&lt;/span&gt; idiom is a little more idiot-proof than the equivalent code in the C++ version, as we know it returns early if there are fewer than N items.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;While modern C++ lets a careful programmer write a good program, it still lets a less-careful programmer do things in ways that create errors. Rust has less of that: it will nag you to cover corner cases more carefully.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Rust doesn't make it magically easier to avoid that TTCTTOU problem - it would have been just as easy to write the code using &lt;span style="font-family: courier;"&gt;&lt;a href="https://doc.rust-lang.org/std/fs/fn.metadata.html"&gt;std::fs::metadata(path)&lt;/a&gt;&lt;/span&gt; in the same way it was in the C++ version.&amp;nbsp; But it does improve my confidence that were that bug present, the code would have handled the "file doesn't exist" problem. But it still would have opened a special file or directory with aplomb.&lt;br /&gt;&lt;br /&gt;It's also very easy to convert to a multithreaded program:&amp;nbsp; Just turn the for x in ... loop into a for_each, and use the &lt;a href="https://github.com/rayon-rs/rayon"&gt;Rayon&lt;/a&gt; crate &lt;span style="font-family: courier;"&gt;.par_bridge()&lt;/span&gt; to cause the function in for_each to be executed in parallel.&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;div&gt;&lt;div&gt;    globwalk::&lt;span style="color: #dcdcaa;"&gt;glob&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"*.txt"&lt;/span&gt;)?&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;::ok)&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(|dirent| std::fs::File::&lt;span style="color: #dcdcaa;"&gt;open&lt;/span&gt;(dirent.&lt;span style="color: #dcdcaa;"&gt;path&lt;/span&gt;()).&lt;span style="color: #dcdcaa;"&gt;ok&lt;/span&gt;())&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter&lt;/span&gt;(|file| {&lt;/div&gt;&lt;div&gt;            file.&lt;span style="color: #dcdcaa;"&gt;metadata&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;and_then&lt;/span&gt;(|md| Ok(md.&lt;span style="color: #dcdcaa;"&gt;is_file&lt;/span&gt;()))&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;unwrap_or&lt;/span&gt;(&lt;span style="color: #569cd6;"&gt;false&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;        })&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;par_bridge&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;for_each&lt;/span&gt;(|file| {&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Of course, that won't compile, because we've forgotten to use any locking on the hash table into which we're inserting counts:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span style="font-family: courier;"&gt;error[E0596]: cannot borrow `wordcounts` as mutable, as it is a captured variable in a `Fn` closure&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span style="font-family: courier;"&gt;&amp;nbsp; --&amp;gt; src/main.rs:25:22&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span style="font-family: courier;"&gt;&amp;nbsp; &amp;nbsp;|&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span style="font-family: courier;"&gt;25 |&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;*wordcounts.entry(w).or_insert(0) += 1;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;span style="font-family: courier;"&gt;&amp;nbsp; &amp;nbsp;|&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ^^^^^^^^^^ cannot borrow as mutable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;So then we either switch it to a parallel hash table, or we guard it with a mutex. I'll take the simple approach of locking the table before using it, and do just enough optimization to make it faster than the single-threaded version. In this case, I parse each line into lowercased-words, which I store in a vector, before locking the hash table and then bulk-inserting the line's worth of words:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;div&gt;&lt;div style="color: #d4d4d4;"&gt;&lt;div style="line-height: 18px;"&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; anyhow::&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; lazysort::SortedBy;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; rayon::prelude::*;                                                 // NEW&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; std::collections::HashMap;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; std::io::prelude::*;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;fn&lt;/span&gt; &lt;span style="color: #dcdcaa;"&gt;scanfiles&lt;/span&gt;() -&amp;gt; &lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;&amp;lt;()&amp;gt; {&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;mut&lt;/span&gt; wordcounts = HashMap::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;();&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; wordcounts_locked = std::sync::Mutex::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(&amp;amp;&lt;span style="color: #569cd6;"&gt;mut&lt;/span&gt; wordcounts);     // NEW&lt;/div&gt;&lt;br /&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; words = regex::Regex::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;r"([a-zA-Z]{2,})"&lt;/span&gt;)?;&lt;/div&gt;&lt;div&gt;    globwalk::&lt;span style="color: #dcdcaa;"&gt;glob&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"*.txt"&lt;/span&gt;)?&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;::ok)&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(|dirent| std::fs::File::&lt;span style="color: #dcdcaa;"&gt;open&lt;/span&gt;(dirent.&lt;span style="color: #dcdcaa;"&gt;path&lt;/span&gt;()).&lt;span style="color: #dcdcaa;"&gt;ok&lt;/span&gt;())&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter&lt;/span&gt;(|file| {&lt;/div&gt;&lt;div&gt;            file.&lt;span style="color: #dcdcaa;"&gt;metadata&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;and_then&lt;/span&gt;(|md| Ok(md.&lt;span style="color: #dcdcaa;"&gt;is_file&lt;/span&gt;()))&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;unwrap_or&lt;/span&gt;(&lt;span style="color: #569cd6;"&gt;false&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;        })&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;par_bridge&lt;/span&gt;()                                                   // NEW&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;for_each&lt;/span&gt;(|file| {                                              // CHANGED&lt;/div&gt;&lt;div&gt;            &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; reader = std::io::BufReader::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(file);&lt;/div&gt;&lt;div&gt;            &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; line &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; reader.&lt;span style="color: #dcdcaa;"&gt;lines&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;::ok) {&lt;/div&gt;&lt;div&gt;                &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; wordlist: &lt;span style="color: #4ec9b0;"&gt;Vec&lt;/span&gt;&amp;lt;&lt;span style="color: #4ec9b0;"&gt;String&lt;/span&gt;&amp;gt; = words                       // NEW DESIGN&lt;/div&gt;&lt;div&gt;                    .&lt;span style="color: #dcdcaa;"&gt;captures_iter&lt;/span&gt;(&amp;amp;line)&lt;/div&gt;&lt;div&gt;                    .&lt;span style="color: #dcdcaa;"&gt;map&lt;/span&gt;(|w| w[&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;].&lt;span style="color: #dcdcaa;"&gt;to_lowercase&lt;/span&gt;())&lt;/div&gt;&lt;div&gt;                    .&lt;span style="color: #dcdcaa;"&gt;collect&lt;/span&gt;();&lt;/div&gt;&lt;div&gt;                &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;mut&lt;/span&gt; wordcounts = wordcounts_locked.&lt;span style="color: #dcdcaa;"&gt;lock&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;unwrap&lt;/span&gt;();&lt;/div&gt;&lt;div&gt;                &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; w &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; wordlist {&lt;/div&gt;&lt;div&gt;                    *wordcounts.&lt;span style="color: #dcdcaa;"&gt;entry&lt;/span&gt;(w).&lt;span style="color: #dcdcaa;"&gt;or_insert&lt;/span&gt;(&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;) += &lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;                }&lt;/div&gt;&lt;div&gt;            }&lt;/div&gt;&lt;div&gt;        });&lt;/div&gt;&lt;br /&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; words_sorted = wordcounts.&lt;span style="color: #dcdcaa;"&gt;iter&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;sorted_by&lt;/span&gt;(|a, b| b.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;.&lt;span style="color: #dcdcaa;"&gt;cmp&lt;/span&gt;(a.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;));&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; kv &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; words_sorted.&lt;span style="color: #dcdcaa;"&gt;take&lt;/span&gt;(&lt;span style="color: #b5cea8;"&gt;10&lt;/span&gt;) {&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #dcdcaa;"&gt;println!&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"{} {}"&lt;/span&gt;, kv.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;, kv.&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;);&lt;/div&gt;&lt;div&gt;    }&lt;/div&gt;&lt;div&gt;    Ok(())&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;fn&lt;/span&gt; &lt;span style="color: #dcdcaa;"&gt;main&lt;/span&gt;() {&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #c586c0;"&gt;if&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; Err(e) = &lt;span style="color: #dcdcaa;"&gt;scanfiles&lt;/span&gt;() {&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #dcdcaa;"&gt;println!&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"Error:  Something unexpected happened: {:#?}"&lt;/span&gt;, e);&lt;/div&gt;&lt;div&gt;    }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;span style="color: #d4d4d4;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Not bad - about ten lines of code changed to make a basic parallel version of the code.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;There are some advantages to the C++ version that reflect the immaturity of the Rust standard library.&amp;nbsp; It was able to easily use a partial_sort to reduce the amount of work done sorting by counts; I had to find the lazysort crate, which isn't part of the standard library, which does the same thing.&amp;nbsp;&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Both are fast; depending on the C++ compiler, the rust one may or may not be faster.&amp;nbsp; (&lt;b&gt;Updated&lt;/b&gt;:&amp;nbsp; More benchmarks, prompted by @cb321 on hacker news, and switched the benchmark to something easily downloaded:&amp;nbsp; Charles Dickens "&lt;a href="http://www.textfiles.com/etext/AUTHORS/DICKENS/dickens-tale-126.txt"&gt;A Tale of Two Cities&lt;/a&gt;")&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #f6f6ef; font-size: 12px; overflow: auto; padding: 2px; white-space: pre-wrap;"&gt;&lt;code&gt;   - I7-7920HQ, MacOS
       Rust version:  90ms    (rustc 1.47.0 (18bf6b4f0 2020-10-07))
       C++ version:  340ms   (Apple clang version 12.0.0 (clang-1200.0.32.2))

   - Xeon(R) Gold 6130  (skylake, Ubuntu 20.04)
      Rust:  76ms  (rustc-1.47.0)
      C++:  60ms   (gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2)), -O3, no PGO&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;With a lot of larger files, the parallel version can wordcount four 2mb sample files in 0.307 seconds using a quad-core CPU - not quite linear scaling, but not bad for a few minutes of tweaking.&amp;nbsp; The single-threaded C++ version, meanwhile, is stuck taking about 3.55 seconds on MacOS.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Despite its shorter length, the Rust version probably took me longer to write than the C++ version would have.&amp;nbsp; I had to spend more time figuring out what functions returned so I could handle their possible return types, and had to spend a bit more time googling for things like the filesystem metadata, probably because I'm newer to the language. But making it correct and making it parallel took &lt;i&gt;less&lt;/i&gt;&amp;nbsp;time, even though I'm less experienced in the language. I'll take that tradeoff in a lot of what I do.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;-------&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Update:&amp;nbsp; Some good feedback from burntsushi about the unnecessary use of globwalk introducing a lot of extra dependencies.&amp;nbsp; This is a good point about the risks of making it too easy to use random crates off of github -- or, perhaps, about the dangers inherent in having a less-fully-fledged stdlib.&amp;nbsp; An updated version of the code that's faster to compile is:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; anyhow::&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; lazysort::SortedBy;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; rayon::prelude::*;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; std::collections::HashMap;&lt;/div&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;use&lt;/span&gt; std::io::prelude::*;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;fn&lt;/span&gt; &lt;span style="color: #dcdcaa;"&gt;scanfiles&lt;/span&gt;() -&amp;gt; &lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;&amp;lt;()&amp;gt; {&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;mut&lt;/span&gt; wordcounts = HashMap::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;();&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; wordcounts_locked = std::sync::Mutex::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(&amp;amp;&lt;span style="color: #569cd6;"&gt;mut&lt;/span&gt; wordcounts);&lt;/div&gt;&lt;br /&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; words = regex::Regex::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;r"([a-zA-Z]{2,})"&lt;/span&gt;)?;&lt;/div&gt;&lt;div&gt;    walkdir::WalkDir::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"."&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;into_iter&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;::ok)&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter&lt;/span&gt;(|dirent| dirent.&lt;span style="color: #dcdcaa;"&gt;path&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;extension&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;and_then&lt;/span&gt;(std::ffi::OsStr::to_str) == Some(&lt;span style="color: #ce9178;"&gt;"txt"&lt;/span&gt;))&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(|dirent| std::fs::File::&lt;span style="color: #dcdcaa;"&gt;open&lt;/span&gt;(dirent.&lt;span style="color: #dcdcaa;"&gt;path&lt;/span&gt;()).&lt;span style="color: #dcdcaa;"&gt;ok&lt;/span&gt;())&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;filter&lt;/span&gt;(|file| {&lt;/div&gt;&lt;div&gt;            file.&lt;span style="color: #dcdcaa;"&gt;metadata&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;and_then&lt;/span&gt;(|md| Ok(md.&lt;span style="color: #dcdcaa;"&gt;is_file&lt;/span&gt;()))&lt;/div&gt;&lt;div&gt;                .&lt;span style="color: #dcdcaa;"&gt;unwrap_or&lt;/span&gt;(&lt;span style="color: #569cd6;"&gt;false&lt;/span&gt;)&lt;/div&gt;&lt;div&gt;        })&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;par_bridge&lt;/span&gt;()&lt;/div&gt;&lt;div&gt;        .&lt;span style="color: #dcdcaa;"&gt;for_each&lt;/span&gt;(|file| {&lt;/div&gt;&lt;div&gt;            &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; reader = std::io::BufReader::&lt;span style="color: #dcdcaa;"&gt;new&lt;/span&gt;(file);&lt;/div&gt;&lt;div&gt;            &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; line &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; reader.&lt;span style="color: #dcdcaa;"&gt;lines&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;filter_map&lt;/span&gt;(&lt;span style="color: #4ec9b0;"&gt;Result&lt;/span&gt;::ok) {&lt;/div&gt;&lt;div&gt;                &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; wordlist: &lt;span style="color: #4ec9b0;"&gt;Vec&lt;/span&gt;&amp;lt;&lt;span style="color: #4ec9b0;"&gt;String&lt;/span&gt;&amp;gt; = words&lt;/div&gt;&lt;div&gt;                    .&lt;span style="color: #dcdcaa;"&gt;captures_iter&lt;/span&gt;(&amp;amp;line)&lt;/div&gt;&lt;div&gt;                    .&lt;span style="color: #dcdcaa;"&gt;map&lt;/span&gt;(|w| w[&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;].&lt;span style="color: #dcdcaa;"&gt;to_lowercase&lt;/span&gt;())&lt;/div&gt;&lt;div&gt;                    .&lt;span style="color: #dcdcaa;"&gt;collect&lt;/span&gt;();&lt;/div&gt;&lt;div&gt;                &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;mut&lt;/span&gt; wordcounts = wordcounts_locked.&lt;span style="color: #dcdcaa;"&gt;lock&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;unwrap&lt;/span&gt;();&lt;/div&gt;&lt;div&gt;                &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; w &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; wordlist {&lt;/div&gt;&lt;div&gt;                    *wordcounts.&lt;span style="color: #dcdcaa;"&gt;entry&lt;/span&gt;(w).&lt;span style="color: #dcdcaa;"&gt;or_insert&lt;/span&gt;(&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;) += &lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;;&lt;/div&gt;&lt;div&gt;                }&lt;/div&gt;&lt;div&gt;            }&lt;/div&gt;&lt;div&gt;        });&lt;/div&gt;&lt;br /&gt;&lt;div&gt;    &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; words_sorted = wordcounts.&lt;span style="color: #dcdcaa;"&gt;iter&lt;/span&gt;().&lt;span style="color: #dcdcaa;"&gt;sorted_by&lt;/span&gt;(|a, b| b.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;.&lt;span style="color: #dcdcaa;"&gt;cmp&lt;/span&gt;(a.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;));&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #c586c0;"&gt;for&lt;/span&gt; kv &lt;span style="color: #c586c0;"&gt;in&lt;/span&gt; words_sorted.&lt;span style="color: #dcdcaa;"&gt;take&lt;/span&gt;(&lt;span style="color: #b5cea8;"&gt;10&lt;/span&gt;) {&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #dcdcaa;"&gt;println!&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"{} {}"&lt;/span&gt;, kv.&lt;span style="color: #b5cea8;"&gt;1&lt;/span&gt;, kv.&lt;span style="color: #b5cea8;"&gt;0&lt;/span&gt;);&lt;/div&gt;&lt;div&gt;    }&lt;/div&gt;&lt;div&gt;    Ok(())&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="color: #569cd6;"&gt;fn&lt;/span&gt; &lt;span style="color: #dcdcaa;"&gt;main&lt;/span&gt;() {&lt;/div&gt;&lt;div&gt;    &lt;span style="color: #c586c0;"&gt;if&lt;/span&gt; &lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; Err(e) = &lt;span style="color: #dcdcaa;"&gt;scanfiles&lt;/span&gt;() {&lt;/div&gt;&lt;div&gt;        &lt;span style="color: #dcdcaa;"&gt;println!&lt;/span&gt;(&lt;span style="color: #ce9178;"&gt;"Error:  Something unexpected happened: {:#?}"&lt;/span&gt;, e);&lt;/div&gt;&lt;div&gt;    }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Dave's Data</author><pubDate>Mon, 19 Oct 2020 00:31:18 GMT</pubDate><guid isPermaLink="true">https://da-data.blogspot.com/2020/10/no-c-still-isnt-cutting-it.html</guid></item><item><title>Firefly III monthly summary emails</title><link>https://github.com/davidschlachter/firefly-iii-email-summary</link><description>Self-hosted budgeting software firefly-iii doesn't have an email reports feature. I missed this from Mint and re-implemented it with the API.</description><author>David Schlachter</author><pubDate>Sun, 18 Oct 2020 19:59:00 GMT</pubDate><guid isPermaLink="true">https://github.com/davidschlachter/firefly-iii-email-summary</guid></item><item><title>Tolerating two years of a pandemic in no easy (but some manageable) steps</title><link>https://da-data.blogspot.com/2020/03/tolerating-two-years-of-pandemic-in-no.html</link><description>First off, a reminder:&amp;nbsp; Don't listen to random or not-so-random people like me when it comes to predictions about the spread and danger of COVID-19.&amp;nbsp; Listen to the epidemiologists.&amp;nbsp; I suggest starting with:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://www.imperial.ac.uk/mrc-global-infectious-disease-analysis/news--wuhan-coronavirus/"&gt;Imperial College London team&lt;/a&gt;, who've done groundbreaking work on previous coronaviruses including SARS and MERS.&amp;nbsp; It's an experienced, all-star team.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/trvrb"&gt;Trevor Bedford's twitter feed &lt;/a&gt;is full of great stuff tracing the path of the coronavirus in Seattle.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/AdamJKucharski"&gt;Adam Kucharski&lt;/a&gt; et al. at the London School of Hygiene &amp;amp; Tropical Medicine;&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.medrxiv.org/search/Althaus"&gt;work from Christian Althaus's group &lt;/a&gt;at the Institute for Social and Preventative Medicine&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/HelenBranswell"&gt;Helen Branswell's reporting on the subject&lt;/a&gt; is accurate and lucid.&lt;/li&gt;
&lt;/ul&gt;
My goal here is to lay out the case that:&amp;nbsp; (1)&amp;nbsp; It's worth doing our collective best at minimizing social contact for a while; and that (2)&amp;nbsp; It won't be as bad in the long run, due to a combination of social and technical factors.&amp;nbsp; In other words, we'll get through this, but minimizing the pain requires us to be smart &lt;i&gt;now.&amp;nbsp;&lt;/i&gt;&amp;nbsp;I'm writing this up because I found myself repeating the same fragments of this discussion in various social media, and it seemed like it would make more sense to put it all together.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Background:&amp;nbsp; Social distancing, isolation, and all the rest can save a lot of lives&lt;/b&gt;.&amp;nbsp; Don't take my word for it, &lt;a href="https://www.imperial.ac.uk/media/imperial-college/medicine/sph/ide/gida-fellowships/Imperial-College-COVID19-NPI-modelling-16-03-2020.pdf"&gt;read the ICL report&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
But when you read that report, you'll notice something interesting.&amp;nbsp; It's possible that when we try to finish the big part of social distancing, the virus just returns nearly as bad as before:&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx-oMCUGUOgLIj4ycuWjH3qmDTKrARyJtiPLu46OealYbVlTL1IQeTkKE4BvBfBHhmPosVAhYjCYOeMGaIQXdW3kCq7yYiYxmjaOQAk77GJE_HmBeaMnMqHfSUhmier8mFCkNZewKqpm8/s1600/Screenshot+2020-03-21+14.30.37.png" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx-oMCUGUOgLIj4ycuWjH3qmDTKrARyJtiPLu46OealYbVlTL1IQeTkKE4BvBfBHhmPosVAhYjCYOeMGaIQXdW3kCq7yYiYxmjaOQAk77GJE_HmBeaMnMqHfSUhmier8mFCkNZewKqpm8/s400/Screenshot+2020-03-21+14.30.37.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Figure 3A reprinted from the ICL report.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
I'm going to argue that we'll get through that, because of substantial changes we'll be able to make over the medium term to handle it.&amp;nbsp; Some of this is taken from a series of &lt;a href="https://twitter.com/dave_andersen/status/1238889267197349888"&gt;tweets from me a week ago&lt;/a&gt;, is further bolstered by &lt;a href="https://twitter.com/trvrb/status/1240444821593944064"&gt;tweets from Trevor Bedford&lt;/a&gt;, and includes some material beyond that.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-size: large;"&gt;Why will this get better, and when?&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;
Advance 1:&amp;nbsp; Testing&lt;/h3&gt;
&lt;div&gt;
Over the coming weeks to months, we're going to make reasonably good progress in increasing the ease of testing.&amp;nbsp; The US got off to a terrible start on this, which has crippled our ability to use an isolation-based strategy, but eventually, things will catch up.&amp;nbsp; We'll see several improvements:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Testing phase 0:&amp;nbsp; &lt;b&gt;Insufficient testing to even measure a substantial fraction of cases&lt;/b&gt;.&amp;nbsp; It's reasonable to estimate &lt;a href="https://twitter.com/trvrb/status/1238290215178887169"&gt;that as of a week ago, the US had 10x more cases than we were able to measure&lt;/a&gt;.&amp;nbsp; Just a week ago, the state of Pennsylvania had tested 252 people, identifying 47 positives.&amp;nbsp; Today, we've tested 4137 people, finding 371 positives.&amp;nbsp; To put that in context, the state has about 12 million residents, so we've tested about 1 in 2900 people.&amp;nbsp; At the outset, testing latency was about 3 days to get results.&amp;nbsp; Some tests now have the latency down to a matter of hours.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Testing phase 1:&amp;nbsp; &lt;b&gt;Sufficient testing to measure the true prevalence of cases and test all reasonable possibilities.&lt;/b&gt;&amp;nbsp; &amp;nbsp;We're probably going to reach this phase while we're still in a "lockdown" state, so it won't make things easier, but it's a necessary step to being able to exit complete lockdown.&amp;nbsp; Without accurately understanding the local and national prevalence of the disease, we can't make good decisions.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Future advance:&amp;nbsp; &lt;b&gt;Serum antibody tests to tell if someone has already had the disease.&lt;/b&gt;&amp;nbsp; This may be particularly important for health care workers, food chain workers, etc.&amp;nbsp; We don't yet have hard data on how immunity behaves with COVID-19, but it's reasonable to think there will be some for at least a limited period of time.&amp;nbsp; Once you've had it, you're probably clear to go back to work.&amp;nbsp; There may be people who had low-symptomatic or asymptomatic cases who we can clear but didn't test (see above), so a serum antibody test that can measure whether you've been previously infected can be valuable for helping repopulate the workforce, particularly for some of the highest-risk jobs.&amp;nbsp; [Example:&amp;nbsp; &lt;a href="https://www.businessinsider.com/healthcare-workers-getting-coronavirus-500-infected-2020-2"&gt;Health care workers are at substantially higher risk of contracting the virus]&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Future advance:&amp;nbsp; &lt;b&gt;Widespread, cheap testing &lt;a href="https://www.nytimes.com/2020/03/20/world/europe/coronavirus-testing-world-countries-cities-states.html"&gt;akin to that in Singapore and South Korea&lt;/a&gt;.&lt;/b&gt;&amp;nbsp; When people with nearly any symptoms can get tested, it may become possible to engage in much more careful isolation of confirmed cases, while allowing more limited interaction between the healthy, combined with aggressive contact tracing.&amp;nbsp; Trevor Bedford's tweets laid this out well, but South Korea's success in containment is a good example of this, keeping in mind that there is still very substantial restriction on contact there:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;img alt="Image" height="167" src="https://pbs.twimg.com/media/ETbwpTSUcAAv_ou?format=png&amp;amp;name=large" width="400" /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Future advance:&amp;nbsp; &lt;b&gt;Cheap testing at home&lt;/b&gt;.&amp;nbsp; If it's possible to test every member of your family daily, we can probably let people go out on their business much more than we can now.&amp;nbsp; This obviously requires substantial cost-reduction and throughput improvement of the testing, and seems farther off than the previous two.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
tl;dr:&amp;nbsp; As testing gets better, we can relax some of the social restrictions.&amp;nbsp; Not all of them, but it opens a middle ground between "don't leave your house" and "go hang out with 5000 people from around the globe at a conference in Boston."&amp;nbsp; Getting to such a middle ground is important for the livelihood of local businesses, particularly those that can't change to remote or delivery models.&amp;nbsp; Resuming, e.g., operating a house cleaning business at the cost of requiring daily coronavirus tests may be feasible, particularly if the tests were free and could be done at home.&lt;br /&gt;
&lt;br /&gt;
Want more?&amp;nbsp; See &lt;a href="https://www.wired.com/story/coronavirus-interview-larry-brilliant-smallpox-epidemiologist/"&gt;this Wired interview with Larry Brilliant&lt;/a&gt;, an epidemiologist who helped eradicate smallpox.&lt;/div&gt;
&lt;h3&gt;
Advance 2:&amp;nbsp; Supplies&lt;/h3&gt;
&lt;div&gt;
One of the reasons we need to flatten the curve is that we have limited supplies of hospital beds, medical personnel, personal protective equipment, and ventilators.&amp;nbsp; Over time, we can begin to address some of these issues.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It takes a while to ramp up manufacturing, even of seemingly simple things like masks.&amp;nbsp; For critically-needed supplies such as masks/PPE and ventilators, we should expect to see two increases in our manufacturing capacity:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Increase 1:&amp;nbsp; &lt;b&gt;Increase the throughput of existing lines by increasing the duty cycle.&lt;/b&gt;&amp;nbsp; By hiring more workers (assuming that the inputs are available), some manufacturers will be able to increase throughput by working additional shifts, up to the point that equipment is running full-time.&amp;nbsp; (Full time, of course, is limited by downtime needed to maintain the equipment, so very little actually runs at a 100% duty cycle.)&amp;nbsp; For example, &lt;a href="https://www.massdevice.com/how-are-u-s-based-ventilator-companies-doing/"&gt;Medtronic announced that they were moving to 24/7 production of ventilators&lt;/a&gt;&amp;nbsp;at their existing facility in Ireland.&amp;nbsp; Similar increases are happening with mask manufacturing and the other equipment components we need.&amp;nbsp; This is the fastest way to increase production, but it's limited:&amp;nbsp; Very few lines were probably running at less than shift per day (~30% of capacity), so we won't get more than a 3x increase in production this way.&amp;nbsp; But that still helps.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Increase 2:&amp;nbsp; &lt;b&gt;Add more manufacturing lines&lt;/b&gt;.&amp;nbsp; Depending on the complexity of the process, building a new line could take from weeks to many months.&amp;nbsp; In some cases we can convert existing lines:&amp;nbsp; Some sewing facilities in China have rapidly switched from clothing to masks, but there are bottlenecks farther up the line, such as the &lt;a href="https://www.npr.org/sections/goatsandsoda/2020/03/16/814929294/covid-19-has-caused-a-shortage-of-face-masks-but-theyre-surprisingly-hard-to-mak"&gt;melt-blown fabric fabricating machines that may take five to six months to build&lt;/a&gt;.&amp;nbsp; While Hanes has rapidly turned around to manufacture masks, they're only able to make three-ply cotton masks, which are less effective than conventional surgical masks.&amp;nbsp; Ventilator manufacturer&amp;nbsp;&lt;a href="https://www.forbes.com/sites/baldwin/2020/03/14/ventilator-maker-we-can-ramp-up-production-five-fold"&gt;Ventec estimates they could go to 5x ventilator production in 3-4 months&lt;/a&gt;.&amp;nbsp; If we ballpark that increasing global critical supply production capacity by a factor of ten will take a year, we're probably in the right range.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The return on this investment is somewhat limited, because it also takes trained personnel to operate ventilators, but we get good advantages from them nonetheless:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Sufficient PPE for health care workers increases the number of available (i.e., not out sick or quarantined) skilled workers;&lt;/li&gt;
&lt;li&gt;Reducing the chances of health care workers spreading the disease to themselves or vulnerable populations is an important part of mitigating the ICU cost of coronavirus cases;&lt;/li&gt;
&lt;li&gt;Having sufficient masks of any sort to create a general culture of mask-wearing in the US is likely to reduce transmission, allowing more going out-and-about at the same transmission rate, particularly in high-density areas such as New York.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
This doesn't buy us unfettered movement, but it lets us tolerate a higher active number of cases at any given time -- i.e., means we don't have to flatten the curve quite as much to achieve the same savings of life.&amp;nbsp; Not having to flatten as much later means that we don't have to impose as many restrictions on people's lives and ability to make a living.&lt;/div&gt;
&lt;h3&gt;
Advance 3:&amp;nbsp; Treatment&lt;/h3&gt;
&lt;div&gt;
The more COVID-19 cases we treat (particularly when we have some breathing room to be deliberate about it), the more we learn about how to do better with future cases.&amp;nbsp; This too will come in several phases:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Phase 1:&amp;nbsp; Best practices&lt;/b&gt;.&amp;nbsp; Easy to develop and fast to communicate, improvements in best practices for management of patients with COVID-19 can help improve the survival rate and reduce hospitalization times.&amp;nbsp; There's no silver bullet here, but it's cheap.&amp;nbsp; Examples of this include the development of specialized drive-through testing, which minimizes patient-to-patient and patient-to-provider contact.&amp;nbsp; More technical examples include the WHO's &lt;a href="https://www.who.int/docs/default-source/coronaviruse/clinical-management-of-novel-cov.pdf"&gt;continually-updated best practices for clinical management of COVID-19 cases&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Phase 2:&amp;nbsp; Pharmaceutical interventions&lt;/b&gt;.&amp;nbsp; There's a lot of breathless discussion out there about whether or not particular drugs or drug combinations can help reduce the extent of symptoms of COVID-19 (or, similarly, the back-and-forth about whether NSAIDs are harmful).&amp;nbsp; The reality is that it's very early for all of these and that it will take substantial more study before we have solid answers.&amp;nbsp; An example is the ongoing &lt;a href="https://www.sciencedirect.com/science/article/pii/S0166354220301145"&gt;evaluation of chloroquine&lt;/a&gt;&amp;nbsp;combination therapy.&amp;nbsp; We don't have anything yet, but we're likely to find things that help.&amp;nbsp; This help likely won't be a panacea either - consider that the most effective &lt;a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5240024/"&gt;antiviral we have against influenza decreases symptoms by about a day&lt;/a&gt;&amp;nbsp;- but every bit helps in combination with the other bits.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Phase 3:&amp;nbsp; A vaccine.&lt;/b&gt;&amp;nbsp; Depending on the efficacy and side effect profile of the vaccine, this could be the end of the discussion, or it could simply massively reduce the cost and deaths associated with the virus.&amp;nbsp; But most experts concur this is 1-2 years out.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Treatment has the same effect as fixing supply limitations:&amp;nbsp; We can tolerate more active cases at a time, i.e., we can lower the cost to people's lives and jobs while keeping as many people from dying.&lt;/div&gt;
&lt;h3&gt;
Advance 4:&amp;nbsp; Societal Changes that Reduce Contact&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
There's a lot of important face-to-face interaction in society, but there's a lot we can get rid of, and we're about to have several months of experimenting with what we can and can't change easily.&amp;nbsp; As a warning, this is the least-baked of everything I'm saying here.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Take, as an example, three models of grocery shopping:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Model 1:&amp;nbsp; Conventional US shopping&lt;/b&gt;.&amp;nbsp; Each customer goes to the grocery store weekly (or whenever).&amp;nbsp; At the grocery store, that customer comes into contact with many of the workers present in the store, as well as the other people shopping at the same time.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Model 2:&amp;nbsp; The Instacart Model.&lt;/b&gt;&amp;nbsp; A specialized delivery service sends shopper/drivers to the store who do the shopping and deliver groceries to the customer.&amp;nbsp; An instacart driver can probably do in the range of 5 shopping trips per day.&amp;nbsp; Over the course of a week, then, this shopper/driver reduces the number of contacts that store employees experience by a factor of 25 (5 replaced shoppers per day).&amp;nbsp; A typical grocery store has in the &lt;a href="https://www.statista.com/statistics/240966/average-weekly-sales-per-us-supermarket-store/"&gt;range of &lt;i&gt;two thousand&lt;/i&gt;&amp;nbsp;customers each week&lt;/a&gt;, putting every employee in contact with hundreds of different people.&amp;nbsp; Moving to model 2 reduces that substantially, but there are still a large number of different shoppers entering the store each day.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Model 3:&amp;nbsp; Store shoppers shop, drivers drive&lt;/b&gt;:&amp;nbsp; In this model, a customer order is picked and packed by employees of the store itself.&amp;nbsp; The store employees then transfer the packed groceries to a driver (who never enters the store and can pick up the groceries from a distance).&amp;nbsp; The driver drops the groceries at the customer's house.&amp;nbsp; In this model, &lt;b&gt;drivers never have customer or employee contact&lt;/b&gt;, and thus never act as a disease conduit from other people to store employees or to customers.&amp;nbsp; Store employees still come into contact with each other regularly, but it's far better to have regular contact with the same smaller group than to have a much larger contact graph.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Other areas may go completely online.&amp;nbsp; Consider that today we have the NASDAQ, an entirely electronic exchange, and we have the NYSE, where traders -- until three days ago -- would physically cluster in a cramped environment.&amp;nbsp; The &lt;a href="https://www.cnbc.com/2020/03/18/nyse-to-temporarily-close-trading-floor-move-to-electronic-trading-because-of-coronavirus.html"&gt;NYSE has temporarily gone electronic-only&lt;/a&gt; (which probably won't change much), and I suspect it won't go back.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This great collective experiment we're doing in remote-everything is likely to yield other changes that let us continue to get things done with reduced chances for viral transmission and/or travel.&amp;nbsp; When this is all done, I'm not going to fly to another in-person program committee meeting to referee scientific papers.&amp;nbsp; I'm done with it - I love my colleagues and love the opportunities to chat research, but it's unnecessary travel and by the end of this we'll have perfected on-line paper discussions and program committee meetings.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I don't want to paint too happy a picture for this.&amp;nbsp; There are changes that are going to be absolutely destructive to people's jobs and income -- &lt;a href="https://www.washingtonpost.com/business/2020/03/19/unemployment-insurance-today-coronavirus/"&gt;unemployment claims are skyrocketing&lt;/a&gt;, and industries such as hospitality are going to be very, very deeply hurt, and these are things that won't be fixed by modest social changes.&amp;nbsp; That's going to take concerted government response at a scale we haven't seen since the great depression.&amp;nbsp; There are other people for whom the critical nature of their jobs, from food production to healthcare, will require them to continue working with other people and suffer an increased risk of catching coronavirus, and we we need to ensure there's support in place for them.&amp;nbsp; But there &lt;i&gt;are&lt;/i&gt;&amp;nbsp;things that will improve life for all of us as we make it through this pandemic, and we get the most benefit from them if we can minimize the spread of the disease for a period of months.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
As more people have passed through the disease and gain immunity, as we roll out more and more testing, as we reduce the case fatality rate through better interventions, and as we reduce the amount of "low-importance" social contact, we'll be able to &lt;i&gt;increase&lt;/i&gt;&amp;nbsp;the amount of high-value social contact we allow ourselves.&amp;nbsp; But with the extent of spread in the US already, this is likely to be a game we play out over months to two years, with possible seasonal ebbs and flows.&amp;nbsp; But we'll come through it better-equipped to handle future pandemics (and reduce the chances of them going pandemic).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;</description><author>Dave's Data</author><pubDate>Sun, 18 Oct 2020 16:28:03 GMT</pubDate><guid isPermaLink="true">https://da-data.blogspot.com/2020/03/tolerating-two-years-of-pandemic-in-no.html</guid></item><item><title>Updates on factors that will ease living with a coronavirus pandemic</title><link>https://da-data.blogspot.com/2020/04/updates-on-factors-that-will-ease.html</link><description>Three weeks ago, I posted about&amp;nbsp;&lt;a href="https://da-data.blogspot.com/2020/03/tolerating-two-years-of-pandemic-in-no.html"&gt;things that will help us loosen restrictions as we move forward through the coronavirus pandemic&lt;/a&gt;.&amp;nbsp; In this post, I'm following up on a few of those in the form of a progress tracker.&lt;br /&gt;
&lt;h3&gt;
Testing&lt;/h3&gt;
&lt;div&gt;
&lt;b&gt;PCR viral tests&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
March 23, 2020:&amp;nbsp; 58,500 tests/day&lt;/div&gt;
&lt;div&gt;
Apr 14, 2020:&amp;nbsp; 145,000 tests/day.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Source:&amp;nbsp;&amp;nbsp;&lt;a href="https://covidtracking.com/data/us-daily"&gt;https://covidtracking.com/data/us-daily&lt;/a&gt;&lt;br /&gt;
Taken as the average of a 5 day window centered around the date of concern.&lt;/div&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN01UWgmPh6i8LlZF3XlfIBZZTnTXhpnpB9XqDo3wD1YWkWeF2gi22-RE03raBJimzoB45DrQ805NZRk3eKR3gAw0o2bQFyPLBW4QqsP3DxeG_XH47Wa3XFUv8kv30deu9qly9aB0dduw/s1600/testsday.png" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN01UWgmPh6i8LlZF3XlfIBZZTnTXhpnpB9XqDo3wD1YWkWeF2gi22-RE03raBJimzoB45DrQ805NZRk3eKR3gAw0o2bQFyPLBW4QqsP3DxeG_XH47Wa3XFUv8kv30deu9qly9aB0dduw/s400/testsday.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;SARS-CoV-2 tests per day&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div&gt;
As with all things, test availability is subject to multiple bottlenecks.&amp;nbsp; It takes swabs, PCR reagents, PPE for the people doing the tests, machines on which to run tests, trained personnel, etc.&amp;nbsp; The manufacturing and supply of all of these can take time to spin up. We're not yet to the point where we can test all likely cases, but we're running about 2.4x as many tests as we were three weeks ago.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This is not enough.&amp;nbsp; Estimates vary widely, but one Harvard study suggests we may need in the &lt;a href="https://drive.google.com/file/d/1EhUfmT6ayG3ERxX-wZUmB2wtIEOhRAmP/view?"&gt;millions of tests per day&lt;/a&gt; range.&amp;nbsp; Others put the numbers in the high hundreds of thousands per day, but no matter what, we need at least to go 5x where we are now.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Serum antibody tests&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
Serum antibody tests are starting to roll out.&amp;nbsp; The&amp;nbsp;&lt;a href="https://www.nih.gov/news-events/news-releases/nih-begins-study-quantify-undetected-cases-coronavirus-infection"&gt;NIH has started a study to quantify the true prevalence of cases&lt;/a&gt;.&amp;nbsp;&amp;nbsp;&lt;a href="https://techcrunch.com/2020/03/27/the-fda-just-okayed-multiple-15-minute-blood-tests-to-screen-for-coronavirus-but-there-are-caveats/"&gt;Several commercial test providers have created tests and they are available&lt;/a&gt;&amp;nbsp;(at high cost) in some areas in limited quantities.&amp;nbsp; They're not yet playing a big role but I expect that they'll begin to within a month.&amp;nbsp; As an example, UW Virology in Seattle is &lt;a href="https://twitter.com/UWVirology/status/1250535728330633217"&gt;hoping to begin 1000 tests/day next week&lt;/a&gt;.&amp;nbsp; Stanford &lt;a href="http://med.stanford.edu/news/all-news/2020/04/stanford-medicine-develops-antibody-test-for-coronavirus.html"&gt;is testing 500 per day&lt;/a&gt; now.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
As a warning, of course, the false positive and false negative rates on these tests are too high for them to be used alone for purposes such as "certify that I am immune to covid-19".&amp;nbsp; For example, the Cellex test is somewhere in the 95% range, which means that for every 100 people who have never had coronavirus, the test will tell 5 of them it has.&amp;nbsp; That's higher than the expected fraction of people in the US who have been infected thus far, which means that if the test says you've had it you ... might have had it.&amp;nbsp; So for the coming month, at least, the value of these tests is primarily to help understand the spread (and infection fatality rate) of the disease better, but that understanding is critical to crafting policy on how to respond to it.&amp;nbsp; But for individual benefit, more improvements and more data sources are needed.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Supplies&lt;/h3&gt;
&lt;div&gt;
This is hard to quantify;&amp;nbsp; data is limited and messy.&amp;nbsp; Some anecdotes but not overall numbers:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;3m&amp;nbsp;&lt;a href="https://www.marketwatch.com/story/3m-ceo-says-company-has-doubled-global-production-of-n95-masks-to-nearly-100-million-a-month-2020-03-23"&gt;says it has doubled N95 production&lt;/a&gt;&amp;nbsp;to 100 million / month, with 35M/month in the US.&lt;/li&gt;
&lt;li&gt;Together with smaller manufacturers, that&amp;nbsp;&lt;a href="https://www.wsj.com/articles/3m-ceo-on-n95-masks-demand-exceeds-our-production-capacity-11585842928"&gt;has us up to about 50M per month.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wsj.com/articles/3m-ceo-on-n95-masks-demand-exceeds-our-production-capacity-11585842928"&gt;But DHHS estimates we need 300M masks / month&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;a href="https://www.cbsnews.com/news/n95-mask-shortage-melt-blown-filters/"&gt;Melt-blown poly continues to be one of the key bottlenecks&lt;/a&gt;, which as I noted a few weeks ago, may take several months to ramp up supply.&amp;nbsp; N95s are not the only masks we need, and other manufacturers are bottlenecked by other components, such as elastic, when making ASTM level 1 and 2 masks (standard procedure masks).&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Relations between the US and China are an important factor in mask availability, which may&amp;nbsp;&lt;a href="https://www.npr.org/sections/coronavirus-live-updates/2020/03/29/823543513/project-airbridge-to-expedite-arrival-of-needed-supplies-white-house-says"&gt;hopefully be improving for medical supply shipments&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This is all a long-winded way of saying we're better, we're not better enough, and it's going to be at least several months before we're up to speed on this one, but it's helped by...&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Progress in reusing masks&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
There have been several independent efforts to start reusing masks, and these are entering real deployment.&amp;nbsp; For more information here, see&amp;nbsp;&lt;a href="https://www.n95decon.org/"&gt;https://www.n95decon.org/&lt;/a&gt;.&amp;nbsp; As one example, see&amp;nbsp;&lt;a href="https://www.nbcnews.com/health/health-news/dinner-table-chat-between-husband-wife-may-help-solve-coronavirus-n1183716"&gt;Battelle's 80k masks/day (theoretical) decontamination system&lt;/a&gt;.&amp;nbsp; There are a few of these in deployment now, so we might expect them to reduce N95 mask demand by a million or two masks per month.&amp;nbsp; As they&amp;nbsp;&lt;a href="https://abc6onyourside.com/news/local/pentagon-signs-415-million-contract-with-battelle-to-decontaminate-n95-masks"&gt;ramp up production&lt;/a&gt;&amp;nbsp;(and these are fairly easy to build), they could conceivably reduce demand by something like 50M masks per month by the end of May.&amp;nbsp; That's equivalent to doubling our current mask production, which is a great start.&amp;nbsp; Other hospital systems are deploying UV or heat-based mask sanitization.&amp;nbsp; But we need all of these and more to meet demand, and it won't happen overnight.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
(Calculation note:&amp;nbsp; I've de-rated the decontamination system throughput to 25k masks/day sustained for this calculation to be conservative about the effective duty cycle and the fact that it's likely hard to keep the system perfectly balanced as far as masks available to clean at all times.&amp;nbsp; In theory the 60 machines ordered for HHS could top 100M mask reuses/month).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
But in total, this means that over the course of 3 months, we'll have increased "effective mask production" fourfold, with more increases possible in the subsequent 3 months.&lt;/div&gt;
&lt;h3&gt;
Treatment&lt;/h3&gt;
&lt;div&gt;
Three weeks is basically no time in terms of drug development and testing with humans, so very little new to say here.&amp;nbsp; Testing in humans takes time, and even with a lot of emergency leeway, it still takes time.&amp;nbsp; There are more (preliminary and small) studies coming in about hydroxychloroquine combinations that make it clear that it's no wonder drug;&amp;nbsp; it's still up in the air if it helps, but every week that passes we get more data.&amp;nbsp; Data about Remdesivir is still coming in, but is patchy and many of the studies lack a control group, which makes it very hard to say much with certainty.&amp;nbsp; There are&amp;nbsp;&lt;a href="https://www.clinicaltrialsarena.com/analysis/coronavirus-mers-cov-drugs/"&gt;more than a dozen drugs in various stages of development&lt;/a&gt;&amp;nbsp;as either vaccines or therapies.&amp;nbsp; A lot of activity, which is promising for future results, but I don't pretend to have a crystal ball.&lt;/div&gt;
&lt;h3&gt;
Societal Changes that Reduce Contact&lt;/h3&gt;
&lt;div&gt;
This section should probably be called:&amp;nbsp; Go go human adaptability!&amp;nbsp; There have been lots of promising advances here.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;No-contact shopping:&amp;nbsp;&amp;nbsp;&lt;/b&gt;Retailers and delivery services continue to try to optimize for more and more store-packed or delivered grocery service.&amp;nbsp; As with everything, improvements here require process optimizations, infrastructure changes, and hiring more people, all of which&amp;nbsp;&lt;a href="https://www.washingtonpost.com/business/2020/04/15/grocery-delivery-coronavirus/"&gt;will take time&lt;/a&gt;.&amp;nbsp; Instacart reports that orders have quadrupled from a year ago, and &lt;a href="https://www.washingtonpost.com/business/2020/04/15/grocery-delivery-coronavirus/"&gt;says it has doubled its workforce&lt;/a&gt; from 200k to 350k in the last two weeks.&amp;nbsp; Amazon is&amp;nbsp;&lt;a href="https://www.npr.org/sections/coronavirus-live-updates/2020/04/13/833164484/amazon-puts-new-grocery-delivery-customers-on-hold-as-demand-explodes"&gt;reported to have hired 100,000 workers&lt;/a&gt;&amp;nbsp;and is trying to hire another 75,000.&amp;nbsp;&amp;nbsp;Many of the platforms are improving their process:&amp;nbsp; Instacart has added a "fast and flexible" delivery option to help smooth demand and keep drivers busy.&amp;nbsp; Amazon&amp;nbsp;&lt;a href="https://abc7news.com/amazon-fresh-membership-whole-foods-delivery-coronavirus-grocery-service/6099646/"&gt;is reducing in-person store hours at some locations&lt;/a&gt;&amp;nbsp;to facilitate more delivery.&lt;br /&gt;
&lt;br /&gt;
Even in-person shopping is getting on the ball.&amp;nbsp; Some &lt;a href="https://www.thedenverchannel.com/news/coronavirus/kroger-publix-to-install-plexiglass-barriers-between-customers-and-cashiers-amid-coronavirus-spread"&gt;grocery stores are installing plexiglass barriers&lt;/a&gt; to reduce contact between customers and (high contact fan-out) cashiers.&amp;nbsp; Many are upping cleaning schedules, providing sanitizer, and requiring masks.&amp;nbsp; (Of course, this also requires an increase in the manufacturing of sanitizer, but that's happening too).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Masks for all&lt;/b&gt;:&amp;nbsp; There's a&amp;nbsp;&lt;a href="https://masks4all.co/"&gt;growing consensus&lt;/a&gt;&amp;nbsp;that widespread mask wearing can help reduce the spread of coronavirus.&amp;nbsp; (There's also a lot of fighting and nitpicking about it, but this seems to be the median opinion).&amp;nbsp; The CDC has updated its guidelines to suggest that everyone wear a mask when out in public.&amp;nbsp;&amp;nbsp;&lt;a href="https://www.nytimes.com/2020/04/15/nyregion/coronavirus-face-masks-andrew-cuomo.html"&gt;New York now has a mandatory mask law&lt;/a&gt;&amp;nbsp;"when social distancing is not possible."&amp;nbsp; These changes are just coming online, so we can't see their effects yet, but this seems likely to start making progress by a few weeks from now.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Doin' it online:&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;a href="https://www.wgal.com/article/pennsylvania-voters-can-now-apply-online-to-vote-by-mail-in-ballot/30876787"&gt;More states are beefing up their vote-by-mail efforts&lt;/a&gt;.&amp;nbsp; Some are not.&amp;nbsp; Doctors have been getting &lt;a href="https://khn.org/news/telemedicine-surges-fueled-by-coronavirus-fears-and-shift-in-payment-rules/"&gt;increasingly online with providing telemedicine services&lt;/a&gt;, and for some visits, this appears to be working very well.&amp;nbsp; This may have a long-lasting effect in reducing the amount we all go to the doctor's office to share germs with each other.&amp;nbsp; We do need primary care visits to resume, however, because &lt;a href="https://www.nytimes.com/2020/04/13/health/coronavirus-measles-vaccines.html"&gt;data also shows that vaccination prescriptions are down right now&lt;/a&gt; as people can't get physically to their doctors.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Tl;dr:&amp;nbsp; We've made measurable progress for three weeks, but there's a lot more to go before we're near getting things back to normal.&amp;nbsp; I'll try to update this again in a few weeks unless some better site comes online for tracking these things.&lt;/div&gt;</description><author>Dave's Data</author><pubDate>Sun, 18 Oct 2020 16:27:56 GMT</pubDate><guid isPermaLink="true">https://da-data.blogspot.com/2020/04/updates-on-factors-that-will-ease.html</guid></item><item><title>Speeding up fuzzing rust with shared initialization</title><link>https://da-data.blogspot.com/2020/05/speeding-up-fuzzing-rust-with-shared.html</link><description>Having &lt;a href="https://da-data.blogspot.com/2020/05/moving-pi-searcher-from-go-to-rust.html"&gt;ported the Pi searcher to Rust&lt;/a&gt;, I've started exploring fuzzing frameworks to help find bugs.&amp;nbsp; I settled on Rust's &lt;a href="https://github.com/rust-fuzz/cargo-fuzz"&gt;cargo-fuzz&lt;/a&gt;&amp;nbsp;using the libfuzzer backend, since I'm familiar with libfuzzer &lt;a href="https://da-data.blogspot.com/2017/01/finding-bugs-in-tensorflow-with.html"&gt;from using it on TensorFlow&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Naturally, since the Pi Searcher had been comparatively stable for 7 years in Go, and the translation from Go to Rust was fairly straightforward... I introduced a bug that my tests didn't find, and the fuzzer found over dinner:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibuiOmpIXSaCLXNYv1jwMtWZEHegeM1z9cPpmMvFxMiI2YYnt8eQ3gGflonG90CZMNCPE2KHtSFf5EAXr1EHn_-DQNXNahpb2CNhDAJpbLZI8-VCJnxkAgG_oWokX2GW1fxUmn_CWL__M/s1600/Screenshot+2020-05-20+21.52.11.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="178" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibuiOmpIXSaCLXNYv1jwMtWZEHegeM1z9cPpmMvFxMiI2YYnt8eQ3gGflonG90CZMNCPE2KHtSFf5EAXr1EHn_-DQNXNahpb2CNhDAJpbLZI8-VCJnxkAgG_oWokX2GW1fxUmn_CWL__M/s640/Screenshot+2020-05-20+21.52.11.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Whoopsie.&amp;nbsp; That bug arose because of an error in handling the boundary condition of searching for just "9" using the index (which doesn't happen normally because the search function uses a simple sequential search for short strings):&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOwAsI663TfTb8WlMjMWQ1bCohnZfDlWSbqyN8ie35DgO7L1YCILhpFZosYwalGAgANK2qnK2HWw755YyHSmkUtplmQklXPiwwffNT28zDwfDxlkCxQhfBizwvkSxP2vWF1gKXtL33W6E/s1600/Screenshot+2020-05-20+21.53.46.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOwAsI663TfTb8WlMjMWQ1bCohnZfDlWSbqyN8ie35DgO7L1YCILhpFZosYwalGAgANK2qnK2HWw755YyHSmkUtplmQklXPiwwffNT28zDwfDxlkCxQhfBizwvkSxP2vWF1gKXtL33W6E/s400/Screenshot+2020-05-20+21.53.46.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
Here, num_digits is 200 million, but they're stored compressed, so the bug was using the size of the file (100 million bytes), which caused the binary search to return a bad range.&amp;nbsp; Fuzzing is awesome, and adapting the fuzzer to the Pi searcher was straightforward:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh63Kw-TgMHNacxkvpa04euZpKKxCBWCqU8R2e_Md8zc30bO4Ssd2Y_Kfx2GvWSXmshTdFzqeb-sCngy0jJtPO088nj5PL8dgKM7pQDdtN7krGrxanEU6X4TRqd4rcNMrPJ-jq6sl4uiPg/s1600/Screenshot+2020-05-20+21.56.00.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh63Kw-TgMHNacxkvpa04euZpKKxCBWCqU8R2e_Md8zc30bO4Ssd2Y_Kfx2GvWSXmshTdFzqeb-sCngy0jJtPO088nj5PL8dgKM7pQDdtN7krGrxanEU6X4TRqd4rcNMrPJ-jq6sl4uiPg/s400/Screenshot+2020-05-20+21.56.00.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
But one thing that bugged me:&amp;nbsp; Fuzzing was a little slow.&lt;br /&gt;
&lt;br /&gt;
Why was it slow?&amp;nbsp; Every time the fuzz function is run with a new input, it had to instantiate a new PiSearcher.&amp;nbsp; Each PiSearcher opens and memory maps using mmap two files:&amp;nbsp; 100MB of compressed digits of Pi and 800MB of a suffix array index into those bytes.&amp;nbsp; This adds a bunch of unnecessary overhead compared to the relatively fast searching code.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="https://llvm.org/docs/LibFuzzer.html#startup-initialization"&gt;Libfuzzer's documentation&lt;/a&gt; suggests that initialization should use a statically initialized global object.&amp;nbsp; But this is Rust.&amp;nbsp; One does not simply willy-nilly toss around globals.&amp;nbsp; Some quick Googling didn't turn up much useful, so I put it aside, as this was merely a speed optimization.&lt;br /&gt;
&lt;br /&gt;
Fortunately, the most recent "&lt;a href="https://this-week-in-rust.org/blog/2020/05/19/this-week-in-rust-339/"&gt;this week in Rust&lt;/a&gt;" blog pointed to Paul Kernfeld's very useful&amp;nbsp;&lt;a href="https://github.com/paulkernfeld/global-data-in-rust"&gt;Guide to Global Data in Rust&lt;/a&gt;.&amp;nbsp; Which, in turn, linked to the&lt;span style="font-family: Courier New, Courier, monospace;"&gt; &lt;/span&gt;&lt;a href="https://docs.rs/once_cell/1.4.0/once_cell/"&gt;&lt;span style="font-family: Courier New, Courier, monospace;"&gt;once_cell&lt;/span&gt; crate&lt;/a&gt;.&amp;nbsp; Just what the fuzzer ordered!&amp;nbsp; A quick rewrite of the fuzzing target yielded:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw20edzz2ZBHQXZFjEZM6g5sQI4PPa8HC1iaDegqfG4JPShyphenhyphenObVcShmPAyoqnicSyUVALMSMk7rjL0dnfvUmw0fm8-nhxg_FCehgjQ5sXBjL_KvZPneJ9-KvvJ3aK4_ScKgfebbsYUAkM/s1600/carbon+%25285%2529.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="403" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhw20edzz2ZBHQXZFjEZM6g5sQI4PPa8HC1iaDegqfG4JPShyphenhyphenObVcShmPAyoqnicSyUVALMSMk7rjL0dnfvUmw0fm8-nhxg_FCehgjQ5sXBjL_KvZPneJ9-KvvJ3aK4_ScKgfebbsYUAkM/s640/carbon+%25285%2529.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Which allows the (read-only) PiSearcher object to be reused across fuzzing calls.&amp;nbsp; Simple and easy.&lt;br /&gt;
&lt;br /&gt;
How much did this help?&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: Courier New, Courier, monospace;"&gt;&amp;gt; cargo fuzz run coretest&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Debug build (default):&lt;/b&gt;&lt;br /&gt;
Old version (new mmap per function call):&amp;nbsp; 304 tests/second.&lt;br /&gt;
New version (statically initialized PiSeacher):&amp;nbsp; 340 tests/second.&lt;br /&gt;
&lt;br /&gt;
10% is nice and all, but that's not a particularly large gain.&amp;nbsp; But wait - that's very slow compared to the normal speed of the Pi searcher.&amp;nbsp; Ahh, yes:&amp;nbsp; cargo fuzz builds debug mode by default.&amp;nbsp; Let's try release, keeping in mind that coverage may not be quite as good (but with the speed gains, it's probably worth it):&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-family: Courier New, Courier, monospace;"&gt;&amp;gt; cargo fuzz run coretest --release --jobs 4&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Release build, 4 jobs:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;Old version:&amp;nbsp; 10800&lt;br /&gt;
New version&amp;nbsp; &amp;nbsp;&amp;nbsp;26050&lt;br /&gt;&lt;br /&gt;
Not bad - 10% in debug mode and almost 2.5x faster in release mode with multiple jobs.&amp;nbsp; Thanks, &lt;span style="font-family: Courier New, Courier, monospace;"&gt;once_cell&lt;/span&gt;!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</description><author>Dave's Data</author><pubDate>Sun, 18 Oct 2020 16:27:50 GMT</pubDate><guid isPermaLink="true">https://da-data.blogspot.com/2020/05/speeding-up-fuzzing-rust-with-shared.html</guid></item><item><title>Moving the Pi Searcher from Go to Rust</title><link>https://da-data.blogspot.com/2020/05/moving-pi-searcher-from-go-to-rust.html</link><description>Seven years ago (almost to the date), I wrote about &lt;a href="https://da-data.blogspot.com/2013/05/improving-pi-searchers-speed-by-moving.html"&gt;my experience moving the Pi Searcher from C++ to Go&lt;/a&gt;.&amp;nbsp; In that article, I mentioned that while the core searching code got slower, the system as a whole sped up by avoiding the per-request fork overhead of the earlier CGI-based code.&lt;br /&gt;
&lt;br /&gt;
This year I moved the &lt;a href="https://www.angio.net/pi/"&gt;Pi Searcher&lt;/a&gt; to Rust, hoping to get the best of both worlds.&amp;nbsp; The tl;dr is that it worked and gave me and end-to-end throughput increase of at least 22%.&amp;nbsp; But not entirely in the place I'd expected!&amp;nbsp; The code is basically a transliteration of the Go to Rust, except for moving from Go's internal net/http server to actix-web for Rust.&amp;nbsp; The algorithm is the same:&amp;nbsp; sequential search for short search strings, and using a suffix array for longer strings.&lt;br /&gt;
&lt;h3&gt;
Results&lt;/h3&gt;
Code length isn't too different.&amp;nbsp; I was a little sloppy in writing the Rust version, so I don't think a comparison is entirely fair, but they're within 50% of each other and would probably be closer if I structured the Rust better.&lt;br /&gt;
&lt;h4&gt;
Core search times using the suffix array&lt;/h4&gt;
The core search didn't change by much, as timed on my 2017 i7 Macbook Pro once the cache was fully warmed:&lt;br /&gt;
&lt;br /&gt;
Go Version:&amp;nbsp; 8.1 microseconds/search&lt;br /&gt;
Rust version:&amp;nbsp; 6.1 microseconds/search&lt;br /&gt;
&lt;br /&gt;
No big deal.&amp;nbsp; And not surprising - this time is bounded by the binary search / indirect memory reference time.&amp;nbsp; With 200M positions in the file, searching takes about log2(200M) = 27 steps.&amp;nbsp; Each of those steps involves two dependent memory lookups, and at about 100ns per memory lookup, that's 27*2*100 = 5.4 microseconds of memory time.&amp;nbsp; That's obviously a handwavy calculation that ignores real memory timings and the fact that the first few lookups will hit in cache, but it suggests that both bits of code are &lt;i&gt;mostly&lt;/i&gt;&amp;nbsp;memory-bound.&lt;br /&gt;
&lt;h4&gt;
Direct access over HTTP to the JSON results&lt;/h4&gt;
What about direct reqs/second, measured using &lt;span&gt;ab -c 2 -n 1000&lt;/span&gt;?&amp;nbsp; Measurements on the Pi searcher server (an n1 small GCP instance):&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Rust&lt;/b&gt;&lt;br /&gt;
Requests per second:&amp;nbsp; &amp;nbsp; 6657.61 [#/sec] (mean)&lt;br /&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.300 [ms] (mean)&lt;br /&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.150 [ms] (mean, across all concurrent requests)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Go&lt;/b&gt;&lt;br /&gt;
Requests per second:&amp;nbsp; &amp;nbsp; 6074.71 [#/sec] (mean)&lt;br /&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.329 [ms] (mean)&lt;br /&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.165 [ms] (mean, across all concurrent requests)&lt;br /&gt;
&lt;br /&gt;
So far, that doesn't look all that better, and certainly not like it was worth rewriting.&amp;nbsp; But the pi searcher doesn't exist in a vacuum - the backend is accessed through an Apache reverse proxy.&lt;br /&gt;
&lt;h4&gt;
Access via the Apache reverse proxy&lt;/h4&gt;
&lt;b&gt;Go&lt;/b&gt;&lt;br /&gt;
Requests per second:&amp;nbsp; &amp;nbsp; 2811.57 [#/sec] (mean)&lt;br /&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.711 [ms] (mean)&lt;br /&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.356 [ms] (mean, across all concurrent requests)&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;b&gt;Rust&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
Requests per second:&amp;nbsp; &amp;nbsp; 3445.73 [#/sec] (mean)&lt;/div&gt;
&lt;div&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.580 [ms] (mean)&lt;/div&gt;
&lt;div&gt;
Time per request:&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0.290 [ms] (mean, across all concurrent requests)&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Ah-ha!&amp;nbsp; We finally have a speedup.&amp;nbsp; And what's &lt;i&gt;probably &lt;/i&gt;happening is that the speedup is a little bigger than it looks here, but we're bottlenecked in our measurements by doing the measurements on the same machine.&amp;nbsp; With the server running both the ab benchmarker, the Apache proxy, &lt;i&gt;and&lt;/i&gt;&amp;nbsp;the pi searcher, it's hard to find huge speedups.&amp;nbsp; I'd probably be better off moving to nginx but that's for another year.&lt;/div&gt;
&lt;h3&gt;
Observations&lt;/h3&gt;
The process of rewriting wouldn't have been all that painful for someone familiar with actix-web.&amp;nbsp; As a newbie, I spent a lot of time fighting with it to be able to use its derived parsers for requests while still being able to handle errors myself in some cases.&amp;nbsp; I still don't like the solution I came up with, where there are two analogous-but-different functions to serve GETs and POSTs:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9iVAdmdwnByULjycnWe7RyvGfXc_9xvwtNcMASaBOrWDGIUhhAIjdUoXoyMgXq1NsvRAgu6mKh5fdfU1B0cSzU2AR9Wk0vxElTybJMsk5XBZwgP9HzMJ7ZngIIk3RNH97QW0CtkSgcj8/s1600/carbon.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9iVAdmdwnByULjycnWe7RyvGfXc_9xvwtNcMASaBOrWDGIUhhAIjdUoXoyMgXq1NsvRAgu6mKh5fdfU1B0cSzU2AR9Wk0vxElTybJMsk5XBZwgP9HzMJ7ZngIIk3RNH97QW0CtkSgcj8/s640/carbon.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
(The "legacy" bit is because the pi searcher exports both a modern JSON-based API and a legacy interface that looks like the old CGI interface.)&amp;nbsp; I'm sure there are better ways to accomplish what I was trying to do:&amp;nbsp; I'm not a Rust expert by any means;&amp;nbsp; I used this rewrite as a way to dive in a little to see what creating web services was like in Rust so that I could better evaluate the costs/benefits for real work projects.&lt;br /&gt;
&lt;br /&gt;
Rust's &lt;span&gt;&lt;a href="https://doc.rust-lang.org/std/vec/struct.Vec.html#method.binary_search_by"&gt;binary_search_by_key&lt;/a&gt;&lt;/span&gt; isn't designed as well for suffix array use.&amp;nbsp; Actually, it's designed and implemented just fine, but the documentation notes:&lt;br /&gt;
&lt;blockquote class="tr_bq"&gt;
&lt;span&gt;&amp;nbsp;If there are multiple matches, then any one of the matches could be returned.&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
This is an &lt;i&gt;entirely&lt;/i&gt;&amp;nbsp;sane decision for an API designer to make, because it gives them freedom to change the implementation in the future.&amp;nbsp; Unfortunately, as an API user, it means I can't use it to find the full range of results in a suffix array, which one does by finding the first and last matching elements.&amp;nbsp; I had to re-implement binary search within my code, which, fortunately, was about 15 lines of very easy-to-read code.&amp;nbsp; This was a place that Rust really shined:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPOCuVj_AnihnSfSFXJV6GMsSMeATylXpHHyTr_s_NiDl-e_BNXvVBgfbL5VZaWc7cenLOmKyidUsFhq3EKsNfQtmry2XqdMDxKPzFP2G0gk3i7MKThZycCUyT7-Be0CeC7kv2a6Ijatk/s1600/carbon+%25281%2529.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPOCuVj_AnihnSfSFXJV6GMsSMeATylXpHHyTr_s_NiDl-e_BNXvVBgfbL5VZaWc7cenLOmKyidUsFhq3EKsNfQtmry2XqdMDxKPzFP2G0gk3i7MKThZycCUyT7-Be0CeC7kv2a6Ijatk/s400/carbon+%25281%2529.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;I've internalized the -1, 0, 1 mapping of &lt;a href="https://golang.org/pkg/strings/#Compare"&gt;C-style comparison functions such as Go&lt;/a&gt;'s, but I really liked here that it was an explicit type, not an integer.&lt;br /&gt;
&lt;br /&gt;
The 22% speedup is probably under-measuring, but it's also the number I care about:&amp;nbsp; the actual throughput my server can sustain.&lt;br /&gt;
&lt;br /&gt;
Things that were painful:&amp;nbsp; Getting the routing and whatnot set up with actix-web took a lot of work.&amp;nbsp; The documentation isn't comprehensive for weird usecases like mine (which are, admittedly, stupid -- I'm supporting a legacy interface on both GET/POST and a JSON-ish interface that also stupidly takes both GET/POST).&amp;nbsp; Sorting through the twists of using &lt;span&gt;#[get(...)]&lt;/span&gt; vs explicitly routing things&amp;nbsp;&lt;span&gt;.route(web::get().to(serve_legacy_get)&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;&amp;nbsp;took a while to get right.&amp;nbsp; Mixing my own "in-band" error handling with Actix's error handling was also a pain.&amp;nbsp; It's clear that the framework is designed for supporting modern API development usecases, and that's not unreasonable.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style="font-family: inherit;"&gt;I miss having explicitly named multiple return values.&amp;nbsp; The Search function returns a tuple of &lt;/span&gt;&lt;span&gt;(position, count)&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;, both of which are of type &lt;/span&gt;&lt;span&gt;usize&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;,&amp;nbsp; and it's nice to have the semantics documented explicitly through return parameter naming in Go.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style="font-family: inherit;"&gt;Things that were awesome:&amp;nbsp; Automatic request parsing into a struct (and automatic marshaling of the struct back to json) was very nice.&amp;nbsp; I'd implemented the JSON marshaling as a wrapper in the Go version, but it was automatic in Rust.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;Rust has better support for some functional forms, so, for example, finding the "next search result" (i.e., the element that appears first after position p) was elegant:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdiXUiJivSdGjjztrx6zlkLdGJ7oWcu848Kv31o0qKWXPR4R37Yt0K3oterNF24TxEnUcl__aqgVbPPMUZOPa3YiM2UNujYStf_65ZS-thfMxzJv3bqkWaMxaW8NbnFwpWYtkr3gIHYfw/s1600/carbon+%25282%2529.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdiXUiJivSdGjjztrx6zlkLdGJ7oWcu848Kv31o0qKWXPR4R37Yt0K3oterNF24TxEnUcl__aqgVbPPMUZOPa3YiM2UNujYStf_65ZS-thfMxzJv3bqkWaMxaW8NbnFwpWYtkr3gIHYfw/s400/carbon+%25282%2529.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;

&lt;span style="font-family: inherit;"&gt;I do love that compared to the Go version:&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIv8hk4mFSVeK-oCX6yil1IHLUECCBEAmWQuX7RgQOzuMH8Jse9fzYJirDU5-t21YrM6AmRVUEC88pfdIbgkpA49LFzgfuzrnbZ1cXR9eX3H2NNo-xHsXZKznUkhYNfyYPiMRrg2sTZTY/s1600/carbon+%25283%2529.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIv8hk4mFSVeK-oCX6yil1IHLUECCBEAmWQuX7RgQOzuMH8Jse9fzYJirDU5-t21YrM6AmRVUEC88pfdIbgkpA49LFzgfuzrnbZ1cXR9eX3H2NNo-xHsXZKznUkhYNfyYPiMRrg2sTZTY/s400/carbon+%25283%2529.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
One thing I had been worried about was mmap support, but this was mostly a no-op.&amp;nbsp; The only issue was that I had to recalculate the "mapped as uint32" version in functions where I used it (which is basically nothing), because one doesn't store two pointers to the same thing in a struct in Rust:&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;span style="color: #569cd6;"&gt;let&lt;/span&gt; &lt;span style="color: #9cdcfe;"&gt;idxu32&lt;/span&gt;: &amp;amp;[&lt;span style="color: #4ec9b0;"&gt;u32&lt;/span&gt;] = &lt;span style="color: #4ec9b0;"&gt;bytemuck&lt;/span&gt;::&lt;span style="color: #dcdcaa;"&gt;cast_slice&lt;/span&gt;(&amp;amp;&lt;span style="color: #569cd6;"&gt;self&lt;/span&gt;.&lt;span style="color: #dcdcaa;"&gt;pi_index_map&lt;/span&gt;);&lt;/div&gt;
&lt;br /&gt;
No biggie and if I did it in more than two places it'd be an easy helper function.&lt;br /&gt;
&lt;h3&gt;
Wrapup&lt;/h3&gt;
&lt;div&gt;
A 22% speedup isn't bad, and is probably under-measured because of the other overhead in the system that should also be removed (hi, Apache, I'm looking at you).&amp;nbsp; But it was a good experience, and I'm pleased with the results:&amp;nbsp; this is code that I've poked at on and off for quite a while, and getting a nontrivial speed boost without adding any real complexity or extra lines of code was quite welcome.&amp;nbsp; There are aspects of the Rust ecosystem that remain frustrating -- error handling and documentation primary among them, and Actix is fast and helpful but has a lot of sharp edges -- but it's matured drastically since the last time(s) I've taken a peek at it.&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;</description><author>Dave's Data</author><pubDate>Sun, 18 Oct 2020 16:27:44 GMT</pubDate><guid isPermaLink="true">https://da-data.blogspot.com/2020/05/moving-pi-searcher-from-go-to-rust.html</guid></item><item><title>Tolerating the Pandemic #3</title><link>https://da-data.blogspot.com/2020/06/tolerating-pandemic-3.html</link><description>In two previous posts, I discussed &lt;a href="https://da-data.blogspot.com/2020/03/tolerating-two-years-of-pandemic-in-no.html"&gt;some ongoing processes that will help us tolerate the pandemic better&lt;/a&gt;, and &lt;a href="https://da-data.blogspot.com/2020/04/updates-on-factors-that-will-ease.html"&gt;an update 3 weeks after&lt;/a&gt; the first.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's been two months, which is enough time for more progress to have happened.&amp;nbsp; There hasn't been enough, and some things have had less progress than I've hoped for, but we've also seen a bit more progress in other areas.&amp;nbsp; Let's stick with the same framework from before:&amp;nbsp; Testing, PPE/Supplies, Treatments, and Societal changes to reduce contact.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="5"&gt;Testing&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;In PCR testing&lt;/b&gt;, a picture is worth a thousand words, such as this one taken from Johns Hopkins:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEvnk3imXdKLBfz8Fzq8Ndz3tNUewZzvGthaHtIIia6Xgucb5a_Ny4To4kYgvLrHnAI8kGxqaWBt8wg6qgqsfD-Q-laHCSeYRUFl_UYHPtFujWT6hvWmeXsJEBbUL5IyrryljLgIKxwQs/s2400/hopkins-testing-chart.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="391" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEvnk3imXdKLBfz8Fzq8Ndz3tNUewZzvGthaHtIIia6Xgucb5a_Ny4To4kYgvLrHnAI8kGxqaWBt8wg6qgqsfD-Q-laHCSeYRUFl_UYHPtFujWT6hvWmeXsJEBbUL5IyrryljLgIKxwQs/w625-h391/hopkins-testing-chart.png" width="625" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;We've gone from 58k tests/day, through 145k tests/day, up to about 450k tests/day.&amp;nbsp; It took us about a month to triple and another two months to triple again.&amp;nbsp; That's good, but it's still not at the &lt;a href="https://drive.google.com/file/d/1EhUfmT6ayG3ERxX-wZUmB2wtIEOhRAmP/view?"&gt;levels that the Harvard study recommend&lt;/a&gt;.&amp;nbsp; It is, however, about halfway there, and we can probably get to where we need to be in another five months if the federal and state governments fund it.&amp;nbsp; Unfortunately, the harvard number is probably excessively conservative.&amp;nbsp; Newer research suggests that testing may &lt;a href="https://www.medrxiv.org/content/10.1101/2020.06.22.20136309v1"&gt;need to happen as often as weekly to effectively suppress transmission within a population&lt;/a&gt;;&amp;nbsp; we won't reach those levels for a lot longer.&amp;nbsp; (But we have other means of suppressing transmission, below).&amp;nbsp; The more testing and tracing the better -- every time we catch a case, we help prevent them from infecting more people, which drives down the effective reproductive rate.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;Serum antibody tests&lt;/b&gt; are now &lt;a href="https://www.centerforhealthsecurity.org/resources/COVID-19/serology/Serology-based-tests-for-COVID-19.html"&gt;out in force&lt;/a&gt;, and some of them, such as the Abbott test, are showing very high selectivity and specificity.&amp;nbsp; They're helping drive better understandings of how much of the population has been infected and clearing up earlier divergent hypotheses about this (answer: in most places, the numbers are at or under 5%, which means we're very far from any sort of herd immunity).&amp;nbsp; We're not yet to the point of understanding immunity and the tests well enough to trust them as immunity certificates, but it's getting closer.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="5"&gt;Supplies&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;n95 masks:&amp;nbsp;&amp;nbsp;&lt;/b&gt;3M claims to be ramping up from the previous 35m masks/month domestically&amp;nbsp;&lt;a href="https://www.manufacturing.net/supply-chain/news/21132326/3m-expanding-n95-mask-production-to-95m-per-month"&gt;to 95m masks/month&lt;/a&gt;, but this is on a timeline that may take until the end of 2020.&amp;nbsp; The current phase of expansion is only expected to start producing more masks about ... now.&amp;nbsp; There's still a general mask shortage, and some of the decontamination efforts are scaling back their claims a little (e.g., Battelle's decontamination system, which they hoped would allow 20 reuses per mask, is looking perhaps like it will handle three reuses).&amp;nbsp; There's still a lot of benefit there, and hospitals are finding ways to use other respirators, but we still need more.&amp;nbsp; By the end of the year we'll probably be close to what we need.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;surgical masks&lt;/b&gt;:&amp;nbsp; I don't have data yet on the production rates of ASTM level 1 and 2 masks.&amp;nbsp; Will try to update;&amp;nbsp; there are some folks at CMU attempting to quantify this.&amp;nbsp; Regardless, you still can't buy them in the store, so that's at least one sign. :-)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Cloth masks&lt;/b&gt;:&amp;nbsp; &lt;a href="https://masks4all.co/"&gt;Evidence continues to pile up &lt;/a&gt;for the effectiveness of widespread cloth mask wearing as a way to reduce the chances of transmitting the virus.&amp;nbsp; More on that below.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;font size="5"&gt;Treatment&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some success stories!&amp;nbsp; In the previous update, I just handwaved that Remdesivir was possibly maybe helpful.&amp;nbsp; It's now part of the standard of care, having been shown to reduce hospitalization time (but the reduction in mortality was not statistically significant).&amp;nbsp; But two months is enough time to run a lot of studies, and the UK's large RECOVERY study completed an analysis of the use of the steroid dexamethasone in severely-ill COVID-19 patients, finding that&lt;a href="https://rebelem.com/the-recovery-trial-dexamethasone-for-covid-19/"&gt; it could cut mortality in ventilated patients by up to 1/3&lt;/a&gt;.&amp;nbsp; It's not a silver bullet, and isn't appropriate for use in less seriously-ill patients or the earlier stages of the illness (it suppresses the immune system), but this is a fantastic treatment improvement that can cut the overall fatality rate.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are &lt;a href="https://www.statnews.com/feature/coronavirus/drugs-vaccines-tracker/"&gt;continuing trials of other antivirals and treatments, but as before, these can take a long time&lt;/a&gt;.&amp;nbsp; It's still reasonable to expect a few more treatment improvements that will reduce the fatality rate, but hold on to your hats:&amp;nbsp; The huge reduction in fatalities from dexamethasone is unusual and not something we should expect to stumble upon monthly.&lt;br /&gt;&lt;br /&gt;In vaccines, there are now &lt;a href="https://www.nytimes.com/interactive/2020/science/coronavirus-vaccine-tracker.html"&gt;three vaccines in phase-3 trials&lt;/a&gt;&amp;nbsp;, and from all signs it seems there's reason to be optimistic that we may have a vaccine in &lt;i&gt;limited&lt;/i&gt;&amp;nbsp;production by the end of 2021.&amp;nbsp; If we're lucky, front-line workers may have something even earlier, but we're still looking at least a year, and possibly longer, before things start to make a difference.&amp;nbsp; But this remains impressively fast and hopeful-looking progress for a vaccine.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;font size="5"&gt;Societal Changes &amp;amp; Knowledge About Transmission&lt;br /&gt;&lt;/font&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've sneakily retitled this section, because part of the improvements we get are from being able to be more and more selective about what we close, reopen, or change, and understanding the dynamics of SARS-CoV-2 transmission helps us do those things better.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some of the most hopeful news is the increasing piles of evidence that non-medical masks and staying outside are effective, low-cost interventions to reduce spread.&amp;nbsp; It's hard to do randomized trials where people don't know if they're wearing a mask, but the correlations remain strong, and events such as the recent protests (outdoors + most people masked) did not seem to result in case spikes, compared to other reopening-related events (indoor dining/bars) that &lt;i&gt;have&lt;/i&gt;&amp;nbsp;been traced to case spikes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Delivery services have fully ramped up and wait times for, e.g., Instacart and Amazon Prime Now and other services are back near to baseline in many locations.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Business are struggling to figure out how to safely allow employees to come back to work, and this isn't going to be a fast change.&amp;nbsp; Guidelines for schools and daycares are unclear, but I'm hopeful that as we gain more evidence about the spread in children, an update in two months will note that we now have effective policies for how to resume these things (comparatively) safely.&amp;nbsp; We'll hopefully be able to learn from &lt;a href="https://www.washingtonpost.com/world/asia_pacific/japan-coronavirus-schools-reopen/2020/06/06/9047be8c-a645-11ea-8681-7d471bf20207_story.html"&gt;Japan's experience reopening their schools&lt;/a&gt;, though keeping in mind that mask wearing is much more normalized there and baseline transmission rates have been lower.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;We're nowhere near being back to normal.&amp;nbsp; But we've made continued progress in knocking down the reproductive rate, and that will let us have better choices in balancing daily activities and risk.&amp;nbsp; Now, of course, it will be necessary to actually make good choices, but that's a different post...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><author>Dave's Data</author><pubDate>Sun, 18 Oct 2020 16:27:30 GMT</pubDate><guid isPermaLink="true">https://da-data.blogspot.com/2020/06/tolerating-pandemic-3.html</guid></item><item><title>Tolerating the Pandemic #4: The Ventilation Edition</title><link>https://da-data.blogspot.com/2020/08/tolerating-pandemic-4-ventilation.html</link><description>&lt;p&gt;&amp;nbsp;This is #4 in the series of how we can tolerate the pandemic in a lot of slow, steady progress and hard work.&amp;nbsp; As a quick recap, the &lt;a href="https://da-data.blogspot.com/2020/03/tolerating-two-years-of-pandemic-in-no.html"&gt;first post laid out a bit of a roadmap&lt;/a&gt;&amp;nbsp;(March 23, 2020); the &lt;a href="https://da-data.blogspot.com/2020/04/updates-on-factors-that-will-ease.html"&gt;second&lt;/a&gt;&amp;nbsp;(April 17, 2020) and &lt;a href="https://da-data.blogspot.com/2020/06/tolerating-pandemic-3.html"&gt;third&lt;/a&gt;&amp;nbsp;(June 26, 2020) noted updates on the categories described in the first.&lt;/p&gt;&lt;p&gt;In the two months since my previous post, one of the most exciting advances has been in improved understanding of the transmission dynamics of SARS-CoV-2, particularly with respect to aerosol-like transmission.&amp;nbsp; An &lt;a href="https://www.nytimes.com/2020/08/11/health/coronavirus-aerosols-indoors.html"&gt;Aug 11 New York Times article&lt;/a&gt; has a good summary of some of the research in this area.&amp;nbsp; Tl;dr:&amp;nbsp; Ballistic (large droplet) transmission is probably still a big factor, and is helped quite a bit by masks.&amp;nbsp; Aerosol transmission is a big contributor particularly to superspreader events (and particularly indoors).&amp;nbsp; Cloth or surgical masks help but are not a silver bullet, particularly in crowded, confined spaces.&lt;/p&gt;&lt;p&gt;Why is this exciting? Because it helps us bring more tools to bear against transmission. It furthers the (already very strong) case for the outdoors being substantially safer than being indoors; it reinforces the importance of masks as part of a source control strategy; and it suggests that improvements to ventilation and good (HEPA or MERV-13 or higher) filtration also have a role to play in reducing the number of people who get infected from a transmitting individual.&lt;/p&gt;&lt;p&gt;For more on this, I suggest starting with the &lt;a href="https://schools.forhealth.org/wp-content/uploads/sites/19/2020/06/Harvard-Healthy-Buildings-Program-Schools-For-Health-Reopening-Covid19-June2020.pdf"&gt;Harvard Healthy Buildings report from June&lt;/a&gt;&amp;nbsp;and &lt;a href="https://www.colorado.edu/researchinnovation/sites/default/files/attached-files/covidsolutions-webinarslides-aug6.pdf"&gt;this slide deck from CU Boulder&lt;/a&gt;.&amp;nbsp; As a taste of some of the great things in there, this slide, analyzing the infection probability of a known real super-spreader event (an indoor choir practice) while changing different components of the scenario, such as increasing ventilation. Or just moving the darn thing outside, which would have approximately solved the problem.&amp;nbsp; (The advantage of being outside &lt;a href="https://da-data.blogspot.com/2020/06/tolerating-pandemic-3.html"&gt;was already clear as of the previous update in June,&lt;/a&gt; but more evidence and understanding of why is good.)&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQDUr_wHpMOKQoXB-QHfM0CiqkWAn6I-gr7DK4ZIiLYsrCacmNYUqBWh-fL0UczNLdB6iX1Mb6TDJ3AY5e8F3q0ae1Gu5bgQR9izjDktPmWvWTevG1pxCZv6pwWHVNpOKEl_jirGm0qZE/s2272/Screen+Shot+2020-08-23+at+10.05.55+PM.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQDUr_wHpMOKQoXB-QHfM0CiqkWAn6I-gr7DK4ZIiLYsrCacmNYUqBWh-fL0UczNLdB6iX1Mb6TDJ3AY5e8F3q0ae1Gu5bgQR9izjDktPmWvWTevG1pxCZv6pwWHVNpOKEl_jirGm0qZE/s640/Screen+Shot+2020-08-23+at+10.05.55+PM.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;With that said, let's get back to the framework from the previous posts: Testing, PPE/Supplies, Treatments, and Societal changes to reduce contact. I'll fold ventilation improvements into the latter, since that's where I'd previously discussed things like plexiglass barriers in retail.&lt;/p&gt;&lt;h2 style="text-align: left;"&gt;Testing&lt;/h2&gt;&lt;div&gt;I'm going to just incorporate covidtracking's graph here, since it's now nicer than mine [&lt;a href="https://covidtracking.com/data/charts/us-daily-tests"&gt;source&lt;/a&gt;]&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNlwOhs10BIkAIISPCtcGIqLNJrhdCBIPQd6tWBNk3pzaLhGm5qhoOrFHTZE3ToJ9Qd9lTsnxCgVE6EcyPHDhg57BOAT68Nk4dCS0D9qqEfAXiSS6XTor1kOYvqd5OjLG3__Q9OyBTEd8/s2024/Screen+Shot+2020-08-23+at+10.12.38+PM.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNlwOhs10BIkAIISPCtcGIqLNJrhdCBIPQd6tWBNk3pzaLhGm5qhoOrFHTZE3ToJ9Qd9lTsnxCgVE6EcyPHDhg57BOAT68Nk4dCS0D9qqEfAXiSS6XTor1kOYvqd5OjLG3__Q9OyBTEd8/s640/Screen+Shot+2020-08-23+at+10.12.38+PM.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;So that's .. not what I'd like to see, but we have to be careful reading that. In update #3 (June), we were at 450k tests/day. As of now the US is up to about 700k.&amp;nbsp; Better than June, but case counts are also still higher than they were in June;&amp;nbsp; test positive rates are only just now getting back down to where they were. The good news is that we're testing a lot; the bad news is that with cases so high our testing isn't anywhere near sufficient to keep cases low.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPIqYY6thsca6dAhAypVgSUY8ySbHq1lg3UGeMxRX4XVuClUmGp6IkWEf5nG40878ATBiR_vWwr-RBK6uFtcOyCrvwKpMEQYa5_oUDzHgLicWMCX-KLgRv2j2x6mo6XeZRygUAUGnb0FM/s1024/US.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPIqYY6thsca6dAhAypVgSUY8ySbHq1lg3UGeMxRX4XVuClUmGp6IkWEf5nG40878ATBiR_vWwr-RBK6uFtcOyCrvwKpMEQYa5_oUDzHgLicWMCX-KLgRv2j2x6mo6XeZRygUAUGnb0FM/s640/US.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h2 style="text-align: left;"&gt;PPE&lt;/h2&gt;&lt;p&gt;N95 mask production continues to ramp up about as expected.&amp;nbsp; &lt;a href="https://www.3m.com/3M/en_US/company-us/coronavirus/"&gt;3M says it's on track to produce 95 million per month by October&lt;/a&gt;&amp;nbsp;in the US, and 2B annually for the global market.&amp;nbsp; In our previous update, 3m was trying to hit 50M/month by July, &lt;a href="https://www.startribune.com/3m-says-it-s-on-track-with-n95-production-goals/571710872/"&gt;which they seem to have&lt;/a&gt;.&amp;nbsp; Recall that DHS estimates we need about 300M masks/month in the US, but 3M isn't the only supplier. We're basically on track ramping up our PPE capacity, but it also still may be until the end of 2020 that we've really gotten this solved.&lt;/p&gt;&lt;p&gt;Anecdotally, N95 masks are showing up occasionally on Amazon now (before getting re-restricted for healthcare use only). Reusable options are emerging. But there are still few high-quality surgical masks (ASTM level 1-3 certified) available for the general public, which would be an improvement over the high variance in quality of uncertified masks.&lt;/p&gt;&lt;h2 style="text-align: left;"&gt;The Purell Indicator&lt;/h2&gt;&lt;div&gt;I've been monitoring availability of Purell as one interesting, informal indicator of the availability of hand sanitizer. In the last two weeks, it's become available again. There's been plenty of other-brand hand sanitizer available for the last two months, but as one of the most well-known brands, this is a good sign that manufacturing is catching up with demand.&lt;/div&gt;&lt;h2 style="text-align: left;"&gt;Treatment Improvements&lt;/h2&gt;&lt;div&gt;The big news two months ago was the outcome of the dexamethasone study; that remains part of the standard of care. Overall, studies of the infection fatality rate (IFR) suggest that it is lower now than in earlier phases of the epidemic, which is likely due to a combination of factors: treatment improvements, less overloading of hospitals, and better protection of highly-vulnerable populations such as nursing homes.&amp;nbsp; But within this hides an important benefit: &lt;b&gt;It's better to get SARS-CoV-2 today than it was in February&lt;/b&gt;.&amp;nbsp; And it's likely to continue to improve as we run through additional options for improving treatment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are now &lt;a href="https://www.nytimes.com/interactive/2020/science/coronavirus-vaccine-tracker.html"&gt;approximately 10 vaccine candidates in phase III trials&lt;/a&gt;. (I say approximately, because two of them are technically approved, but have been approved prior to their phase III trial, which means that their use will effectively be a phase III, albeit a potentially poorly controlled one).&amp;nbsp; Prospects for the vaccine remain good:&lt;/div&gt;&lt;div&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;There are candidates based upon several different technologies.&lt;/li&gt;&lt;li&gt;Results appear promising that infection yields protection for at least several months for most people.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;The different technologies part is important. Several of the candidate vaccines are based upon an adenovirus vector, which has the drawback that prior infection by the same or similar adenovirus may reduce the vaccine's effectiveness. This &lt;a href="https://www.thelancet.com/journals/lancet/article/PIIS0140-6736(20)31605-6/fulltext"&gt;appears to be the case&lt;/a&gt;, for example, for the CanSino Ad5-vectored vaccine, which otherwise appears promising and is now in Phase III. This is in no way a fatal flaw for the Ad-based vaccines, but it means we may need alternatives. Fortunately, several of the other candidates are mRNA-based vaccines, such as that by Moderna in the US, which are likely to have entirely different failure patterns: we've never yet taken an mRNA vaccine to approval. But if one of these vaccines works, it probably won't fail for the same people for whom Ad5-vectored vaccines fail. And a few candidates, such as the vaccine from Wuhan Institute of Biological Products / Sinopharm, are inactivated virus vaccine, presenting a third mechanism to play with.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's important to remember that no vaccine is likely to be perfect, and the deployment of a vaccine is not next week. Even once manufacturing is ramped up, several of the vaccines require two doses, potentially separated by several weeks. But progress remains good.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm not going to say much about convalescent plasma. Too much stupid politics going around about it, and it's still awaiting more randomized trial results. It's unlikely to be a silver bullet either, of course: making it requires people who're sick, it's expensive and rare, and its efficacy is as yet unknown. More scalable technologies, such as monoclonal antibodies, &lt;a href="https://www.nih.gov/news-events/news-releases/clinical-trials-monoclonal-antibodies-prevent-covid-19-now-enrolling"&gt;are still in development &amp;amp; testing&lt;/a&gt;.&lt;/div&gt;&lt;h2 style="text-align: left;"&gt;Societal and Environmental Changes&lt;/h2&gt;&lt;div&gt;As noted above, this is where I'm most excited this month. Ventilation improvements to existing buildings can be expensive, but they pay dividends for years in healthier, more productive occupants, so upgrading as part of a pandemic-reduction strategy may not be a net cost increase as much as an unexpected cost shift to, well, now. This is something we can and should be pursuing aggressively, but we'll see how much traction it gets. I'd love to find someone/where that tracks ventilation system upgrades!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A large concern now is school reopening. We're just seeing the leading edge of it, with universities such as UNC &lt;a href="https://www.newsobserver.com/news/coronavirus/article245194165.html"&gt;reopening and then backtracking on it&lt;/a&gt;. Many k-12 schools have delayed their reopening plans as cases in the US remain well above levels where opening would be safe. School closures have been widely regarded as one of the more effective NPIs (non-pharmaceutical interventions), both because they reduce the chances of children spreading the disease, but also because they reduce parents' mobility.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><author>Dave's Data</author><pubDate>Sun, 18 Oct 2020 16:27:22 GMT</pubDate><guid isPermaLink="true">https://da-data.blogspot.com/2020/08/tolerating-pandemic-4-ventilation.html</guid></item><item><title>Svelte for Sites, React for Apps</title><link>https://www.swyx.io/svelte-sites-react-apps</link><description>Why we should stop trying to use the same tool for different jobs.</description><author>swyx's site RSS Feed</author><pubDate>Sun, 18 Oct 2020 04:08:02 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/svelte-sites-react-apps</guid></item><item><title>Emacs: org block complete and edit</title><link>https://xenodium.com/emacs-edit-after-org-block-completion</link><description>&lt;p&gt;I quickly got used to &lt;a href="http://xenodium.com/emacs-org-block-company-completion/"&gt;Emacs org block company completion&lt;/a&gt;. I did, however, almost always found myself running &lt;em&gt;org-edit-special&lt;/em&gt; immediately after inserting completion. I use &lt;strong&gt;C-c '&lt;/strong&gt; for that. That's all fine, but it just felt redundant.&lt;/p&gt;
&lt;p&gt;Why not automatically edit the source block in corresponding major mode after completion? I think I can also get used to that!&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-edit-after-org-block-completion/automatic.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Or maybe the automatic approach is too eager? There's also a middle ground: ask immediately after.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-edit-after-org-block-completion/prompted.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Or maybe I don't want either in the end? Time will tell, but I now have all three options available:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defcustom company-org-block-edit-mode 'auto
  &amp;quot;Customize whether edit mode, post completion was inserted.&amp;quot;
  :type '(choice
          (const :tag &amp;quot;nil: no edit after insertion&amp;quot; nil)
          (const :tag &amp;quot;prompt: ask before edit&amp;quot; prompt)
          (const :tag &amp;quot;auto edit, no prompt&amp;quot; auto)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The new option is now in the &lt;a href="https://github.com/xenodium/dotsies/blob/main/emacs/ar/company-org-block.el"&gt;company-org-block snippet&lt;/a&gt; with my latest config.&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 18 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-edit-after-org-block-completion</guid></item><item><title>The 6 Conditions of Change</title><link>http://spirals.blog/articles/6-conditions-of-change/</link><description>&lt;h3&gt;&lt;a href="#conditions"&gt;👇 Skip to the conditions 👇&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/potential/"&gt;&lt;strong&gt;Potential:&lt;/strong&gt; How flexible are you? 👉&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/solutions/"&gt;&lt;strong&gt;Solutions:&lt;/strong&gt; What are you solving for in life? 👉&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/dissonance/"&gt;&lt;strong&gt;Dissonance:&lt;/strong&gt; Your tolerance for change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Barriers:&lt;/strong&gt; What confronts you? &lt;em&gt;(Coming Soon)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Insight:&lt;/strong&gt; What can the past teach you? &lt;em&gt;(Coming Soon)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment:&lt;/strong&gt; Who is helping you transition? &lt;em&gt;(Coming Soon)&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;Dear reader,
Have you ever spent what felt like an eon forcing everything you’ve got into trying to change something?&lt;/p&gt;
&lt;p&gt;Maybe it is the endless attempts of diets or quitting smoking.&lt;/p&gt;
&lt;p&gt;Perhaps, you’re trying to become a hard-working, responsible citizen that everybody else seems to have worked out how to be. Instead, you’re halfway through your first degree and just quit your job to travel to South America.&lt;/p&gt;
&lt;p&gt;Are you trying to rally a team together at work but feel like you don’t have enough support?&lt;/p&gt;
&lt;p&gt;Can you relate to me when I say, “I’ll change one of these days,” Or are you more the type to respond with, “Change? I’m open to anything, really.”&lt;/p&gt;
&lt;p&gt;Do you feel like you’re reaching for something, but everything around you is pulling you down? You can’t get a handle on the world around you, and you just want, so badly, to arrive at the end?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Removing the friction&lt;/h2&gt;
&lt;p&gt;Changing things is complicated. No matter how big or small, adjusting our current reality requires great dedication and energy. This is a series exploring the &lt;em&gt;&lt;strong&gt;6 necessary conditions&lt;/strong&gt;&lt;/em&gt; that need to be present in order for change to occur.&lt;/p&gt;
&lt;p&gt;Imagine these conditions as six keys we need to unlock the door of &lt;em&gt;real change&lt;/em&gt;. If one of these conditions is not met, the door remains closed. &lt;strong&gt;If more than one is not met…we may even regress.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With all conditions present, the door opens, and we can move easily through the passage. Change will live within us and act upon us effortlessly.&lt;/p&gt;
&lt;h2&gt;The 6 conditions of Change&lt;/h2&gt;
&lt;p&gt;Behold! The 6 Keys, initially outlined by Clare Graves and his students Don Beck and Edward Cowen. This series will address the high-level concepts, providing illustrations, because…who doesn’t like pictures 😁? If you’re interested in reading further, I would encourage you to pick up a copy of their book for some bedtime reading.&lt;/p&gt;
&lt;ul class="tiles" id="conditions"&gt;
  &lt;li&gt;
    &lt;a href="http://spirals.blog/articles/6-conditions-of-change/potential"&gt;
      &lt;img src="http://spirals.blog/articles/6-conditions-of-change/potential/tile.png" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://spirals.blog/articles/6-conditions-of-change/solutions"&gt;
      &lt;img src="http://spirals.blog/articles/6-conditions-of-change/solutions/tile.png" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;a href="http://spirals.blog/articles/6-conditions-of-change/dissonance"&gt;
      &lt;img src="http://spirals.blog/articles/6-conditions-of-change/dissonance/tile.png" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;
  &lt;li class="todo"&gt;
    &lt;!-- &lt;a href="barriers"&gt; --&gt;
      &lt;img src="http://spirals.blog/articles/6-conditions-of-change/barriers/tile.png" /&gt;
    &lt;!-- &lt;/a&gt; --&gt;
  &lt;/li&gt;
  &lt;li class="todo"&gt;
    &lt;!-- &lt;a href="insight"&gt; --&gt;
      &lt;img src="http://spirals.blog/articles/6-conditions-of-change/insight/tile.png" /&gt;
    &lt;!-- &lt;/a&gt; --&gt;
  &lt;/li&gt;
  &lt;li class="todo"&gt;
    &lt;!-- &lt;a href="environment"&gt; --&gt;
      &lt;img src="http://spirals.blog/articles/6-conditions-of-change/environment/tile.png" /&gt;
    &lt;!-- &lt;/a&gt; --&gt;
  &lt;/li&gt;
&lt;/ul&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 18 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/6-conditions-of-change/</guid></item><item><title>Potential: How flexible are you?</title><link>http://spirals.blog/articles/6-conditions-of-change/potential/</link><description>&lt;p&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/"&gt;👈 Back to all conditions&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Our first condition of change is &lt;strong&gt;Potential&lt;/strong&gt;. Not everyone is &lt;em&gt;&lt;strong&gt;open&lt;/strong&gt;&lt;/em&gt; to change, you see? Ever heard the phrase, you can lead a horse to water, but you can’t make it drink?&lt;/p&gt;
&lt;p&gt;As the world moves to more chaos, and complexity rises like our sea (😕), we move toward a system of many different needs, values, and aspirations. It would make sense for us to be able to move between these right?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Potential&lt;/strong&gt; is divided up into three “states”, depending on how “open” you are to other ways of thinking (or color systems).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Open:&lt;/strong&gt; Healthiest. Readiness to accept new modes of being&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arrested:&lt;/strong&gt; Caught up with the current way of life, and the &lt;strong&gt;Barriers&lt;/strong&gt; present (more on &lt;strong&gt;Barriers&lt;/strong&gt; later)&lt;/li&gt;
&lt;li&gt;‌&lt;strong&gt;Closed:&lt;/strong&gt; Unhealthiest. Blocked entirely by life conditions, and lacks flexibility&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Open: “Going with the flow”&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Open" src="http://spirals.blog/articles/6-conditions-of-change/potential/open.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;To be “open” in terms of one’s &lt;strong&gt;potential&lt;/strong&gt;, means there is flexibility for more &lt;em&gt;complex&lt;/em&gt; levels of functioning to happen.
For you psychology buffs out there, this could correlate to the “Openness” of the Big 5.&lt;/p&gt;
&lt;p&gt;Being open is the healthiest form, with the individual/organization/country adapting and shifting as the surrounding world changes. In our image above, we jump on a boat to escape the rising tide, able to move wherever we please.&lt;/p&gt;
&lt;p&gt;Someone who is open does not hold a sharp picture (aka: a strong frame). They deal well with &lt;strong&gt;Barriers&lt;/strong&gt;, as they are able to move outside the current way of thought, dodge things, or think about how to turn the situation around.&lt;/p&gt;
&lt;p&gt;Open people/entities have great listening skills, are non-judgmental, tolerant of differences, and lack close-mindedness. Generally, they’re pretty bad-ass people 😎.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Open:&lt;br /&gt;
Healthy, flexible, and anticipates change. Adapts when needed&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The power of “openness” comes from it’s anticipation that &lt;strong&gt;&lt;a href="https://spirals.blog/articles/chaos-surfing/"&gt;things will change&lt;/a&gt;&lt;/strong&gt;. There is an “elasticity” between perspectives, and they’ll often engage in multiple colors.&lt;/p&gt;
&lt;p&gt;This is the ideal place for us to all be, but it takes a LOT of work, and is something we must constantly be vigilant on. Lest we become…&lt;/p&gt;
&lt;h2&gt;Arrested: “Don’t rock the boat”&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Arrested" src="http://spirals.blog/articles/6-conditions-of-change/potential/arrested.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;For most of us, this is the default mode (unless we work really hard to be otherwise). Change &lt;em&gt;can&lt;/em&gt; occur, but only if our &lt;strong&gt;Barriers&lt;/strong&gt; are overcome. Also, we need more &lt;strong&gt;Dissonance&lt;/strong&gt;, as we become more “entrenched” into our current way of life (not a problem for &lt;strong&gt;Open&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Arrested&lt;/strong&gt; people/companies/countries may also lack &lt;strong&gt;Insights&lt;/strong&gt; to explain what is happening. As a result, an &lt;strong&gt;Arrested&lt;/strong&gt; entity will make excuses for the status quo, reluctant to change things. They will come to grips with the &lt;strong&gt;Barriers&lt;/strong&gt;, as opposed to working with, changing, or transmuting them in &lt;strong&gt;Open&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you catch yourself saying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Let’s do what we can with what we have”&lt;/li&gt;
&lt;li&gt;“I’ll change &lt;em&gt;one&lt;/em&gt; of these days&lt;/li&gt;
&lt;li&gt;“Stick with the tried and true”&lt;/li&gt;
&lt;li&gt;“I’ve come to peace with it now”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There may be a chance you’re a touch arrested in how you’re approaching the situation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Identifying the &lt;strong&gt;Barriers&lt;/strong&gt;, teaming up with others, and finding innovative ways to approach your problems could help increase your openness.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If we chose to remain arrested, expect little movement towards more complex thinkings. Efforts will instead be placed toward refining and working harder/smarter, versus a fundamental shift of thinking and approach where things are more open.&lt;/p&gt;
&lt;p&gt;New life conditions (org changes at work, new tax laws, natural disasters, breakups, etc) pose much more disruption for someone who is Arrested. They generate more anxiety, and uncertainty, as the “fixed” way of life is forced to change.&lt;/p&gt;
&lt;p&gt;To extend our metaphor of the image above, the house on the island is quite stationary. Although we are fairing better than the drowning, &lt;strong&gt;Closed&lt;/strong&gt;, figure, when the sea eventually rises we will be envious of the “S.S. Open”. Unless we re-address the fundamental relationship to our problems, we’ll just keep building higher, and higher, eventually ending up in…&lt;/p&gt;
&lt;h2&gt;Closed: “Life sucks, and it’s NOT my fault”&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Closed" src="http://spirals.blog/articles/6-conditions-of-change/potential/closed.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Barriers&lt;/strong&gt; are high in a &lt;strong&gt;Closed&lt;/strong&gt; state of mind. If we ignore the warning signs, and slip from &lt;a href="https://spirals.blog/articles/cycles-of-life/"&gt;Beta into the Gamma Trap&lt;/a&gt;, they will grow higher still. It’s not a great place to be.&lt;/p&gt;
&lt;p&gt;There are a number of places a &lt;strong&gt;“Closed”&lt;/strong&gt; perspective may come from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Historical trauma that created incredible, negative meaning towards something&lt;/li&gt;
&lt;li&gt;Refusal to identify and address the issues one is experiencing before it’s “too late”&lt;/li&gt;
&lt;li&gt;Strong social/parental conditioning (passing on fears and beliefs to children is sadly very common)&lt;/li&gt;
&lt;li&gt;Physical ailments or damage (unfortunately preventing the individual to progress developmentally)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What little flexibility we had in &lt;strong&gt;Arrested&lt;/strong&gt; is now completely gone. The confusion, and uncertainty of &lt;strong&gt;Arrested&lt;/strong&gt; give way to anger, hatred, panic, violence, suicide, depression, and a range of other nasties. Someone who is &lt;strong&gt;Closed&lt;/strong&gt; feels threatened by just about everything that’s not “my perspective”, and will fight tooth and nail to protect the failing way of life.&lt;/p&gt;
&lt;p&gt;If we observe, again, our metaphor, the individual has sand-bagged himself on a sinking island. Refusing refuge from the “Open Boat,” and too late to build a house, he remains trapped in his condition until he either changes, or drowns.&lt;/p&gt;
&lt;p&gt;Grim, much 💀?&lt;/p&gt;
&lt;p&gt;The danger of &lt;strong&gt;Closed&lt;/strong&gt; minded thinking stems from it’s inability to see the &lt;strong&gt;Barriers&lt;/strong&gt;. Much like the power that &lt;strong&gt;Openness&lt;/strong&gt; receives from it’s flexibility, the opposite is true for &lt;strong&gt;Closed&lt;/strong&gt; thinking. &lt;strong&gt;Closed&lt;/strong&gt; perspectives are often exhibited by an overactive, single color that feels threatened by introduced circumstances.&lt;/p&gt;
&lt;p&gt;Here is what to watch for in yourself and others to identify a &lt;strong&gt;Closed&lt;/strong&gt; perspective:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“My way is the only way a rational person would think”&lt;/li&gt;
&lt;li&gt;“This is all there is”&lt;/li&gt;
&lt;li&gt;“I can’t think of any way to solve this”&lt;/li&gt;
&lt;li&gt;“It’s done for”&lt;/li&gt;
&lt;li&gt;“Everyone else is wrong”&lt;/li&gt;
&lt;li&gt;“Why can’t you see my view?”&lt;/li&gt;
&lt;li&gt;Constant doubt (“Do you really love me?”)&lt;/li&gt;
&lt;li&gt;Insatiability&lt;/li&gt;
&lt;li&gt;Every idea washed with the same color&lt;/li&gt;
&lt;li&gt;Irritable quickly under stress&lt;/li&gt;
&lt;li&gt;Completes things to &lt;em&gt;extremes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Builds a shell to hide in&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Closed:&lt;br /&gt;
Inability to see Barriers, shuts down, avoids all change, and fights to stay put.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A &lt;strong&gt;Closed&lt;/strong&gt; perspective will usually collapse in on itself, unless supported by others inflicted with the same thinking. Groups of closed-mindedness can clump together, dig trenches, and try to “take on the world”. Take, for example, how the Samurai of Japans dying feudal era resisted against western ideas. Instead of adapting, integrating, and merging into the modern world, they fought to the last man, and are no more.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Open for Business: Using “Potential”&lt;/h2&gt;
&lt;p&gt;What do we get when we assess the “potential” of some thing, or some one?&lt;/p&gt;
&lt;p&gt;The greatest benefit is we may now identify the &lt;em&gt;probability that it/we/they can change&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If they are &lt;strong&gt;Open&lt;/strong&gt;, then the probability is high.&lt;/p&gt;
&lt;p&gt;If we are &lt;strong&gt;Arrested&lt;/strong&gt;, the &lt;strong&gt;Barriers&lt;/strong&gt; need to be identified that are creating walls, and the &lt;strong&gt;Dissonance&lt;/strong&gt; volume may need to be turned up (make them sweat it 😓).&lt;/p&gt;
&lt;p&gt;If it’s closed, then deep thought should be given to &lt;strong&gt;whether it’s worth trying to change it or not&lt;/strong&gt;. This may sound drastic, however if &lt;strong&gt;Potential&lt;/strong&gt; is low (&lt;strong&gt;Closed&lt;/strong&gt;), and the fortifications are up, it may be more trouble than it’s worth.&lt;/p&gt;
&lt;p&gt;Once we can read the Potential, we may also assess the required energy to shift the system. This can be critical at an organizational level to determine if resources should be placed in re-directing the current way of things, or investing energy into something else.&lt;/p&gt;
&lt;p&gt;Potential will also give us insight into the stress produced from changes (side-effects). We additionally learn how much can be changed, and in what ways, and to what degree.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Potential is just &lt;strong&gt;one&lt;/strong&gt; of the Six Conditions of Change. It is arguably one of the most important condition needed for enabling a shift, and provides valuable information on how receptive and flexible we/they/you are.&lt;/p&gt;
&lt;p&gt;So next time, before jumping into that new exercise routine, company structure, or country, have a look at your own &lt;strong&gt;Potential&lt;/strong&gt;. Are you &lt;strong&gt;Closed&lt;/strong&gt; in some areas, and &lt;strong&gt;Open&lt;/strong&gt; in others? Where could you be more flexible? What is holding you &lt;strong&gt;Arrested&lt;/strong&gt;, limiting your options?&lt;/p&gt;
&lt;p&gt;(Next up, we’ll take a look at Solutions)[/articles/6-conditions-of-change/solutions/], and how focusing on where we’re at can make all the difference.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://spirals.blog/articles/6-conditions-of-change/"&gt;👈 Back to all conditions&lt;/a&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 18 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/6-conditions-of-change/potential/</guid></item><item><title>BEBEN X8 Review</title><link>https://www.dannyguo.com/blog/beben-x8-review</link><author>Danny Guo</author><pubDate>Sun, 18 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.dannyguo.com/blog/beben-x8-review</guid></item><item><title>Yahoo groups is finally closing, and I am SO happy</title><link>https://stop.zona-m.net/2020/10/yahoo-groups-is-finally-closing-and-i-am-so-happy/</link><description>&lt;p&gt;Why? Because it may (just may) help many people see the light.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 17 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/yahoo-groups-is-finally-closing-and-i-am-so-happy/</guid></item><item><title>Why does package-lock.json exist, and how does it work?</title><link>https://lucasfcosta.com/blog/lockfile-guide/</link><description>When writing JavaScript applications, you describe its dependencies using a `package.json` file. This file contains all of your applications direct dependencies and their versions.

If you're buildin...</description><author>Lucas F. Costa - Blog</author><pubDate>Sat, 17 Oct 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://lucasfcosta.com/blog/lockfile-guide/</guid></item><item><title>Mac and Chrome HotKeys</title><link>https://blog.herlein.com/post/hotkeys/</link><description>&lt;p&gt;A simple hotkey extension in Chrome that makes my life easier.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 17 Oct 2020 11:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/hotkeys/</guid></item><item><title>Object Detection at 1840 FPS with TorchScript, TensorRT and DeepStream</title><link>https://paulbridger.com/posts/video-analytics-deepstream-pipeline/</link><description>In this article we take performance of the SSD300 model even further, leaving Python behind and moving towards true production deployment technologies: TorchScript, TensorRT and DeepStream. We also identify and understand several limitations in Nvidia&amp;rsquo;s DeepStream framework, and then remove them by modifying how the &lt;code&gt;nvinfer&lt;/code&gt; element works.</description><author>Machine Learning Articles on paulbridger.com</author><pubDate>Sat, 17 Oct 2020 09:43:23 GMT</pubDate><guid isPermaLink="true">https://paulbridger.com/posts/video-analytics-deepstream-pipeline/</guid></item><item><title>AxiDraw Lego camera mount</title><link>https://muffinman.io/blog/axidraw-lego-camera-mount/</link><description>&lt;article class="article"&gt;&lt;p&gt;I already &lt;a href="/blog/axidraw-plotter-camera-mount/"&gt;built a mount&lt;/a&gt; for my Raspberry Pi camera, but it was 3d printed. Meaning that it has one fixed position. I used it a couple of times, but I wasn&amp;#x27;t super satisfied. Then I stumbled on &lt;a href="https://imgur.com/gallery/VjXSSzh"&gt;these images&lt;/a&gt;, and thought it was a great idea to use Lego to build a new, more versatile mount.&lt;/p&gt;
&lt;p&gt;A friend of mine had a bunch of spare Legos laying around, so he gave me two bags full of Legos to play around. I wasn&amp;#x27;t sure where to start, especially because I wanted to make both height and rotation adjustable. After fiddling with the blocks for about an hour, I came up with this:&lt;/p&gt;
&lt;div class="grid"&gt;&lt;figure class="image__figure"&gt;&lt;img alt="Camera on the mount, front view" height="3024" src="./lego-front.jpg" width="4032" /&gt;&lt;/figure&gt;&lt;figure class="image__figure"&gt;&lt;img alt="Camera on the mount, back view" height="3024" src="./lego-back.jpg" width="4032" /&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;It is quite simple, but the secret is in the blue part. Because it can be connected with the black &amp;quot;rail&amp;quot; I
&lt;span class="sidenote__text" tabindex="0"&gt;glued on to the plotter&lt;/span&gt;&lt;span class="sidenote__note"&gt;&lt;span class="sidenote__note-inner"&gt;&lt;span class="sidenote__note-text"&gt;I used double sided mounting tape, as it is stable enough and easy to remove if I want to&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class="image__figure"&gt;&lt;img alt="AxiDraw with black lego rail glued on" height="3024" src="./lego-rail.jpg" width="4032" /&gt;&lt;/figure&gt;
&lt;p&gt;This allows me to change the height of the mount, by inserting the blue part into the different hole. And to make things even better, the blue part behaves as an axis, and the whole mount can be rotated around it. Once mounted, it looks like this:&lt;/p&gt;
&lt;figure class="image__figure"&gt;&lt;img alt="Camera mounted on the plotter" height="3024" src="./lego-mounted.jpg" width="4032" /&gt;&lt;/figure&gt;
&lt;p&gt;And finally I shot a short test video plotting my logo:&lt;/p&gt;
&lt;figure class="video__figure"&gt;&lt;video class="" controls="" src="./lego-example.mp4#t=0.001"&gt;&lt;/video&gt;&lt;/figure&gt;
&lt;p&gt;If you want to see pen plots of my generative art, check my &lt;a href="https://www.instagram.com/muffinman_io/"&gt;Instagram account&lt;/a&gt;.&lt;/p&gt;&lt;/article&gt;</description><author>Muffin Man</author><pubDate>Sat, 17 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/blog/axidraw-lego-camera-mount/</guid></item><item><title>Distribute ALL THE THINGS!</title><link>https://nyoom.io/posts/2020-10-17-distribute-all-the-things/</link><description>&lt;h1 id="bad-ideas-are-born-out-of-necessity"&gt;Bad Ideas Are Born out of Necessity&lt;/h1&gt;
&lt;p&gt;So recently, I got a new Dell R720xd (from &lt;a href="https://techmikeny.com/"&gt;TechMikeNY&lt;/a&gt;) to compliment my Dell C2100 that I&amp;rsquo;ve had for a few years.
The new server was promptly christened &amp;ldquo;Irminsul&amp;rdquo; (following the C2100 as &amp;ldquo;Yggdrasil&amp;rdquo;, a &lt;a href="https://en.wikipedia.org/wiki/World_tree"&gt;&amp;ldquo;World Tree&amp;rdquo;&lt;/a&gt;),
and begun a full disk test to make sure everything was spotless. Unfortunately, a disk ended 99.97% with bad sectors, so a quick email to
Mike (Seriously, shout out to the team over there.) and we were off to the races.&lt;/p&gt;</description><author>Q. Marchi: A Blog</author><pubDate>Sat, 17 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nyoom.io/posts/2020-10-17-distribute-all-the-things/</guid></item><item><title>October 2020 Projects</title><link>https://venam.net/blog/programming/2020/10/17/october-projects.html</link><description>Seven long and perilous months have gone by since my previous article, what feels like an eternity, and yet feels like a day — Nothing and everything has happened. All I can add to the situation in my country, that I've already drawn countless times, is that my expectations weren't fulfilled. Indeed, after a governmental void and a horrific explosion engulfing a tremendous part of the capital, I'm not sure any words can express the conflicting feelings and anger I have. Sentimentalities aside, let's get to what I've been up to.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Sat, 17 Oct 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/programming/2020/10/17/october-projects.html</guid></item><item><title>How to extract plain text from an HTML page in Python</title><link>https://stribny.name/posts/how-to-extract-plain-text-from-an-html-page-in-python/</link><author>Posts by Petr Stribny</author><pubDate>Fri, 16 Oct 2020 22:49:14 GMT</pubDate><guid isPermaLink="true">https://stribny.name/posts/how-to-extract-plain-text-from-an-html-page-in-python/</guid></item><item><title>Always beware of mathwashing!</title><link>https://stop.zona-m.net/2020/10/always-beware-of-mathwashing/</link><description>&lt;p&gt;You still don&amp;rsquo;t know how mathwashing may hurt you? Keep reading, then.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 16 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/always-beware-of-mathwashing/</guid></item><item><title>Intermedia Workshop Notes 1999-2003</title><link>https://mbutler.org/intermedia-workshop-notes-1999-2003/</link><description>Matthew T. Butler Intermedia Workshop notes University of Iowa 1999-2003 Intermedia Writing explores language from a visual arts perspective. It examines the relationship between word and image as well as word as image. It asks, &amp;#8220;How can we write with video, with paint, with our bodies? How does language function in the artist&amp;#8217;s studio?&amp;#8221; Intermedia [&amp;#8230;]</description><author>mbutler</author><pubDate>Fri, 16 Oct 2020 18:46:09 GMT</pubDate><guid isPermaLink="true">https://mbutler.org/intermedia-workshop-notes-1999-2003/</guid></item><item><title>Lenses Matter</title><link>https://bastibe.de/2020-10-16-lenses-matter.html</link><description>&lt;p&gt;A common trope in discussions about cameras on the internet is: “sensor size trumps all”, and as a corollary, “smartphone cameras suck”. Which is obviously false to anyone who has ever taken a good picture on a smartphone (with its tiny sensor).&lt;/p&gt;
&lt;p&gt;The argument, however, goes like this: Bigger pixels&lt;sup class="footnote-ref" id="fnref-1"&gt;&lt;a href="#fn-1"&gt;1&lt;/a&gt;&lt;/sup&gt; can capture a greater dynamic range, and bigger sensors are made from bigger pixels. Therefore, and here is the dangerous leap, cameras with bigger sensors take better pictures.&lt;/p&gt;
&lt;p&gt;But I currently have a bit of time on my hands, and way too many cameras, so let's try it out, shall we?&lt;/p&gt;
&lt;p&gt;My five contestants are:&lt;/p&gt;
&lt;img src="/static/2020-10/cameras.thumb.jpg" style="width: 70%; padding-left: 15%; padding-top: 5px; padding-bottom: 10px;" /&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;a href="https://en.wikipedia.org/wiki/Pixel_2"&gt;Google Pixel 2&lt;/a&gt;, with a 12.2 MP 5.75 × 4.32 mm “1/2.55 in” sensor from 2017, and a 3.8 mm f/1.8 lens (27 mm f/13 equivalent, crop 7.14),&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://en.wikipedia.org/wiki/Pentax_Q7"&gt;Pentax Q7&lt;/a&gt;, with a 12 MP 7.44 × 5.58 mm “1/1.7 in” sensor from 2013, and a 5-15 mm f/2.8-4.5 lens (24-70 mm f/13-22 equivalent, crop 4.76),&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://en.wikipedia.org/wiki/Panasonic_Lumix_DMC-LX100"&gt;Panasonic LX100&lt;/a&gt;, with a 13 MP, cropped 17.3 × 13 mm “micro four thirds” sensor from 2014, and a 11-34 mm f/1.7-2.8 lens (24-75 mm f/3.8-6 equivalent, crop 2.2),&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://en.wikipedia.org/wiki/Ricoh_GR_(large_sensor_compact_camera"&gt;Ricoh GR&lt;/a&gt;), with a 16 MP 23.7 × 15.7 mm “APS-C” sensor from 2013, and a 28 mm f/2.8 lens (27 mm f/4.2 equivalent, crop 1.5),&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://en.wikipedia.org/wiki/Fujifilm_X-T2"&gt;Fujifilm X-T2&lt;/a&gt;, with a 24 MP 23.6 × 15.6 mm “APS-C” sensor from 2016, and a 18-135 mm f/3.5-5.6 lens (27-200 mm f/5.25-8.4 equivalent, crop 1.5).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I went for a walk around the neighborhood, and took a few pictures with a bag full of cameras. In particular, I was looking for a high dynamic range scene, in the form of a sunset. All pictures were taken at a low ISO&lt;sup class="footnote-ref" id="fnref-2"&gt;&lt;a href="#fn-2"&gt;2&lt;/a&gt;&lt;/sup&gt; and underexposed by two stops to account for the backlighting. All images were taken at 27 mm (equivalent&lt;sup class="footnote-ref" id="fnref-3"&gt;&lt;a href="#fn-3"&gt;3&lt;/a&gt;&lt;/sup&gt;) focal length.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://photonstophotos.net/Charts/PDR.htm#FujiFilm%20X-T2,Google%20Pixel%202,Panasonic%20Lumix%20DMC-LX100,Pentax%20Q7,Ricoh%20GR"&gt;Measurements predict&lt;/a&gt; that the dynamic range and noise levels of these cameras should get better as the sensor size increases.&lt;/p&gt;
&lt;br /&gt;
&lt;a href="/static/2020-10/scene-1-lightbox.html" target="_blank"&gt;
  &lt;div class="lightbox" style="height: 200px;"&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 1 Google Pixel 2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Google Pixel 2&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 1 Pentax Q7.thumb.jpg" /&gt;
      &lt;figcaption&gt;Pentax Q7&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 1 Panasonic DMC-LX100.thumb.jpg" /&gt;
      &lt;figcaption&gt;Panasonic LX100&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 1 Ricoh GR.thumb.jpg" /&gt;
      &lt;figcaption&gt;Ricoh GR&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 1 Fujifilm X-T2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Fujifilm X-T2&lt;/figcaption&gt;
    &lt;/figure&gt;
  &lt;/div&gt;
&lt;/a&gt;

&lt;p&gt;The first scene was taken essentially in auto mode, and adjusted in Darktable to match roughly in tonality (exposure adjustments of ±0.25EV), but not color. In general, all cameras were able to capture the entire dynamic range of this scene, from the brightest almost-white area around the sun, to the darkest patches in the shade near the waterline.&lt;/p&gt;
&lt;p&gt;This, right off the bat, is the most important result of this experiment: &lt;em&gt;Most scenes do not have enough dynamic range to matter&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Differences appear in the noise levels, which are fairly constant across all cameras, with only the X-T2 being noticeably less noisy than the rest. However, this advantage of the X-T2 is not one of sensor size (the Ricoh GR has a same-size sensor), but simply of being two-generations &lt;em&gt;newer&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The largest difference between these photos is instead in flare: The Pixel 2, Pentax Q7 and Ricoh GR are flaring across the entire image, while the LX100 and X-T2 are far more controlled. This is probably because the Pixel 2 and Ricoh GR have collected dust and scratches from my pockets, and the Pentax Q7 lens being somewhat mediocre. The LX100 and X-T2 are in a better condition, and a better design, too. All lenses also show some amount of colorful lens flares to the bottom-right of the sun, particularly in the LX100 and Pentax Q7, and strange, colored rings around the edge of the Ricoh GR's frame.&lt;/p&gt;
&lt;br /&gt;
&lt;a href="/static/2020-10/scene-2-lightbox.html" target="_blank"&gt;
  &lt;div class="lightbox" style="height: 200px;"&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Google Pixel 2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Google Pixel 2&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Pentax Q7.thumb.jpg" /&gt;
      &lt;figcaption&gt;Pentax Q7&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Panasonic DMC-LX100.thumb.jpg" /&gt;
      &lt;figcaption&gt;Panasonic LX100&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Ricoh GR.thumb.jpg" /&gt;
      &lt;figcaption&gt;Ricoh GR&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Fujifilm X-T2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Fujifilm X-T2&lt;/figcaption&gt;
    &lt;/figure&gt;
  &lt;/div&gt;
&lt;/a&gt;

&lt;p&gt;To look into these differences between lenses in more detail, the second scene was taken from a slightly different spot, with the lenses stopped down (if possible). This image includes two bright sun spots, one from the sun itself, and one in the reflection on the water.&lt;/p&gt;
&lt;p&gt;Notably, the Pixel 2, like most smartphones, can not change its aperture. And it produces a bright red flare towards the left edge of the image. The Pentax Q7 again flares dramatically and colorful, and my Ricoh GR's lens is probably beyond cleaning at this point, judging from the massive flare it produces. Again, the standout pictures here are the X-T2 and LX100, with well-defined sun stars and comparatively little flaring. (Note the red dots in the X-T2: these are the phase-detection pixels on the X-T2's sensor reflecting light back into the lens and back on the image.)&lt;/p&gt;
&lt;br /&gt;
&lt;a href="/static/2020-10/scene-2-crop-lightbox.html" target="_blank"&gt;
  &lt;div class="lightbox" style="height: 200px;"&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Crop Google Pixel 2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Google Pixel 2&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Crop Pentax Q7.thumb.jpg" /&gt;
      &lt;figcaption&gt;Pentax Q7&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Crop Panasonic DMC-LX100.thumb.jpg" /&gt;
      &lt;figcaption&gt;Panasonic LX100&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Crop Ricoh GR.thumb.jpg" /&gt;
      &lt;figcaption&gt;Ricoh GR&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 2 Crop Fujifilm X-T2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Fujifilm X-T2&lt;/figcaption&gt;
    &lt;/figure&gt;
  &lt;/div&gt;
&lt;/a&gt;

&lt;p&gt;Here is an enlargement of the dark patch at the right edge of the second scene, to judge noise levels and detail in the shadow. Perhaps surprisingly, the differences between these images are not big at all. The X-T2 clearly wins in terms of both shadow detail and noise levels, but by a rather small margin, and only really visible when enlarged. The Pentax Q7 resolves almost no detail in the shadow, but neither does the Ricoh GR. So sensor size does not seem to affect this round.&lt;/p&gt;
&lt;br /&gt;
&lt;a href="/static/2020-10/scene-3-lightbox.html" target="_blank"&gt;
  &lt;div class="lightbox" style="height: 200px;"&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Google Pixel 2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Google Pixel 2&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Pentax Q7.thumb.jpg" /&gt;
      &lt;figcaption&gt;Pentax Q7&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Panasonic DMC-LX100.thumb.jpg" /&gt;
      &lt;figcaption&gt;Panasonic LX100&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Ricoh GR.thumb.jpg" /&gt;
      &lt;figcaption&gt;Ricoh GR&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Fujifilm X-T2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Fujifilm X-T2&lt;/figcaption&gt;
    &lt;/figure&gt;
  &lt;/div&gt;
&lt;/a&gt;

&lt;p&gt;This third scene was shot one day later, with settings optimized for optimal image quality: Base ISO, aperture one stop closed from wide open, focused on a high-contrast part of the scene. I processed these images with white balance from a grey card, then edited exposure, contrast, and saturation to match across images. Chromatic aberrations and vignetting were corrected using a profile or by hand. No sharpening was applied, but the highest-quality deinterlacing was selected (AMaZe for Bayer sensors, Markensteijn 3-pass for X-Trans sensors).&lt;/p&gt;
&lt;p&gt;At this magnification, even my 24in/4K screen only barely hints at differences in sharpness. Which implies that prints up to A3 should be possible from all of these cameras without much difference in perceived sharpness.&lt;/p&gt;
&lt;br /&gt;
&lt;a href="/static/2020-10/scene-3-crop-lightbox.html" target="_blank"&gt;
  &lt;div class="lightbox" style="height: 200px;"&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Crop Google Pixel 2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Google Pixel 2&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Crop Pentax Q7.thumb.jpg" /&gt;
      &lt;figcaption&gt;Pentax Q7&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Crop Panasonic DMC-LX100.thumb.jpg" /&gt;
      &lt;figcaption&gt;Panasonic LX100&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Crop Ricoh GR.thumb.jpg" /&gt;
      &lt;figcaption&gt;Ricoh GR&lt;/figcaption&gt;
    &lt;/figure&gt;
    &lt;figure&gt;
      &lt;img src="/static/2020-10/Scene 3 Crop Fujifilm X-T2.thumb.jpg" /&gt;
      &lt;figcaption&gt;Fujifilm X-T2&lt;/figcaption&gt;
    &lt;/figure&gt;
  &lt;/div&gt;
&lt;/a&gt;

&lt;p&gt;If we crop into these images, differences in detail resolution indeed become apparent. The Pentax Q7 is definitely the least detailed, on account of its soft lens. The Pixel 2 and LX100 show a very similar amount of details, which is a testament to how good modern smart phone cameras truly have become. While the two cameras with the biggest sensors, the Ricoh GR and the X-T2, do resolve visibly more detail, the differences are not dramatic.&lt;/p&gt;
&lt;p&gt;So does sensor size trump all? From these experiments, I wouldn't say so. Essentially, all of these cameras took decent images. The X-T2 clearly was better than the rest, but not hugely so, while being &lt;em&gt;much&lt;/em&gt; bigger and more expensive and newer.&lt;/p&gt;
&lt;p&gt;While the measured dynamic range differences surely exist, they did not manifest even in a sunrise, so I'm inclined to discount their importance. This is, frankly, not what I expected. The miniscule differences in resolution were equally unexpected.&lt;/p&gt;
&lt;p&gt;What did however make a big difference was lens quality. Flare control, aperture range, and focal range play a huge role in the resulting image quality. Zooming in (and stopping down) are still the most effective way of extracting more detail from a scene. And having a camera with a secure grip that is quick to operate helps, too. I think I am growing out of sensor size snobbery, is what I'm saying.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;&lt;p&gt;technically, “sensor elements”, not “picture elements”, i.e. “sensels”&lt;a class="footnote" href="#fnref-1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn-2"&gt;&lt;p&gt;lower ISO → less noise.&lt;a class="footnote" href="#fnref-2"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn-3"&gt;&lt;p&gt;the focal length a lens on a 35 mm film camera would need to cover the same angle of view.&lt;a class="footnote" href="#fnref-3"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>bastibe.de</author><pubDate>Fri, 16 Oct 2020 15:14:00 GMT</pubDate><guid isPermaLink="true">https://bastibe.de/2020-10-16-lenses-matter.html</guid></item><item><title>Talking to Strangers: What We Should Know About the People We Don’t Know</title><link>https://apurva-shukla.me/bookshelf/talking-to-strangers/</link><description>⭐ ⭐ ⭐ ⭐ ⭐ You’re complex, why can’t we think of strangers the same way? Throughout a series of case studies Gladwell attempts to answer why…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Fri, 16 Oct 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/bookshelf/talking-to-strangers/</guid></item><item><title>Flexbile Python use in Blender</title><link>https://ciesie.com/post/blender_flexible_python/</link><description>&lt;p&gt;This post is about using Python in &lt;em&gt;Blender&lt;/em&gt;. It&amp;rsquo;s not a tutorial. It&amp;rsquo;s more of an inspiration
to learn and experiment with Python.&lt;/p&gt;
&lt;p&gt;Imagine you work on a piece. The first stage is very experimental. You look for what works and what
doesn&amp;rsquo;t. At some point the piece and the process take shape. Some things become repetitive. It&amp;rsquo;s
very useful to notice those patterns early and optimize them.&lt;/p&gt;
&lt;p&gt;Lets say I&amp;rsquo;m working in &lt;em&gt;ZBrush&lt;/em&gt; and I want to render in &lt;em&gt;Blender&lt;/em&gt;. The geometry moves between
those two pretty often. Exporting and importing takes quite a few clicks. All that clicking adds
up and nibbles at my, that day&amp;rsquo;s, energy.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Fri, 16 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/blender_flexible_python/</guid></item><item><title>Simple video buffering loader in React</title><link>https://muffinman.io/blog/react-simple-video-buffering-loader/</link><description>&lt;article class="article"&gt;&lt;p&gt;For multiple projects, I had to add a simple video component with
&lt;span class="sidenote__text" tabindex="0"&gt;play/pause button&lt;/span&gt;&lt;span class="sidenote__note"&gt;&lt;span class="sidenote__note-inner"&gt;&lt;span class="sidenote__note-text"&gt;Always include at least basic video controls for accessibility&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
and a buffering loader. It is not hard to detect the buffering state, but it can be tricky to get everything right.&lt;/p&gt;
&lt;p&gt;Therefore, I created a simple component which I now copy from project to project with slight style adjustments. Jump to &lt;a href="#code"&gt;the code&lt;/a&gt; if you are not interested in how it&amp;#x27;s made.&lt;/p&gt;
&lt;h2 id="demo"&gt;Demo &lt;a class="anchor-link" href="#demo"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Here you can see the final version (it might be easier to see the functionality if you &lt;a href="https://codepen.io/stanko/pen/WNxwreJ" target="_blank"&gt;open it in a separate tab&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id="how-it-works"&gt;How it works &lt;a class="anchor-link" href="#how-it-works"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The solution is simple and relies on four video events:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;waiting&lt;/code&gt; - playback has stopped because of a temporary lack of data&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pause&lt;/code&gt; - playback has been paused&lt;/li&gt;
&lt;li&gt;&lt;code&gt;play&lt;/code&gt; - playback has begun&lt;/li&gt;
&lt;li&gt;&lt;code&gt;playing&lt;/code&gt; - playback is ready to start after having been paused or delayed due to lack of data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are going to use &lt;code&gt;waiting&lt;/code&gt; event to set our loading flag to &lt;code&gt;true&lt;/code&gt; and all other events to set it to &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If the video is already playing, and buffering happens, we&amp;#x27;ll get events fired in this order:&lt;/p&gt;
&lt;pre class="language-shell"&gt;&lt;code class="language-shell code-highlight"&gt;&lt;span class="code-line"&gt;&lt;span class="token string"&gt;&amp;quot;waiting&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token string"&gt;&amp;quot;playing&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is all fine and dandy, but if the video is paused, and we play it things get a little messy.
Now, if buffering happens, we&amp;#x27;ll get these events fired:&lt;/p&gt;
&lt;pre class="language-shell"&gt;&lt;code class="language-shell code-highlight"&gt;&lt;span class="code-line"&gt;&lt;span class="token string"&gt;&amp;quot;play&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token string"&gt;&amp;quot;playing&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token string"&gt;&amp;quot;waiting&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token string"&gt;&amp;quot;playing&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of these events are fired in a very quick succession and alter the state too fast leading to some bad UX. The secret is to add a short debounce time to avoid it. What I found to work best is 200ms for &lt;code&gt;waiting&lt;/code&gt; event and 50ms for all others.&lt;/p&gt;
&lt;h2 id="code"&gt;Code &lt;a class="anchor-link" href="#code"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&amp;#x27;m using React with hooks, but the same thing can be easily ported to React class or vanilla JavaScript.&lt;/p&gt;
&lt;pre class="language-tsx"&gt;&lt;code class="language-tsx code-highlight"&gt;&lt;span class="code-line"&gt;&lt;span class="token keyword"&gt;import&lt;/span&gt; &lt;span class="token imports"&gt;&lt;span class="token maybe-class-name"&gt;React&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt; useEffect&lt;span class="token punctuation"&gt;,&lt;/span&gt; useState&lt;span class="token punctuation"&gt;,&lt;/span&gt; useRef &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class="token keyword"&gt;from&lt;/span&gt; &lt;span class="token string"&gt;&amp;#x27;react&amp;#x27;&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token constant"&gt;PLAYING_DEBOUNCE_TIME&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;50&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token constant"&gt;WAITING_DEBOUNCE_TIME&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token number"&gt;200&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token function-variable function"&gt;Video&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt; src&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token spread operator"&gt;...&lt;/span&gt;props &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;isPlaying&lt;span class="token punctuation"&gt;,&lt;/span&gt; setIsPlaying&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;useState&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;false&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;isWaiting&lt;span class="token punctuation"&gt;,&lt;/span&gt; setIsWaiting&lt;span class="token punctuation"&gt;]&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;useState&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;false&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token keyword"&gt;const&lt;/span&gt; isWaitingTimeout &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;useRef&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token keyword"&gt;null&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token keyword"&gt;const&lt;/span&gt; isPlayingTimeout &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;useRef&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token keyword"&gt;null&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token keyword"&gt;const&lt;/span&gt; videoElementRef &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;useRef&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token function"&gt;useEffect&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token keyword"&gt;if&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token operator"&gt;!&lt;/span&gt;videoElementRef&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token keyword"&gt;return&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token punctuation"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token function-variable function"&gt;waitingHandler&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token function"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;isWaitingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      isWaitingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;setTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;        &lt;span class="token function"&gt;setIsWaiting&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;true&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token constant"&gt;WAITING_DEBOUNCE_TIME&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token function-variable function"&gt;playHandler&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token function"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;isWaitingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token function"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;isPlayingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      isPlayingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;setTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;        &lt;span class="token function"&gt;setIsPlaying&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;true&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;        &lt;span class="token function"&gt;setIsWaiting&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;false&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token constant"&gt;PLAYING_DEBOUNCE_TIME&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token function-variable function"&gt;pauseHandler&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token function"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;isWaitingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token function"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;isPlayingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      isPlayingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token function"&gt;setTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;        &lt;span class="token function"&gt;setIsPlaying&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;false&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;        &lt;span class="token function"&gt;setIsWaiting&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token boolean"&gt;false&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token constant"&gt;PLAYING_DEBOUNCE_TIME&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token keyword"&gt;const&lt;/span&gt; element &lt;span class="token operator"&gt;=&lt;/span&gt; videoElementRef&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;addEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;waiting&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; waitingHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;addEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;play&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; playHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;addEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;playing&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; playHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;addEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;pause&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; pauseHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token comment"&gt;// clean up&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token keyword"&gt;return&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token function"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;isWaitingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token function"&gt;clearTimeout&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;isPlayingTimeout&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;removeEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;waiting&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; waitingHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;removeEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;play&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; playHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;removeEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;playing&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; playHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      element&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;removeEventListener&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;&amp;quot;pause&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; pauseHandler&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;,&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;videoElementRef&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token keyword"&gt;const&lt;/span&gt; &lt;span class="token function-variable function"&gt;handlePlayPauseClick&lt;/span&gt; &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token arrow operator"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token keyword"&gt;if&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;videoElementRef&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token keyword"&gt;if&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;isPlaying&lt;span class="token punctuation"&gt;)&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;        videoElementRef&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;pause&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token punctuation"&gt;}&lt;/span&gt; &lt;span class="token keyword"&gt;else&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;        videoElementRef&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token property-access"&gt;current&lt;/span&gt;&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token method function property-access"&gt;play&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;      &lt;span class="token punctuation"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token punctuation"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token keyword"&gt;return&lt;/span&gt; &lt;span class="token punctuation"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;    &lt;span class="token tag"&gt;&lt;span class="token tag"&gt;&lt;span class="token punctuation"&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class="token attr-name"&gt;className&lt;/span&gt;&lt;span class="token attr-value"&gt;&lt;span class="token punctuation attr-equals"&gt;=&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;SimpleVideo&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="token plain-text"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token plain-text"&gt;      &lt;/span&gt;&lt;span class="token tag"&gt;&lt;span class="token tag"&gt;&lt;span class="token punctuation"&gt;&amp;lt;&lt;/span&gt;video&lt;/span&gt; &lt;span class="token spread"&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;span class="token spread operator"&gt;...&lt;/span&gt;props&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class="token attr-name"&gt;ref&lt;/span&gt;&lt;span class="token script language-javascript"&gt;&lt;span class="token script-punctuation punctuation"&gt;=&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;videoElementRef&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class="token attr-name"&gt;src&lt;/span&gt;&lt;span class="token script language-javascript"&gt;&lt;span class="token script-punctuation punctuation"&gt;=&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;src&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class="token attr-name"&gt;className&lt;/span&gt;&lt;span class="token attr-value"&gt;&lt;span class="token punctuation attr-equals"&gt;=&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;SimpleVideo-video&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="token plain-text"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token plain-text"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token plain-text"&gt;      &lt;/span&gt;&lt;span class="token tag"&gt;&lt;span class="token tag"&gt;&lt;span class="token punctuation"&gt;&amp;lt;&lt;/span&gt;button&lt;/span&gt; &lt;span class="token attr-name"&gt;onClick&lt;/span&gt;&lt;span class="token script language-javascript"&gt;&lt;span class="token script-punctuation punctuation"&gt;=&lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;handlePlayPauseClick&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class="token attr-name"&gt;className&lt;/span&gt;&lt;span class="token attr-value"&gt;&lt;span class="token punctuation attr-equals"&gt;=&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;SimpleVideo-playPause&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="token plain-text"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token plain-text"&gt;        &lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;isPlaying &lt;span class="token operator"&gt;?&lt;/span&gt; &lt;span class="token string"&gt;&amp;quot;Pause&amp;quot;&lt;/span&gt; &lt;span class="token operator"&gt;:&lt;/span&gt; &lt;span class="token string"&gt;&amp;quot;Play&amp;quot;&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token plain-text"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token plain-text"&gt;        &lt;/span&gt;&lt;span class="token punctuation"&gt;{&lt;/span&gt;isWaiting &lt;span class="token operator"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="token tag"&gt;&lt;span class="token tag"&gt;&lt;span class="token punctuation"&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class="token attr-name"&gt;className&lt;/span&gt;&lt;span class="token attr-value"&gt;&lt;span class="token punctuation attr-equals"&gt;=&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;SimpleVideo-loader&lt;span class="token punctuation"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="token plain-text"&gt;Buffering&lt;/span&gt;&lt;span class="token tag"&gt;&lt;span class="token tag"&gt;&lt;span class="token punctuation"&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token plain-text"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token plain-text"&gt;      &lt;/span&gt;&lt;span class="token tag"&gt;&lt;span class="token tag"&gt;&lt;span class="token punctuation"&gt;&amp;lt;/&lt;/span&gt;button&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="token plain-text"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token plain-text"&gt;    &lt;/span&gt;&lt;span class="token tag"&gt;&lt;span class="token tag"&gt;&lt;span class="token punctuation"&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class="token punctuation"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;  &lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class="code-line"&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/article&gt;</description><author>Muffin Man</author><pubDate>Fri, 16 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/blog/react-simple-video-buffering-loader/</guid></item><item><title>Let's Peek: A tale of finding "Waypoint"</title><link>https://caiustheory.com/lets-peek/</link><description>&lt;p&gt;Following a product launch at work earlier this year, I theorised if someone was watching the published lists of SSL Certificates they could potentially sneak a peak at things before they were publicised. Probably far too much noise to monitor continuously, but as a potential hint towards naming of things with a more targeted search it might be useful. Sites like &lt;a href="https://crt.sh/"&gt;https://crt.sh/&lt;/a&gt; and &lt;a href="https://censys.io/certificates"&gt;https://censys.io/certificates&lt;/a&gt; make these logs searchable and queryable.&lt;/p&gt;
&lt;p&gt;Fast forward to this week, where at &lt;a href="https://digital.hashiconf.com/"&gt;HashiConf Digital&lt;/a&gt; &lt;a href="https://hashicorp.com/"&gt;HashiCorp&lt;/a&gt; are announcing two new products, which they&amp;rsquo;ve been teasing for a month or so. Watching &lt;a href="https://boundaryproject.io/"&gt;Boundary&lt;/a&gt; get announced in the HashiConf opening keynote I then wondered what the second project might be called.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve spent a chunk of the last month looking at various HashiCorp documentation for their projects, and I noticed they have a pattern recently of using &lt;code&gt;&amp;lt;name&amp;gt;project.io&lt;/code&gt; as the product websites. The newly announced Boundary also fits this pattern.&lt;/p&gt;
&lt;p&gt;🤔 Could I figure out the second product name 24 hours before public release? &lt;a href="https://twitter.com/Caius/status/1316435256875143168"&gt;Amazingly, yes&lt;/a&gt;! 🎉&lt;/p&gt;
&lt;p&gt;Searching at random for all certificates issued for &lt;code&gt;*project.io&lt;/code&gt; was probably going to be a bit futile, so to narrow the search space slightly I started by looking at when &lt;code&gt;boundaryproject.io&lt;/code&gt; had its certificate issued, and who by. The list of things I spotted were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Common name is &amp;ldquo;boundaryproject.io&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Issued by LetsEncrypt (no real surprise there)&lt;/li&gt;
&lt;li&gt;Issued on 2020-09-23&lt;/li&gt;
&lt;li&gt;Leaf certificate&lt;/li&gt;
&lt;li&gt;Not yet expired (still trusted)&lt;/li&gt;
&lt;li&gt;No alternate names in the certificate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Loading up &lt;a href="https://censys.io/certificates"&gt;https://censys.io/certificates&lt;/a&gt; and building a query for this, resulted in a regexp lookup against the common name, and an issued at date range of 10 days, just before and a week after the boundary certificate issued date.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;parsed.subject.common_name:/[a-z]+project\.io/ AND
parsed.issuer.organization.raw:&amp;quot;Let's Encrypt&amp;quot; AND
parsed.validity.start:[&amp;quot;2020-09-20&amp;quot; TO &amp;quot;2020-09-30&amp;quot;] AND
tags.raw:&amp;quot;leaf&amp;quot; AND
tags.raw:&amp;quot;trusted&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href="https://censys.io/certificates?q=parsed.subject.common_name%3A%2F%5Ba-z%5D%2Bproject%5C.io%2F+AND+parsed.issuer.organization.raw%3A%22Let%27s+Encrypt%22+AND+tags.raw%3A%22leaf%22+AND+tags.raw%3A%22trusted%22+AND+parsed.validity.start%3A%5B%222020-09-20%22+TO+%222020-09-30%22%5D"&gt;Run the search yourself&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Searching brought back a couple of pages of results, I scanned them by eye and copied out the ones that only had the single name in the certificate which resulted in the following shortlist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;boundaryproject.io&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;essenceproject.io&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lumiereproject.io&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;techproject.io&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;udproject.io&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vesselproject.io&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;waypointproject.io&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We already know about Boundary, so the fact I found it in our list suggests the query &lt;em&gt;might&lt;/em&gt; have captured the new product site too. Loading all these sites in a web browser showed some had password protection on them (ooh!) and some just plain didn’t load (ooh!), and some others were blatently other things (boo!). Removing the latter ones left us with a much shorter list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;essenceproject.io&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;udproject.io&lt;/code&gt;&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;waypointproject.io&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All domains on the internet have to point somewhere, using DNS records. On a hunch I looked up a couple of the existing HashiCorp websites to see if they happened to all point at the same IP Address(es).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ host boundaryproject.io
boundaryproject.io has address 76.76.21.21
$ host nomadproject.io
nomadproject.io has address 76.76.21.21
$ host hashicorp.com | head -1
hashicorp.com has address 76.76.21.21
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ah ha, now I wonder if any of the shortlist also points to &lt;code&gt;76.76.21.21&lt;/code&gt; 🤔&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;$ host essenceproject.io | head -1
essenceproject.io has address 198.185.159.145
$ host udproject.io | head -1
udproject.io has address 137.74.116.3
$ host waypointproject.io
waypointproject.io has address 76.76.21.21
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;🎉 Excellent, &lt;a href="https://waypointproject.io"&gt;https://waypointproject.io&lt;/a&gt; was a password protected site pointed at HashiCorp&amp;rsquo;s IP address 🎉&lt;/p&gt;
&lt;p&gt;I then wondered if I could verify this somehow ahead of waiting for the second keynote. I firstly &lt;a href="https://twitter.com/Caius/status/1316435256875143168"&gt;tweeted about it&lt;/a&gt; but didn&amp;rsquo;t name Waypoint explicitly, just hid &amp;ldquo;way&amp;rdquo; and &amp;ldquo;point&amp;rdquo; in the tweet. I got a reply from &lt;a href="https://twitter.com/ksatirli/status/1316435508046815234"&gt;@ksatirli&lt;/a&gt; which suggested it was correct (and then later &lt;a href="https://twitter.com/mitchellh/status/1316468703584645121"&gt;@mitchellh&lt;/a&gt; confirmed it.&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;)&lt;/p&gt;
&lt;p&gt;HashiCorp also does a lot in public, and all the source code and related materials are on GitHub so perhaps some of their commit messages or marketing sites will contain reference to Waypoint. One github search later across their organisation: &lt;a href="https://github.com/search?q=org%3Ahashicorp+waypoint&amp;amp;type=issues"&gt;https://github.com/search?q=org%3Ahashicorp+waypoint&amp;amp;type=issues&lt;/a&gt; and I&amp;rsquo;d discovered a commit in the newly-public &lt;code&gt;hashicorp/boundary-ui&lt;/code&gt; repo which references Waypoint: &lt;a href="https://github.com/hashicorp/boundary-ui/commit/346f76404d9a0c90dedbccdd3d2c228572eb5ec1"&gt;346f76404&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;chore: tweak colors to match waypoint and for a11y&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Good enough for me, now to wait and see what the project is for. Given it&amp;rsquo;s now all announced and live, you can just visit &lt;a href="https://waypointproject.io"&gt;https://waypointproject.io&lt;/a&gt; to find out! (It&amp;rsquo;s so much cooler/useful than I&amp;rsquo;d hoped for.)&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;I so hope whoever registered this was going for UDP in the name, rather than UD Project.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;I&amp;rsquo;m a massive fan of IP address related quirks. Facebook&amp;rsquo;s IPv6 address contains &lt;code&gt;face:b00c&lt;/code&gt; for example. A nice repeating &lt;code&gt;76.76.21.21&lt;/code&gt; is almost IPv4 art somehow.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Secrets are more fun when they are kept secret. 🥳&amp;#160;&lt;a class="footnote-backref" href="#fnref:3"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Caius Theory</author><pubDate>Thu, 15 Oct 2020 22:00:00 GMT</pubDate><guid isPermaLink="true">https://caiustheory.com/lets-peek/</guid></item><item><title>Websoft giants are doing great</title><link>https://stop.zona-m.net/2020/10/websoft-giants-are-doing-great/</link><description>&lt;p&gt;Do you know HOW great?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 15 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/websoft-giants-are-doing-great/</guid></item><item><title>Étude in C minor</title><link>https://zserge.com/posts/etude-in-c/</link><description>Let me start with a picture.
int main() {float f ;char c;int d,o;while(scanf( "%d%c%d ",&amp;amp;d,&amp;amp;c,&amp;amp;o) &amp;gt;0){c&amp;amp;=31;for(f=!(c&amp;gt;&amp;gt;4)*55,c=(c*8/5+8)%12+o* 12-24;c--;f*=1.0595); for(d=16e3/d;d--; putchar(d*f *.032)) ;}} I don&amp;rsquo;t really draw well, so I used formatted C code instead. That was supposed to be a triangular sound wave written in C. In fact, this very C code plays two-octave melodies written in text notation from stdin.
It&amp;rsquo;s only 160 bytes, fits into a modern-day tweet, and the reason it&amp;rsquo;s there is to show how simple it is to create minimal music with code in any programming language, not just the special languages like CSound, ChucK, or SonicPi.</description><author>zserge's blog</author><pubDate>Thu, 15 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/etude-in-c/</guid></item><item><title>Using dynamic SQL query in Redshift database</title><link>https://www.rasikjain.com/posts/using-sql-dynamic-queries-in-redshift-database/</link><description>While working with a client, we had a requirement to perform bulk insert/update using Retool table and Redshift database. For this situation, We had to loop through the table records and execute a dynamic SQL query in Redshift.
Redshift database supports execution of dynamic SQL with the help of Prepared Statements or Stored Procedures.
Prepared Statements We use prepared statements when we want to execute dynamic SQL queries directly without a stored procedure.</description><author>Rasik Jain - Senior Architect | Generative AI &amp;amp; Full-Stack Engineering</author><pubDate>Thu, 15 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.rasikjain.com/posts/using-sql-dynamic-queries-in-redshift-database/</guid></item><item><title>Hacktoberfest 2020: Government edition</title><link>https://daniel.do/article/hacktoberfest-2020-govcon-edition</link><description>Focusing entirely on government contributions this year.</description><author>Daniel Immke</author><pubDate>Thu, 15 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://daniel.do/article/hacktoberfest-2020-govcon-edition</guid></item><item><title>A foreigner's opinion on Walt Disney's debts, or bailouts</title><link>https://stop.zona-m.net/2020/10/a-foreigners-opinion-on-walt-disneys-debts-or-bailouts/</link><description>&lt;p&gt;Disney is too big for something else, not failure.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 14 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/a-foreigners-opinion-on-walt-disneys-debts-or-bailouts/</guid></item><item><title>Future of Copyright &amp;amp; Competition Law in Media</title><link>https://ecollections.law.fiu.edu/lawreview/vol14/iss2/6/</link><author>Essays by Matthew Eric Bassett</author><pubDate>Wed, 14 Oct 2020 19:20:00 GMT</pubDate><guid isPermaLink="true">https://ecollections.law.fiu.edu/lawreview/vol14/iss2/6/</guid></item><item><title>Class Unloading in Layered Java Applications</title><link>https://www.morling.dev/blog/class-unloading-in-layered-java-applications/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_do_we_really_need_plug_ins"&gt;Do We Really Need Plug-ins?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_plug_ins_in_layered_java_applications"&gt;Plug-ins in Layered Java Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_class_unloading_in_practice"&gt;Class Unloading in Practice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_if_things_go_wrong"&gt;If Things Go Wrong&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_learning_more"&gt;Learning More&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Layers are sort of the secret sauce of the Java platform module system (JPMS):
by providing fine-grained control over how individual JPMS modules and their classes are loaded by the JVM,
they enable advanced usages like loading multiple versions of a given module, or dynamically adding and removing modules at application runtime.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;The &lt;a href="https://www.morling.dev/blog/introducing-layrry-runner-and-api-for-modularized-java-applications/"&gt;Layrry&lt;/a&gt; API and launcher provides a small plug-in API based on top of layers,
which for instance can be used to dynamically add plug-ins contributing new views and widgets to a running JavaFX application.
If such plug-in gets removed from the application again,
all its classes need to be unloaded by the JVM, avoiding an ever-increasing memory consumption if for instance a plug-in gets updated multiple times.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;In this blog post I’m going to explore how to ensure classes from removed plug-in layers are unloaded in a timely manner,
and how to find the culprit in case some class fails to be unloaded.&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Wed, 14 Oct 2020 18:45:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/class-unloading-in-layered-java-applications/</guid></item><item><title>HashMap 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/10/14/HashMap.html</link><description>&lt;h1 id="hashmap"&gt;HashMap&lt;/h1&gt;
&lt;p&gt;HashMap 实现了 Map 接口，用于存储键值对，与 Hashtable 不同的是，HashMap &lt;strong&gt;允许 null 元素&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;HashMap 具有两个性能相关的参数：&lt;strong&gt;初始容量(&lt;em&gt;initial capacity&lt;/em&gt;)&lt;/strong&gt;和&lt;strong&gt;负载因子(&lt;em&gt;load factor&lt;/em&gt;)&lt;/strong&gt;， 容量是指 HashMap &lt;strong&gt;桶（&lt;em&gt;buckets&lt;/em&gt;）&lt;/strong&gt;的容量，初始容量即 HashMap 在创建时桶的默认大小。&lt;/p&gt;

&lt;p&gt;负载因子默认是 &lt;strong&gt;0.75&lt;/strong&gt;，默认初始容量是 &lt;strong&gt;16&lt;/strong&gt;，初始容量如果设置过大会导致遍历时间变长，但可以降低 &lt;strong&gt;resize&lt;/strong&gt; 的次数，需要结合场景自己权衡。&lt;/p&gt;

&lt;p&gt;在容量达到阈值后会进行扩容，扩容后容量为当前的&lt;strong&gt;两倍&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;另外设置的初始容量并不代表实际数组的初始大小，而是会根据设定值找到一个最近的 &lt;strong&gt;2 的次幂&lt;/strong&gt;当做初始容量。而因为每次扩容都是两倍，所以也保证了数组长度一直是 &lt;strong&gt;2 的次幂&lt;/strong&gt;。
&lt;!--more--&gt;
HashMap 是&lt;strong&gt;非线程安全&lt;/strong&gt;的，可以通过 Collections 类获取同步的包装对象：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;synchronizedMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;(...));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;HashMap 的迭代器被设计为 &lt;strong&gt;fail-fast&lt;/strong&gt; 的，如果迭代器创建完成后 HashMap 的结构被修改，迭代器将会抛出&lt;strong&gt;ConcurrentModificationException&lt;/strong&gt;异常。&lt;/p&gt;

&lt;p&gt;HashMap 采用&lt;strong&gt;数组+链表/红黑树&lt;/strong&gt;的数据结构，当链表长度大于等于 &lt;strong&gt;8&lt;/strong&gt; 时链表将转换为红黑树。&lt;/p&gt;

&lt;h1 id="源码"&gt;源码&lt;/h1&gt;
&lt;p&gt;HashMap 的源码相比较之前的集合要多很多，主要是因为 1.8 之后引入了红黑树，很多代码都是对红黑树的操作。&lt;/p&gt;

&lt;h2 id="构造器"&gt;构造器&lt;/h2&gt;
&lt;p&gt;我们先看看初始化：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Illegal initial capacity: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loadFactor&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nc"&gt;Float&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isNaN&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Illegal load factor: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadFactor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tableSizeFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;tableSizeFor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;构造器中除了对两个入参做了合法性检测之外就是调用了&lt;code class="language-plaintext highlighter-rouge"&gt;tableSizeFor&lt;/code&gt;方法计算扩容阈值，而这个值也会被当成数组的初始大小。&lt;code class="language-plaintext highlighter-rouge"&gt;tableSizeFor&lt;/code&gt;方法的一系列位运算骚操作即可保证返回值是最接近给定参数的一个 2 的次幂。&lt;/p&gt;

&lt;h2 id="putk-v"&gt;put(K, V)&lt;/h2&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;putVal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="nf"&gt;putVal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;onlyIfAbsent&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
               &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;evict&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// 初始化数组&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// 通过哈希值计算该 key 的数组索引并判断该位置是否已经存在数据，&lt;/span&gt;
        &lt;span class="c1"&gt;// 没有则创建一个新的链表&lt;/span&gt;
        &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 该索引已存在数据：链表或红黑树&lt;/span&gt;
        &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;))))&lt;/span&gt;
            &lt;span class="c1"&gt;// key 已存在，后面会直接更新 value&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;// key 不存在，且当前索引位置的元素为红黑树&lt;/span&gt;
            &lt;span class="c1"&gt;// 则将该键值对插入红黑树中&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;putTreeVal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// key 不存在，且当前索引位置的元素为链表&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;binCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;binCount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// 创建链表节点并插入到链表末尾&lt;/span&gt;
                    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="no"&gt;TREEIFY_THRESHOLD&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// -1 for 1st&lt;/span&gt;
                        &lt;span class="c1"&gt;// 链表长度大于阈值后开始将链表转换成红黑树&lt;/span&gt;
                        &lt;span class="n"&gt;treeifyBin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                        &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;))))&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// existing mapping for key&lt;/span&gt;
            &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;onlyIfAbsent&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="c1"&gt;// 更新 value&lt;/span&gt;
                &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;afterNodeAccess&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;oldValue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;modCount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(++&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// 长度大于阈值后进行 resize 操作&lt;/span&gt;
        &lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;afterNodeInsertion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evict&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;内容主要在&lt;code class="language-plaintext highlighter-rouge"&gt;putVal&lt;/code&gt;中，通过哈希值计算索引的算法也很简单：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;// n 为数组的长度&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为之前保证过数组长度永远是 2 的次幂，所以对&lt;code class="language-plaintext highlighter-rouge"&gt;n - 1&lt;/code&gt;进行 &amp;amp; 运算相当于求余，从而保证索引在数组内。&lt;/p&gt;

&lt;p&gt;再将元素添加到链表中后会判断是否需要转换成红黑树，需要的话则会调用&lt;code class="language-plaintext highlighter-rouge"&gt;treeifyBin&lt;/code&gt;转换，最后还会调用&lt;code class="language-plaintext highlighter-rouge"&gt;resize&lt;/code&gt;方法进行扩容。&lt;/p&gt;

&lt;h2 id="treeifybinnodekv-int"&gt;treeifyBin(Node&amp;lt;K,V&amp;gt;[], int)&lt;/h2&gt;
&lt;p&gt;该方法用于将链表转换成红黑树。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;treeifyBin&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;MIN_TREEIFY_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// 链表节点转换成树节点&lt;/span&gt;
            &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;replacementTreeNode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tl&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;hd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;tl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hd&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;hd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;treeify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;遍历链表所有节点，将其转换成树节点，此时只是把链表节点转换成了树节点，还没有称为红黑树，等到节点全部转换完成后调用&lt;code class="language-plaintext highlighter-rouge"&gt;hd.treeify(tab)&lt;/code&gt;方法才会调整为红黑树。&lt;/p&gt;

&lt;h2 id="resize"&gt;resize()&lt;/h2&gt;
&lt;p&gt;当数组长度超出阈值后会进行 resize 操作，该操作会创建一个两倍大小的数组，并对数据进行重新分配。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;oldTab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oldCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldTab&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;oldTab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oldThr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// 初始化新的数组大小与新的阈值&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newCap&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newThr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldCap&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldCap&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MAX_VALUE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;oldTab&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 超过最大值则不进行扩容&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;newCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldCap&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                 &lt;span class="n"&gt;oldCap&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="no"&gt;DEFAULT_INITIAL_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;newThr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldThr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 扩容为原来的两倍&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldThr&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// initial capacity was placed in threshold&lt;/span&gt;
        &lt;span class="n"&gt;newCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldThr&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;               &lt;span class="c1"&gt;// zero initial threshold signifies using defaults&lt;/span&gt;
        &lt;span class="n"&gt;newCap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DEFAULT_INITIAL_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;newThr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)(&lt;/span&gt;&lt;span class="no"&gt;DEFAULT_LOAD_FACTOR&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;DEFAULT_INITIAL_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newThr&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;newCap&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;newThr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCap&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="no"&gt;MAXIMUM_CAPACITY&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
                  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;ft&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MAX_VALUE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newThr&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// 创建新的数组&lt;/span&gt;
    &lt;span class="nd"&gt;@SuppressWarnings&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s"&gt;"rawtypes"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"unchecked"&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
        &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;newTab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;[])&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newCap&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newTab&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldTab&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 将旧数组中的数据迁移到新的数组中&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;oldCap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldTab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;oldTab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;// 删除数组中的引用，防止内存泄漏&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;newTab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCap&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;// 链表只有一个元素直接存入新的数组即可&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;TreeNode&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newTab&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oldCap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 将红黑树中移入新的数组&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// preserve order&lt;/span&gt;
                    &lt;span class="c1"&gt;// 将链表从旧数组移入到新的数组&lt;/span&gt;
                    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;loHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loTail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hiHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hiTail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;oldCap&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loTail&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                                &lt;span class="n"&gt;loHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                            &lt;span class="k"&gt;else&lt;/span&gt;
                                &lt;span class="n"&gt;loTail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                            &lt;span class="n"&gt;loTail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="o"&gt;}&lt;/span&gt;
                        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hiTail&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                                &lt;span class="n"&gt;hiHead&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                            &lt;span class="k"&gt;else&lt;/span&gt;
                                &lt;span class="n"&gt;hiTail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                            &lt;span class="n"&gt;hiTail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="o"&gt;}&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loTail&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;loTail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="n"&gt;newTab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loHead&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hiTail&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;hiTail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="n"&gt;newTab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;oldCap&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hiHead&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;newTab&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description><author>张可的博客</author><pubDate>Wed, 14 Oct 2020 18:16:27 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/10/14/HashMap.html</guid></item><item><title>De-Agonizing Performance Self-Evaluations</title><link>https://ivymike.dev/de-agonizing-performance-self-evaluations.html</link><description>&lt;p&gt;When I worked at medium-to-large companies, I used to dread the yearly "performance self-assessments".  Not that I didn't want a raise, but writing about my own performance was agonizing.  It reminded me of writing college entrance essays, another torturous process for me.&lt;/p&gt;
&lt;p&gt;But at some point, I figured out the …&lt;/p&gt;</description><author>IvyMike.dev</author><pubDate>Wed, 14 Oct 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://ivymike.dev/de-agonizing-performance-self-evaluations.html</guid></item><item><title>What's "good" code and does it matter?</title><link>https://ntietz.com/blog/does-good-code-really-matter/?utm_source=atom&amp;utm_medium=feed</link><description>&lt;p&gt;I take pride in my work and in writing good code, and it's important sometimes to take a step back and ask: what does that even mean? And does it matter?&lt;/p&gt;
&lt;p&gt;At a high level, "good code" is code that is suitable for its purpose and achieves its goals. That definition is pretty lacking, though, I think. You can write some very very hacky prototypes that achieve their goals—proving out an idea—while also being pretty objectively bad code. But objectively, by what measure?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is where we get back into what it means for code to really be suitable for its purpose. Code is a living thing. It is written, edited, read, and used, in order of increasing frequency: most code will be used far more often than it is edited, read far more often than it is edited, and edited far more often than it's newly written. This means that for code to be good, it has to support these activities. It has to do its job well when it's used. It has to be able to be read. It has to be able to be updated.&lt;/p&gt;
&lt;p&gt;A great deal has been written already on how code can do its job well. The short summary here is that it has to do what is expected (per the spec, if you are fortunate enough to have one) and have few defects. On the non-functional side, it has to also do what's expected in a reasonable amount of time, reliably. It doesn't matter how free of bugs your program is if it literally never terminates. And sometimes a "reasonable amount of time" might actually be a floor on the time for things like bcrypt, which we &lt;em&gt;want&lt;/em&gt; to make reasonably slow.&lt;/p&gt;
&lt;p&gt;Supporting reading and editing go hand-in-hand, because they are core parts of maintaining a codebase. You cannot really edit a codebase confidently if you cannot read it and understand what it's doing, and you cannot fix bugs or add features if you cannot edit it confidently. While tests are a big portion of this, they are distinct from the quality of the code under test. In an ideal world, they add assurance, but the code itself should have a clear design that presents itself. It should be designed from the outset to be extensible.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;But does that really capture what we're doing day-to-day? I'm a software engineer, not a computer programmer. While I take pride in writing good code, my job is not to produce good code but to effectively solve problems, usually using code. In practice, engineering means you have to make tradeoffs.&lt;/p&gt;
&lt;p&gt;When you're trying to solve a problem, but you're not sure exactly how to solve it, you reach for prototypes and proofs of concept. These will be sufficient to test an idea and validate the approach, but you can cut a lot of corners on them. The code doesn't look good, it's almost certainly not maintainable long-term. But is this a good engineering decision? In a lot of cases, yes! It's the right tradeoff to make.&lt;/p&gt;
&lt;p&gt;Similarly, you can write the absolute best code you have ever created for that shiny new feature, but... realistically, you're probably working on it in a business, and realistically, improving that quality to make it super readable and super extensible won't deliver value to the business. It really depends on how much the code will be extended and read, and it's also a tradeoff between time now (for a startup burning cash, time right &lt;em&gt;now&lt;/em&gt; is in very short supply!) and time later (once you get profitable or take another infusion of cash from &lt;del&gt;rich suckers&lt;/del&gt; venture capitalists, you can afford to rewrite things).&lt;/p&gt;
&lt;p&gt;This comes back in a lot of decisions you have to make as a software engineer. If you design a super-scalable system that can handle all the traffic you will need three years from now... well, that growth will probably never materialize, because you did not spend that time developing your product right &lt;em&gt;now&lt;/em&gt;. It's often a better decision to write something that works okay for now, and refactor/rewrite later when you need to scale up.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;So, does writing good code matter?&lt;/p&gt;
&lt;p&gt;It does, to an extent. Your code has to be good enough to do its job, which is usually to deliver value and to optimize more for the here and now than down the road, scale that might never materialize. If your code does its job well enough and it can be (maybe somewhat painfully) maintained and updated for a couple of years, well, by the time those two years are gone you may well have rewritten it anyway! If you'd spent twice as long at the outset writing your magnus opus, that time would have been wasted.&lt;/p&gt;
&lt;p&gt;Your code can't be a dumpster fire. It probably shouldn't be the Mona Lisa, either. Striking a balance is an important facet of engineering for all things, ranging from the quality of your code (good, but not &lt;em&gt;too&lt;/em&gt; good!) to how much scale to handle (enough, but don't over-engineer it!) to how much coffee to drink (just kidding, never too much coffee).&lt;/p&gt;</description><author>ntietz.com blog - technically a blog</author><pubDate>Wed, 14 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ntietz.com/blog/does-good-code-really-matter/?utm_source=atom&amp;utm_medium=feed</guid></item><item><title>Telegraf: dynamically adding custom tags</title><link>https://srijan.ch/telegraf-dynamic-tags</link><description>Adding a custom tag to data coming in from an input plugin for telegraf</description><author>Srijan Choudhary, all posts</author><pubDate>Wed, 14 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://srijan.ch/telegraf-dynamic-tags</guid></item><item><title>Car design will improve forever</title><link>https://stop.zona-m.net/2020/10/car-design-will-improve-forever/</link><description>&lt;p&gt;But only if it has those two features.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 13 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/car-design-will-improve-forever/</guid></item><item><title>Stop useEffect from running on every render with useCallback</title><link>https://maxrozen.com/stop-useeffect-running-every-render-with-usecallback</link><description>Did ESLint tell you to add a function to your dependency array, and now you're getting infinite re-renders? Let's learn how useEffect can help.</description><author>Max Rozen</author><pubDate>Tue, 13 Oct 2020 12:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/stop-useeffect-running-every-render-with-usecallback</guid></item><item><title>3D Printing Garden Cage Hinges</title><link>https://ivymike.dev/3d-printing-garden-cage-hinges.html</link><description>&lt;p&gt;My girlfriend's COVID-19 hobby is gardening--broccoli, greens, carrots, radishes, you name it.  The only problem has been the rascally neighborhood squirrels and raccoons, who insist on digging in the raised garden beds, ruining her crops.  A few weeks ago, with a friend's help, we built PVC cages as protection. PVC …&lt;/p&gt;</description><author>IvyMike.dev</author><pubDate>Tue, 13 Oct 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://ivymike.dev/3d-printing-garden-cage-hinges.html</guid></item><item><title>Follow up: Intentional Documentation</title><link>https://blog.harterrt.com/int_d11n_preso.html</link><description>&lt;p&gt;Last week I presented the idea of 
&lt;a href="https://blog.harterrt.com/randy_au_d11n.html"&gt;Intentional Documentation&lt;/a&gt;
to Mozilla's data science team.
Here's a &lt;a href="/static/int_d11n/"&gt;link to the slides&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The rest of this post is a transcription of what I shared with the team
(give or take).&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In Q4, I'm trying to build a set of trainings
to help …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Tue, 13 Oct 2020 04:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/int_d11n_preso.html</guid></item><item><title>Setting up Raspberry Pi 3 with PiHole</title><link>https://heitorpb.github.io/bla/rasp3-pihole/</link><description>How to setup PiHole on a Raspberry Pi.</description><author>Heitor's log</author><pubDate>Tue, 13 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://heitorpb.github.io/bla/rasp3-pihole/</guid></item><item><title>Nokia Composer in 512 bytes</title><link>https://zserge.com/posts/nokia/</link><description>Those who ever owned an old Nokia phone like 3310 or 3210 might still remember its wonderful ability to compose your own ringtones straight on the phone&amp;rsquo;s keyboard. By arranging notes and pauses you could end up with a popular tune beeped out of the phone&amp;rsquo;s speaker, and furthermore, you could share it with your friends! If you missed that era, here&amp;rsquo;s how it looked like:
Unimpressed? Well, trust me, it was really cool back then especially if you are into music.</description><author>zserge's blog</author><pubDate>Tue, 13 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/nokia/</guid></item><item><title>Another Amazon problem: its returns do not return</title><link>https://stop.zona-m.net/2020/10/another-amazon-problem-its-returns-do-not-return/</link><description>&lt;p&gt;But it&amp;rsquo;s not only Amazon.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 12 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/another-amazon-problem-its-returns-do-not-return/</guid></item><item><title>AmpliBox - a Self Hosted File Storage App with AWS Amplify</title><link>https://www.swyx.io/amplify-storage-demo</link><description>A demo using AWS S3 (Simple Storage Service) using Amplify Storage, Svelte, and Tailwind CSS</description><author>swyx's site RSS Feed</author><pubDate>Mon, 12 Oct 2020 18:35:04 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/amplify-storage-demo</guid></item><item><title>Hashtable 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/10/12/Hashtable.html</link><description>&lt;h1 id="hashtable"&gt;Hashtable&lt;/h1&gt;
&lt;p&gt;Hashtable 实现了 Map 接口，用于存储键值对，&lt;strong&gt;禁止 null 元素&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;用作键的对象必须保证&lt;code class="language-plaintext highlighter-rouge"&gt;hashCode&lt;/code&gt;与&lt;code class="language-plaintext highlighter-rouge"&gt;equals&lt;/code&gt;的可用性。&lt;/p&gt;

&lt;p&gt;Hashtable 是&lt;strong&gt;线程安全&lt;/strong&gt;的，但一般来说，如果不需要考虑线程安全问题可以使用 &lt;strong&gt;HashMap&lt;/strong&gt; 作为替代，如果需要线程安全的高并发哈希表可以使用 &lt;strong&gt;ConcurrentHashMap&lt;/strong&gt;，总的来说就是，一般不需要使用 HashTable。&lt;/p&gt;

&lt;p&gt;Hashtable 具有两个性能相关的参数：&lt;strong&gt;初始容量(&lt;em&gt;initial capacity&lt;/em&gt;)&lt;/strong&gt;和&lt;strong&gt;负载因子(&lt;em&gt;load factor&lt;/em&gt;)&lt;/strong&gt;， 容量是指 HashTable &lt;strong&gt;桶（&lt;em&gt;buckets&lt;/em&gt;）&lt;/strong&gt;的容量，初始容量即 HashTable 在创建时桶的默认大小。在哈希冲突的情况下，每个桶会通过&lt;strong&gt;链表&lt;/strong&gt;存储多条数据。
&lt;!--more--&gt;
负载因子默认是 &lt;strong&gt;0.75&lt;/strong&gt;，一般来说该值是最佳值。&lt;/p&gt;

&lt;p&gt;当 HashTable 容量超出负载因子时将会进行 &lt;strong&gt;rehash&lt;/strong&gt; 操作，该操作会对所有数据的位置进行重新分配，是耗时操作。&lt;/p&gt;

&lt;p&gt;HashTable 的迭代器被设计为 &lt;strong&gt;fail-fast&lt;/strong&gt; 的，如果迭代器创建完成后 Hashtable 的结构被修改，迭代器将会抛出&lt;strong&gt;ConcurrentModificationException&lt;/strong&gt;异常。但 Hashtable 本身的&lt;code class="language-plaintext highlighter-rouge"&gt;get&lt;/code&gt;及&lt;code class="language-plaintext highlighter-rouge"&gt;put&lt;/code&gt;方法并不是 fail-fast 的。&lt;/p&gt;

&lt;p&gt;但迭代器也并不能保证准确的 fail-fast，只会尽最大努力的抛出异常。&lt;/p&gt;

&lt;h1 id="源码"&gt;源码&lt;/h1&gt;
&lt;p&gt;Hashtable 存储的是键值对，在内部会将键值封装成一个&lt;code class="language-plaintext highlighter-rouge"&gt;Entry&amp;lt;K,V&amp;gt;&lt;/code&gt;对象，我们先看看这个类：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKey&lt;/span&gt;&lt;span class="o"&gt;()==&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKey&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;()==&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="nc"&gt;Objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Entry 类主要是对键值对的封装，其中&lt;code class="language-plaintext highlighter-rouge"&gt;hash&lt;/code&gt;是键的&lt;code class="language-plaintext highlighter-rouge"&gt;hashCode&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;next&lt;/code&gt;表示下一个节点，我们上面也说过了，每个位置可能会存储多条数据，而存储方式就是链表。&lt;/p&gt;

&lt;p&gt;我们再看看类中定义的几个主要的参数：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;//当前Hashtable的实际大小&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;//扩容阈值 = capacity * loadFactor&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;//负载因子，默认0.75&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;负载因子可以用过构造器指定，&lt;code class="language-plaintext highlighter-rouge"&gt;threshold&lt;/code&gt;会在初始化时被设置，每次扩容也会更新。&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;table&lt;/code&gt;数组则是 Hashtable 的底层数据结构，用于存储数据，也就是上面说的桶，而数组的每个元素都是个链表。&lt;/p&gt;

&lt;h2 id="putkv"&gt;put(K,V)&lt;/h2&gt;
&lt;p&gt;再来通过一个典型的 put 方法看看其内部实现：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Make sure the value is not null&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NullPointerException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Makes sure the key is not already in the hashtable.&lt;/span&gt;
    &lt;span class="nc"&gt;Hashtable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7FFFFFFF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@SuppressWarnings&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unchecked"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(;&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;addEntry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们上面说过需要保证键的&lt;code class="language-plaintext highlighter-rouge"&gt;hashCode&lt;/code&gt;与&lt;code class="language-plaintext highlighter-rouge"&gt;equals&lt;/code&gt;的可用性，这里就可以看到原因，计算数组位置的依据就是&lt;code class="language-plaintext highlighter-rouge"&gt;hashCode&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;通过键来计算对应数组索引的算法很简单：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7FFFFFFF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;0x7FFFFFFF&lt;/code&gt;是&lt;code class="language-plaintext highlighter-rouge"&gt;Integer.MAX_VALUE&lt;/code&gt;的值，按位与这一步是为了防止索引值超出整型范围，然后根据数组长度求余可以将索引控制在数组范围内。&lt;/p&gt;

&lt;p&gt;下面的 for 循环是用来搜索 HashTable 中是否已经包含当前键对象，如果已经包含则直接更新&lt;code class="language-plaintext highlighter-rouge"&gt;value&lt;/code&gt;的值。&lt;/p&gt;

&lt;p&gt;否则调用&lt;code class="language-plaintext highlighter-rouge"&gt;addEntry&lt;/code&gt;方法将该键值对添加到 HashTable 中去。&lt;/p&gt;

&lt;h2 id="addentryint-k-v-int"&gt;addEntry(int, K, V, int)&lt;/h2&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addEntry&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;K&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;modCount&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;&lt;span class="c1"&gt;// 尽可能保证 fail-fast&lt;/span&gt;

    &lt;span class="nc"&gt;Hashtable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Rehash the table if the threshold is exceeded&lt;/span&gt;
        &lt;span class="n"&gt;rehash&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7FFFFFFF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Creates the new entry.&lt;/span&gt;
    &lt;span class="nd"&gt;@SuppressWarnings&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unchecked"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;首先判断当前数组是否已达到扩容阈值，达到则先进行 &lt;strong&gt;rehash&lt;/strong&gt; 操作，该操作会重新创建一个更大的数组，并重新分配所有的数据。&lt;/p&gt;

&lt;p&gt;rehash 操作完成后就可以将键值对信息组装成 Entry 并添加到&lt;code class="language-plaintext highlighter-rouge"&gt;table&lt;/code&gt;中。&lt;/p&gt;

&lt;h2 id="rehash"&gt;rehash()&lt;/h2&gt;
&lt;p&gt;rehash 操作时耗时操作，主要负责两个任务，一是扩容，二是重新分配数据位置。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;rehash&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;oldMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// overflow-conscious code&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;MAX_ARRAY_SIZE&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;MAX_ARRAY_SIZE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="c1"&gt;// Keep running with MAX_ARRAY_SIZE buckets&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MAX_ARRAY_SIZE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;[]&lt;/span&gt; &lt;span class="n"&gt;newMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;[&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

    &lt;span class="n"&gt;modCount&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
    &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;loadFactor&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;MAX_ARRAY_SIZE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;oldMap&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;old&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;old&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7FFFFFFF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;newCapacity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;K&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;)&lt;/span&gt;&lt;span class="n"&gt;newMap&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
            &lt;span class="n"&gt;newMap&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;每次的扩容大小是&lt;code class="language-plaintext highlighter-rouge"&gt;(oldCapacity &amp;lt;&amp;lt; 1) + 1&lt;/code&gt;也就是原来长度的&lt;strong&gt;两倍 + 1&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;如果长度已达到最大值，则不会进行扩容，而且在原来长度的基础上继续添加，此时数组上链表的长度会越来越长，扩容完成后会遍历所有数据重新分配位置。&lt;/p&gt;

&lt;h2 id="getobject"&gt;get(Object)&lt;/h2&gt;
&lt;p&gt;通过&lt;code class="language-plaintext highlighter-rouge"&gt;get&lt;/code&gt;方法获取对应键的值，没有则返回&lt;code class="language-plaintext highlighter-rouge"&gt;null&lt;/code&gt;。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="no"&gt;V&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hashCode&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x7FFFFFFF&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?,?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;V&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;先通过哈希值获取到数组的索引，然后遍历该索引处的链表，直到找到哈希值相同且&lt;code class="language-plaintext highlighter-rouge"&gt;equals&lt;/code&gt;方法返回&lt;code class="language-plaintext highlighter-rouge"&gt;true&lt;/code&gt;的值，然后返回该值，或者返回&lt;code class="language-plaintext highlighter-rouge"&gt;null&lt;/code&gt;。&lt;/p&gt;</description><author>张可的博客</author><pubDate>Mon, 12 Oct 2020 18:17:27 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/10/12/Hashtable.html</guid></item><item><title>Fix Steam 'Corrupt Update Files'</title><link>https://jmthornton.net/blog/p/steam-corrupt-update-files</link><description>How to fix the annoying error when downloading or updating some Steam games, which reports the error 'Corrupt Update Files'</description><author>Blog by Jade Michael Thornton</author><pubDate>Mon, 12 Oct 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://jmthornton.net/blog/p/steam-corrupt-update-files</guid></item><item><title>Return on Data: When governments fail to make surveillance useful</title><link>https://nikhilism.com/post/2020/return-on-data/</link><description>There is this common refrain about how companies have data about you and could do bad things. Yet governments often pass surveillance laws that are much worse, and by definition, you can&amp;rsquo;t &amp;ldquo;vote with your wallet&amp;rdquo; for them. So in a world where I&amp;rsquo;m already giving data to third parties, it is useful to ask what I get in return.
If we are talking about corporations, we get ads! Yes, but we also get:</description><author>Nikhil's blog</author><pubDate>Mon, 12 Oct 2020 05:34:02 GMT</pubDate><guid isPermaLink="true">https://nikhilism.com/post/2020/return-on-data/</guid></item><item><title>Notes on Time Management from a Dying Professor</title><link>https://www.swyx.io/time-management-randy-pausch</link><description>Notes on Randy Pausch's lecture on Time Management</description><author>swyx's site RSS Feed</author><pubDate>Mon, 12 Oct 2020 03:10:32 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/time-management-randy-pausch</guid></item><item><title>The wonders of a proxy auto-config (PAC) file</title><link>https://blog.imraniqbal.org/pac-file/</link><description>&lt;p&gt;How I improved my work from home setup using a &lt;a href="https://en.wikipedia.org/wiki/Proxy_auto-config" rel="external"&gt;proxy auto-config&lt;/a&gt; (PAC) file.&lt;/p&gt;</description><author>Imran's Blog</author><pubDate>Mon, 12 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.imraniqbal.org/pac-file/</guid></item><item><title>Phishing: Persuading People through a Voice Synthesized by AI - Part 1</title><link>https://serhack.me/articles/persuading-people-through-voice-ai-phishing-part-1/</link><description>I get between 10 to 20 emails per day and, usually, more than half of them are phishing attempts. Phishing attempts are a type of email scam that typically aims to obtain personal data of the victim, including username and password for email accounts and popular services (Gmail, Hotmail, mail.ru, Twitter, Amazon, etc.), through pages forged &lt;em&gt;ad hoc&lt;/em&gt; to simulate login sections. -&lt;a href="https://serhack.me/articles/persuading-people-through-voice-ai-phishing-part-1/"&gt;Continue to read the article on SerHack.me&lt;/a&gt;</description><author>SerHack - Security Researcher</author><pubDate>Mon, 12 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://serhack.me/articles/persuading-people-through-voice-ai-phishing-part-1/</guid></item><item><title>Untitled • Art</title><link>https://muffinman.io/art/3d-cubes-untitled/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;One plot ended up being smaller because I screwed up cutting it.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;October 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;15x15cm and 13x13cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Fabriano Bristol 250gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Molotow Blackliner, Koi Coloring Brush, Mechanical pencil&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="2500" src="./0.jpg" width="2500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="2200" src="./w_500-h_500--1.jpg" width="2200" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./plot_1920x1080.mp4"&gt;&lt;video class="gallery__video" src="./plot_1920x1080.mp4#t=0.001"&gt;&lt;/video&gt;&lt;svg class="gallery__play-icon" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20 c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Mon, 12 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/3d-cubes-untitled/</guid></item><item><title>Hello World</title><link>https://nyoom.io/posts/2020-10-12-hello-world/</link><description>&lt;p&gt;Decided to setup a blog to track some of the things that I wanted to work on, and maybe hold myself accountable.&lt;/p&gt;
&lt;p&gt;Stack:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Engine: &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Hosting: &lt;a href="https://docs.gitlab.com/ee/user/project/pages/"&gt;GitLab (Pages)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s actually surprising how easy it is to use the WebIDE inside of Gitlab. Means I don&amp;rsquo;t have to maintain an actual work environment,
though, I may end up to just keep using &lt;a href="https://www.gitpod.io/"&gt;Gitpod&lt;/a&gt; instead as state is maintained inside&amp;hellip;&lt;/p&gt;
&lt;p&gt;Who knows what lays ahead&amp;hellip;&lt;/p&gt;</description><author>Q. Marchi: A Blog</author><pubDate>Mon, 12 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nyoom.io/posts/2020-10-12-hello-world/</guid></item><item><title>Why I love teaching online</title><link>https://jasoneckert.github.io/myblog/why-i-love-teaching-online/</link><description>&lt;p&gt;&lt;img alt="OnlineTeaching" src="onlineteaching.jpg#center" title="OnlineTeaching" /&gt;&lt;/p&gt;
&lt;p&gt;When the pandemic hit earlier this year, schools around the globe quickly embraced online teaching to continue their curriculum. While online teaching wasn&amp;rsquo;t entirely new in this space, it certainly wasn&amp;rsquo;t the norm. This meant that many teachers had to adapt quickly, as these 2 funny videos illustrate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=CCe5PaeAeew"&gt;https://www.youtube.com/watch?v=CCe5PaeAeew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Zy_y9yOrgxk"&gt;https://www.youtube.com/watch?v=Zy_y9yOrgxk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, I&amp;rsquo;ve loved every part of this transition because I absolutely love teaching tech courses online.&lt;/p&gt;
&lt;p&gt;Grant you, I&amp;rsquo;ve had some practice prior to 2020, as well as a general interest in how the Web could be used for education. Back in the early 2000s, I designed and wrote all of the online Linux curriculum for Caldera (including the HTML and Perl scripts that hosted it). It was an early stab at online education that had as many faults as it did benefits, but I learned a great deal during the process. Years later, I got to refine what I learned during my online computer science courses at Nova Southeastern, as well as the Train-the-Trainer courses I taught for CompTIA. By this time, technology had caught up to the needs of education, and online education was quite mature with a set of common best practices and technologies that everyone implemented.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Mon, 12 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/why-i-love-teaching-online/</guid></item><item><title>Circular Gradients for the HTML5 Canvas</title><link>https://everttimberg.io/blog/js-circular-gradient/</link><description>Circular gradients are commonly used in pie or doughnut charts to change the colour of segment as the angle around the center of the chart changes. In many non web platforms, the ability to generate these gradients is provided as part of the standard APIs. For example, Android provides a SweepGradient. In the browsers, only Linear and Radial gradients are provided. Thus, if we want to a circular gradient, we&amp;rsquo;ll need to create our own.</description><author>Posts on Evert Timberg</author><pubDate>Mon, 12 Oct 2020 01:19:32 GMT</pubDate><guid isPermaLink="true">https://everttimberg.io/blog/js-circular-gradient/</guid></item><item><title>Billing pipeline: a critical time sensitive system</title><link>https://kevin.deldycke.com/2020/billing-pipeline-critical-time-sensitive-system</link><description>&lt;p&gt;
 This is an answer to
 &lt;a class="reference external" href="https://www.linkedin.com/in/antoine-veuiller/"&gt;
  Antoine Veuiller
 &lt;/a&gt;
 ’s article, an
 &lt;a class="reference external" href="https://medium.com/@aveuiller/stories-of-flaky-test-encounters-in-the-wild-a152bf7151f5"&gt;
  Introduction to Flaky Tests by Example
 &lt;/a&gt;
 , in which he shares his experience on tackling unstable&amp;nbsp;tests.
&lt;/p&gt;



&lt;p&gt;
 And I’m the author of the flaky tests he’s talking about!&amp;nbsp;😬
&lt;/p&gt;



&lt;section id="story-time"&gt;
 &lt;h1&gt;
  Story time!
  &lt;a class="headerlink" href="#story-time" title="Link to this heading"&gt;&amp;nbsp;¶
  &lt;/a&gt;
 &lt;/h1&gt;
 &lt;p&gt;
  I started designing and implementing Scaleway’s billing pipeline …&lt;/p&gt;&lt;/section&gt;</description><author>Kevin Deldycke</author><pubDate>Mon, 12 Oct 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://kevin.deldycke.com/2020/billing-pipeline-critical-time-sensitive-system</guid></item><item><title>2020–10–12: Backlight changes when swithcing between USB-C power modes</title><link>https://xnux.eu/log/#022</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 12 Oct 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#022</guid></item><item><title>[Computing] The different kinds of authentication protocols</title><link>https://www.devever.net/~hl/auth</link><description>&lt;p&gt;There are almost as many authentication protocols out there as there are
application protocols, making it a confusing landscape. Probably most confusing
of all is that attention rarely is drawn to the fact that there are many
different &lt;em&gt;kinds&lt;/em&gt; of authentication protocol, which seek to fill completely
different roles.&lt;/p&gt;</description><author>devever.net/~hl</author><pubDate>Sun, 11 Oct 2020 21:45:00 GMT</pubDate><guid isPermaLink="true">https://www.devever.net/~hl/auth</guid></item><item><title>Trying Different Camera Setups</title><link>https://web.navan.dev/posts/2020-10-11-macOS-Virtual-Cam-OBS.html</link><description>Comparison of different cameras setups for using as a webcam and tutorials for the same.</description><author>Navan's Archive</author><pubDate>Sun, 11 Oct 2020 19:12:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-10-11-macOS-Virtual-Cam-OBS.html</guid></item><item><title>ExoTracker Issues - Abandoning the grid</title><link>https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/</link><description>&lt;p&gt;Trackers have decades of design, with interlocking features and design decisions, many based on the assumption that every event is quantized on a grid:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You don't need lines above events, since it's obvious which row the event is in.
&lt;ul&gt;
&lt;li&gt;In regular trackers, events are treated as taking up height. Most events are triggered when the cursor enters them, but pattern-jump effects are triggered when the cursor exits them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Empty grid cells have dashes in them, to indicate an empty slot belonging to a subcolumn (note/instrument/volume/effect...) and row. (I refer to channels as columns, for historical reasons and because Renoise uses the same terminology.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ExoTracker's central feature is that events/notes no longer have to be quantized to a grid, but are stored as rational numbers (fractions) in terms of "beats". Events are mapped onto rows using a zoom level (rows per beat), and changing the zoom level causes notes to fall onto or off gridlines.&lt;/p&gt;
&lt;p&gt;(tl;dr: Skip forwards to &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/#per-digit-cursors"&gt;"Per-digit cursors"&lt;/a&gt; where the problems start.)&lt;/p&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_full_subcolumn_cursor.png"&gt;&lt;img alt="In ExoTracker, each subcolumn has a different background color. The instrument subcolumn has two digits plus padding. The cursor is located in the instrument subcolumn, and takes up both digits plus padding." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_full_subcolumn_cursor.png" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;In ExoTracker, each subcolumn has a different background color. The instrument subcolumn has two digits plus padding. The cursor is located in the instrument subcolumn, and takes up both digits plus padding.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As a result, many tracker conventions must be adapted to work with off-grid notes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Closely spaced notes/events can cause text to draw over other text. I programmed lower events to erase the text drawn by upper events.&lt;/li&gt;
&lt;li&gt;The "events have height" model breaks down when off-grid events exist and you can change the zoom level. So I draw a line above every note, representing the instant in time the event occurs at (which I find easier to reason about than 1-row-tall events).
&lt;ul&gt;
&lt;li&gt;Initially, for each event, I drew a line across all subcolumns (even empty ones), but that became confusing when combined with closely spaced events erasing text in only occupied subcolumns (not empty ones).&lt;/li&gt;
&lt;li&gt;So now only occupied subcolumns have lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pressing Delete 4 times will no longer delete all notes in the next 4 rows, because it won't erase events between rows.
&lt;ul&gt;
&lt;li&gt;I felt that the alternative, where pressing Delete also deletes notes in between rows, would be more confusing and inflexible for users.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;So I made "cursor step" both snap to the grid and off-grid notes... which is actually rather janky and surprising.
&lt;ul&gt;
&lt;li&gt;The issue is that my code snaps to all events in the channel, not just events with a non-empty value in the cursor X position's subcolumn. Changing this would complicate the code.&lt;/li&gt;
&lt;li&gt;To alleviate this, I turned off off-grid event snapping, and added a mode where pressing Delete (or entering a value) steps to the next event, regardless of the cursor's X subcolumn. This is useful for deleting many events, adding or changing instruments, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Trackers usually have gaps between note/event/volume/effect, so I add padding around each subcolumn.&lt;/li&gt;
&lt;li&gt;If empty grid cells are drawn with dashes, then on-grid notes will erase the dash. But it's not clear if off-grid or triplet notes should erase the dashes or not. I chose to replace dashes with horizontal gridlines. But they don't indicate subcolumns, so I add colored backgrounds.
&lt;ul&gt;
&lt;li&gt;One alternative would be to draw dashes before drawing events, and simply erase dashes whenever text overlaps them. This looks fine with on-grid events, but with off-grid events, you can end up with partial dashes which might look a bit ugly.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In retrospect, this was probably a better idea, since colored backgrounds proved to be a disaster.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="per-digit-cursors"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/#per-digit-cursors"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
Per-digit cursors&lt;/h2&gt;
&lt;p&gt;Everything was more-or-less working, until I added per-digit cursors and the setup broke down. Suddenly the cursor width became highly inconsistent; the cursor is wider when you place it in the leftmost or rightmost digit of a subcolumn.&lt;/p&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_cursor_positions.gif"&gt;&lt;img alt="The effect subcolumn has three positions, or one character plus two digits. The cursor is wider in the left and right subcolumn, and narrower in the center." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_cursor_positions.gif" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;The effect subcolumn has three positions, or one character plus two digits. The cursor is wider in the left and right subcolumn, and narrower in the center.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So I can make the cursor narrower... now there's a gap around the cursor. And several people have said the gap looks very weird, so this isn't a good solution.&lt;/p&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_gap_around_cursor.png"&gt;&lt;img alt="There is a gap between the left border of the subcolumn&amp;#x27;s background, and the cursor&amp;#x27;s left boundary. The same issue occurs with the right of each subcolumn." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_gap_around_cursor.png" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;There is a gap between the left border of the subcolumn's background, and the cursor's left boundary. The same issue occurs with the right of each subcolumn.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_gap_around_cursor_2.png"&gt;&lt;img alt="There is a gap between the note subcolumn&amp;#x27;s boundaries and the cursor&amp;#x27;s boundaries." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_gap_around_cursor_2.png" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;There is a gap between the note subcolumn's boundaries and the cursor's boundaries.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is actually what FamiTracker does too, but it doesn't look ugly because there aren't background stripes.&lt;/p&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/famitracker_cursor_positions.gif"&gt;&lt;img alt="I screen-recorded all cursor positions of FamiTracker into an animated GIF, and overlayed the frames into a single screenshot. There are gaps to the left and right of each subcolumn (note, instrument, volume, and effect). The composite screenshot is ugly." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/famitracker_cursor_positions.gif" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;I screen-recorded all cursor positions of FamiTracker into an animated GIF, and overlayed the frames into a single screenshot. There are gaps to the left and right of each subcolumn (note, instrument, volume, and effect). The composite screenshot is ugly.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So do I make the stripes narrower?&lt;/p&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_narrow_subcolumn_background.png"&gt;&lt;img alt="The background color is confined to the width filled by text and selectable by the cursor. There are gray stripes around each subcolumn. It&amp;#x27;s still ugly." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/exotracker_narrow_subcolumn_background.png" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;The background color is confined to the width filled by text and selectable by the cursor. There are gray stripes around each subcolumn. It's still ugly.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Get rid of the dividers too?&lt;/p&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/no_dividers.png"&gt;&lt;img alt="Now the subcolumn dividers are gone, replaced by gray stripes. It looks weird to have middle gaps wider than side gaps." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/no_dividers.png" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;Now the subcolumn dividers are gone, replaced by gray stripes. It looks weird to have middle gaps wider than side gaps.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So I can make them the same width... but then either the note lines overlap, or they have gaps, or the widths are inconsistent. This will cause problems with mouse handling as well.&lt;/p&gt;
&lt;figure class="image"&gt;
  &lt;a href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/no_dividers_rearranged.png"&gt;&lt;img alt="The gray lines are rearranged, such that the width between subcolumns equals the width between a subcolumn and a channel divider. The note lines overlap." src="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/no_dividers_rearranged.png" /&gt;&lt;/a&gt;
  &lt;figcaption&gt;The gray lines are rearranged, such that the width between subcolumns equals the width between a subcolumn and a channel divider. The note lines overlap.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="a-solution"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/#a-solution"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
A solution?&lt;/h2&gt;
&lt;p&gt;At this point, I feel that background stripes to indicate subcolumn boundaries, and cursors which occupy digits within a multi-digit subcolumn, are simply incompatible.&lt;/p&gt;
&lt;p&gt;If I want to keep that latter feature, I could remove background stripes and replace them with dashes, which are erased whenever text overlaps them. This looks fine with on-grid events, but with off-grid events, you can end up with partial dashes which might look a bit ugly.&lt;/p&gt;</description><author>nyanpasu64's blog</author><pubDate>Sun, 11 Oct 2020 05:16:00 GMT</pubDate><guid isPermaLink="true">https://nyanpasu64.gitlab.io/blog/exotracker-issues-abandoning-the-grid/</guid></item><item><title>Emacs: create a Swift package/project</title><link>https://xenodium.com/emacs-create-a-swift-packageproject</link><description>&lt;p&gt;Been playing around with &lt;a href="https://swift.org/package-manager/"&gt;Swift Package Manager (SPM)&lt;/a&gt;. Creating a new Swift package (ie. project) is pretty simple.&lt;/p&gt;
&lt;p&gt;To create a library package, we can use the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;swift package init --type library
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, to create a command-line utility use:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;swift package init --type executable
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out, there are a few options: empty, library, executable, system-module, manifest.&lt;/p&gt;
&lt;p&gt;With a little elisp, we can write a completing function to quickly generate a Swift package/project without the need to drop to the shell.&lt;/p&gt;
&lt;p&gt;Bonus: I won't have to look up SPM options if I ever forget them.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-create-swift-package/swift-package.gif" /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun ar/swift-package-init ()
  &amp;quot;Execute `swift package init', with optional name and completing type.&amp;quot;
  (interactive)
  (let* ((name (read-string &amp;quot;name (default): &amp;quot;))
         (type (completing-read
                &amp;quot;project type: &amp;quot;
                ;; Splits &amp;quot;--type empty|library|executable|system-module|manifest&amp;quot;
                (split-string
                 (nth 1 (split-string
                         (string-trim
                          (seq-find
                           (lambda (line)
                             (string-match &amp;quot;--type&amp;quot; line))
                           (process-lines &amp;quot;swift&amp;quot; &amp;quot;package&amp;quot; &amp;quot;init&amp;quot; &amp;quot;--help&amp;quot;)))
                         &amp;quot;   &amp;quot;))
                 &amp;quot;|&amp;quot;)))
         (command (format &amp;quot;swift package init --type %s&amp;quot; type)))
    (unless (string-empty-p name)
      (append command &amp;quot;--name &amp;quot; name))
    (shell-command command))
  (dired default-directory)
  (revert-buffer))
&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 11 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-create-a-swift-packageproject</guid></item><item><title>Setting up my blog</title><link>https://blog.imraniqbal.org/blog-setup/</link><description>&lt;p&gt;I wanted to use &lt;a href="https://v2.docusaurus.io/" rel="external"&gt;Docusaurus&lt;/a&gt; to setup my blog because I might be using it for work and wanted to test it out.
I am also a fan of the fact that it's a static site builder, which means I can use it with a free static site hosting solution.
I decided to go with &lt;a href="https://about.gitlab.com/stages-devops-lifecycle/pages/" rel="external"&gt;GitLab Pages&lt;/a&gt; because I am already using GitLab and it lets me use a custom domain.&lt;/p&gt;
&lt;h2 id="setting-up-the-gitlab-project"&gt;&lt;a class="anchor" href="https://blog.imraniqbal.org/blog-setup/#setting-up-the-gitlab-project"&gt;
    #
&lt;/a&gt;
Setting up the GitLab project&lt;/h2&gt;
&lt;p&gt;This was pretty straight forward. I followed this &lt;a href="https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_from_scratch.html" rel="external"&gt;guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First I created a simple enough html page.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span style="color: #F28779;"&gt;echo&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; 'This is me testing stuff.'&lt;/span&gt;&lt;span style="color: #F29E74;"&gt; &amp;gt;&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; index.html&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Followed by a &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;image&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; alpine:3.12.0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;workflow&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  rules&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #5CCFE6;"&gt; if&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; &amp;quot;$CI_COMMIT_BRANCH&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;pages&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  script&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; mkdir public&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; cp index.html public/index.html&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  artifacts&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;    paths&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; public&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  rules&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #5CCFE6;"&gt; if&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; '$CI_COMMIT_BRANCH == &amp;quot;master&amp;quot;'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then another quick &lt;a href="https://docs.gitlab.com/ee/user/project/pages/custom_domains_ssl_tls_certification/" rel="external"&gt;guide&lt;/a&gt; for setting up a custom domain + SSL certificate.&lt;/p&gt;
&lt;p&gt;And voilà!&lt;/p&gt;
&lt;p&gt;&lt;img alt="custom domain setup" src="https://blog.imraniqbal.org/img/initial_blog.png" /&gt;&lt;/p&gt;
&lt;h2 id="using-docusaurus"&gt;&lt;a class="anchor" href="https://blog.imraniqbal.org/blog-setup/#using-docusaurus"&gt;
    #
&lt;/a&gt;
Using Docusaurus&lt;/h2&gt;
&lt;p&gt;Like most modern JavaScript projects, to actually use Docusaurus I needed to first install an initializer that would setup a project for me.
The &lt;a href="https://v2.docusaurus.io/docs/installation" rel="external"&gt;install docs&lt;/a&gt; mentioned using &lt;code&gt;npx&lt;/code&gt; to install and use the initializer.&lt;/p&gt;
&lt;p&gt;This was my first time hearing about &lt;code&gt;npx&lt;/code&gt; and I wasn't too keen on installing yet another JavaScript tool on my system.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span style="color: #73D0FF;"&gt;yarn&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; add @docusaurus/init@next&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #73D0FF;"&gt;node&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; node_modules/@docusaurus/init/bin/index.js init my-blog classic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This seemed to work well enough, the sole issue was the Docusaurus files were now in a dir called &lt;code&gt;my-blog&lt;/code&gt; rather than my project root.&lt;/p&gt;
&lt;p&gt;First I needed to cleanup the install files then move everything in &lt;code&gt;my-blog&lt;/code&gt; a directory up.&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span style="color: #73D0FF;"&gt;rm&lt;/span&gt;&lt;span style="color: #95E6CB;"&gt; -rf&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; node_modules package.json yarn.lock&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #73D0FF;"&gt;mv&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; my-blog/&lt;/span&gt;&lt;span style="color: #5CCFE6; font-style: italic;"&gt;*&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #73D0FF;"&gt;rm&lt;/span&gt;&lt;span style="color: #95E6CB;"&gt; -rf&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; my-blog&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;yarn start&lt;/code&gt; now showed me the default Docusaurus project page. At this point all that I had to do was to follow the &lt;a href="https://v2.docusaurus.io/docs/blog#blog-only-mode" rel="external"&gt;Blog-only mode&lt;/a&gt; guide and customize to my needs.&lt;/p&gt;
&lt;p&gt;One annoying thing is that the &lt;code&gt;doc&lt;/code&gt; directory has to exist with a single &lt;code&gt;.md&lt;/code&gt; file in it to prevent Docusaurus from failing to start.&lt;/p&gt;
&lt;h2 id="updating-gitlab-ci-yml"&gt;&lt;a class="anchor" href="https://blog.imraniqbal.org/blog-setup/#updating-gitlab-ci-yml"&gt;
    #
&lt;/a&gt;
Updating &lt;code&gt;.gitlab-ci.yml&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Updated my CI configuration to use a node image and to cache &lt;code&gt;node_modules&lt;/code&gt;/yarn cache&lt;/p&gt;
&lt;pre class="giallo" style="color: #CCCAC2; background-color: #1F2430;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;image&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; node:14.13.1-alpine3.12&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;workflow&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  rules&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #5CCFE6;"&gt; if&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; &amp;quot;$CI_COMMIT_BRANCH&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;cache&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  key&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; &amp;quot;$CI_PROJECT_ID&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  paths&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; node_modules/&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; .yarn/&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;pages&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  script&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; yarn config set cache-folder .yarn&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; yarn install&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; yarn build --out-dir public&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  artifacts&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;    paths&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;      -&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; public&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span style="color: #5CCFE6;"&gt;  rules&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span style="color: #5CCFE6;"&gt; if&lt;/span&gt;&lt;span style="color: #CCCAC2B3;"&gt;:&lt;/span&gt;&lt;span style="color: #D5FF80;"&gt; '$CI_COMMIT_BRANCH == &amp;quot;master&amp;quot;'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description><author>Imran's Blog</author><pubDate>Sun, 11 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.imraniqbal.org/blog-setup/</guid></item><item><title>World smallest office suite</title><link>https://zserge.com/posts/awfice/</link><description>We are all familiar with a traditional office suite - a word processor, a spreadsheet, a presentation program, maybe a diagramming or note-taking app. We have seen it all in Microsoft Office and Google Docs. Those are really powerful and large. But what would be the most minimal amount of code required to build an office suite?
platform Obviously, our office suite won&amp;rsquo;t be a desktop GUI app - those require plenty of code and efforts to build one.</description><author>zserge's blog</author><pubDate>Sun, 11 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/awfice/</guid></item><item><title>Arrays, vectors and slices in Rust</title><link>https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In this post I will introduce you to arrays, vectors and slices in Rust. Programmers coming from C or C++ will already be familiar with arrays and vectors, but because of Rust's focus on safety there are some differences from their unsafe language counterparts. Slices, on the other hand, will entirely be a new, albeit a very useful concept.&lt;/p&gt;
&lt;h2 id="arrays"&gt;Arrays&lt;/h2&gt;
&lt;p&gt;Arrays are one of the first data types beginner programmers learn. An array is a collection of elements of the same type allocated in a contiguous memory block. For example, if you allocate an array like this:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; array&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;42&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 10&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 5&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then all the &lt;code&gt;i32&lt;/code&gt; integers are allocated next to each other on the stack:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="array memory layout" src="https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/array-layout.svg" /&gt;&lt;/p&gt;
&lt;p&gt;In Rust, an array's size is part of the type. For example, this code will not compile:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//error:expected an array with a fixed size of 4 elements,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//found one with 3 elements&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; array&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust's strictness also prevents problems like array to pointer decay in C/C++:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//C++ code&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;#include&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-storage"&gt;using namespace&lt;/span&gt;&lt;span&gt; std;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//Looks can be deceiving: arr is not a pointer&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//to an array of 5 integers. It has decayed to&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//a pointer to an integer.&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;void&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_array_size&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;*&lt;/span&gt;&lt;span&gt;arr)[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;5&lt;/span&gt;&lt;span&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 8 (the size of a pointer)&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    cout &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Array size in print_array_size function: &amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt; sizeof&lt;/span&gt;&lt;span&gt;(arr)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; endl;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    int&lt;/span&gt;&lt;span class="z-variable"&gt; arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;5&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 5&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 20 (size of 5 4-byte integers)&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    cout &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Array size in main function: &amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt; sizeof&lt;/span&gt;&lt;span&gt;(arr)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; endl;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    print_array_size&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;arr);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;    return&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;print_array_size&lt;/code&gt; function prints 8 instead of the expected 20 (5 integers of 4 bytes) because &lt;code&gt;arr&lt;/code&gt; has decayed from a pointer to an array of 5 integers to just a pointer to an integer.  Similar code in Rust does the right thing:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;use&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span&gt;mem&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span&gt;size_of_val;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_array_size&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;arr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 5&lt;/span&gt;&lt;span&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 20&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Array size in print_array_size function: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; size_of_val&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;arr&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; arr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 5&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 5&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //print 20&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Array size in main function: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; size_of_val&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;arr&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    print_array_size&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;arr&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another difference between an array in C/C++ and Rust is that accessing elements in Rust does bounds checking. For example, in the following C++ code, we try to access 5th element in an array of size 3. This produces &lt;a href="https://blog.regehr.org/archives/213" rel="external"&gt;undefined behaviour&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;#include&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-storage"&gt;using namespace&lt;/span&gt;&lt;span&gt; std;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;int&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    int&lt;/span&gt;&lt;span class="z-variable"&gt; arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;3&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    const auto&lt;/span&gt;&lt;span&gt; index &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;=&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 5&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //arr[index] is undefined behaviour&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    cout &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Integer at index &amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; index &lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;: &amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="z-variable"&gt; arr&lt;/span&gt;&lt;span&gt;[index]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; endl;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;    return&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While similar code in Rust is a panic:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; arr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; index&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 5&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //arr[index] panics with the following message:&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //index out of bounds: the len is 3 but the index is 5&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Integer at index &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-string"&gt;: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; index&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-variable"&gt;index&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might wonder, how is the Rust version better than the C++ version? Well, because the C++ version exhibits undefined behaviour, it gives a no holds barred license to the compiler to do anything in the name of optimizations. In the worst case, this can leak information to an attacker.&lt;/p&gt;
&lt;p&gt;The Rust version, in contrast, will always panic. Moreover, because the process terminates due to the panic, a programmer is more likely to notice and fix this bug. In contrast, C++ sweeps the problem under the rug and the process could carry on as if nothing had happened. I will take a Rust panic any day over a C/C++ undefined behaviour.&lt;/p&gt;
&lt;h2 id="vectors"&gt;Vectors&lt;/h2&gt;
&lt;p&gt;The big limitation of arrays is that they are fixed in size. In contrast, vectors can grow at runtime:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //There are three elements in the vector initially&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; vec!&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 3&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v has &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-string z-punctuation z-definition z-string"&gt; elements&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //but you can add more at runtime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;4&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 5&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v has &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-string z-punctuation z-definition z-string"&gt; elements&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;How does a vector allow dynamic growth? Internally, a vector keeps all the elements in an array allocated on the heap. When a new element is pushed, the vector checks if there is still some capacity left in the array. If not, the vector allocates a bigger array, copies all the elements to the new array and deallocates the old array. This can be seen in the following code:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; vec!&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 4&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v's capacity is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;capacity&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Address of v's first element: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:p&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;0&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;span class="z-comment"&gt;//{:p} prints the address&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 8&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v's capacity is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;capacity&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Address of v's first element: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:p&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;0&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Initially the capacity of the &lt;code&gt;v&lt;/code&gt;'s backing array is 4:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="Vector with capacity 4" src="https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/vec-capacity-4.svg" /&gt;&lt;/p&gt;
&lt;p&gt;A new element is then pushed onto the vector. This makes the vector copy all the elements to a new backing array of capacity 8:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="Vector with capacity 8" src="https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/vec-capacity-8.svg" /&gt;&lt;/p&gt;
&lt;p&gt;The program also prints the address of the first element of the array before and after pushing a new element onto the vector. Both these printed addresses will be different from each other. This change in addresses is clear evidence of a new array of size 8 being allocated behind the scenes.&lt;/p&gt;
&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
If you do not see a different address after pushing more elements onto a vector, it might be because the allocator had enough space at the end of the original buffer such that the new and the old buffers have the same starting address. Try pushing more elements and you will see a different address. Read about C library function &lt;code&gt;realloc&lt;/code&gt; to understand how this might happen.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;h2 id="slices"&gt;Slices&lt;/h2&gt;
&lt;p&gt;Slices act like temporary views into an array or a vector. For example if you have an array:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; arr&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;10&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 20&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 30&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 40&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can create a slice containing second and third elements like this:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;arr&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;..&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;[1..3]&lt;/code&gt; syntax creates a range from index 1 (inclusive)  to 3 (exclusive). If you omit the first number in the range (&lt;code&gt;[..3]&lt;/code&gt;) it defaults to zero and if you omit the last number (&lt;code&gt;[1..]&lt;/code&gt;) it defaults to the length of the array. If you print the elements in the &lt;code&gt;[1..3]&lt;/code&gt; slice, you get 20 and 30:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//prints 20&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;First element in slice: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;0&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//prints 30&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Second element in slice: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But if you try to access an element outside the range of the slice, it will panic:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//panics: index out of bounds&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Third element in slice: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;2&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But how does the slice know that it has only two elements? That's because a slice is not simply a pointer to the array, it also carries around the number of elements of the slice in an additional length field.&lt;/p&gt;
&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
        A pointer with some additional data besides just the address of the pointed to object is called a fat pointer. Slices are not the only kind of fat pointer in Rust. Trait objects, for example, carry a vtable pointer in addition to the pointer to an object.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;p&gt;For example, if you create a slice to a vector:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; vec!&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;..&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then in addition to a pointer to the second element in &lt;code&gt;v&lt;/code&gt;'s buffer, &lt;code&gt;s&lt;/code&gt; also has an 8 byte length field with value 2:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="Slice of a vector" src="https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/slice-of-vec.svg" /&gt;&lt;/p&gt;
&lt;p&gt;The presence of the length field can also be seen in the following code in which the size of a slice(&lt;code&gt;&amp;amp;[i32]&lt;/code&gt;) is 16 bytes (8 for the buffer pointer and 8 for the length field):&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;use&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span&gt;mem&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span&gt;size_of;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //prints 8&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Size of a reference to an i32: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; size_of&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //print 16&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Size of a slice: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; size_of&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;]&amp;gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Slices of arrays are similar, but instead of the buffer pointer pointing to a buffer on the heap, it points to the array on the stack.&lt;/p&gt;
&lt;p&gt;Since slices borrow from the underlying data structure, all the usual borrowing rules apply. For example, this code is rejected by the compiler:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; vec!&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 4&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;..&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;5&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;First element in slice: &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{&lt;/span&gt;&lt;span class="z-string"&gt;:&lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;0&lt;/span&gt;&lt;span&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why? Because when the slice is created, it points to the first element of the vector's backing buffer and as a new element is pushed onto the vector, it allocates a new buffer and the old buffer is deallocated. This leaves the slice pointing to an invalid memory address, which if accessed would have lead to undefined behaviour. Rust has saved you from disaster again.&lt;/p&gt;
&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
Since slices can be created from both arrays and vectors, they are a very powerful abstraction. Hence for arguments in functions, the default choice should be to accept a slice instead of an array or a vector. In fact many functions like &lt;code&gt;len&lt;/code&gt;, &lt;code&gt;is_empty&lt;/code&gt; etc. work on slices instead of on vectors or arrays.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Arrays and vectors being one of the first few data structures that new programmers learn, it is no surprise that Rust too has a solid support for them. But as we saw, Rust's safety guarantees do not allow programmers to abuse these fundamental data types. Slices are a novel concept in Rust but since they are such a useful abstraction, you will find them used pervasively in any Rust codebase.&lt;/p&gt;</description><author/><pubDate>Sun, 11 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hashrust.com/blog/arrays-vectors-and-slices-in-rust/</guid></item><item><title>my first blog post</title><link>https://thatxliner.github.io/posts/my-first-blog-post/</link><description>Hello! this is a test!</description><author>ThatXliner's Blog</author><pubDate>Sun, 11 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thatxliner.github.io/posts/my-first-blog-post/</guid></item><item><title>The Cycle of Life</title><link>http://spirals.blog/articles/cycles-of-life/</link><description>&lt;h2&gt;Or, why life gives you lemons just when you think you’ve got it figured out 🍋&lt;/h2&gt;
&lt;p&gt;Things seem to go round and round don’t they? Have you ever noticed that we seem to be thrown into the midst of these crazy situations (a new job, country, or a deadly pandemic that forces us to stay home and rewatch old Friends episodes for the 17th time)? And just about when we think we’ve got a handle on things, life (like the big bully it is) comes and kicks over our sandcastle.&lt;/p&gt;
&lt;h2&gt;The good times and the bad: Cycles Baby!&lt;/h2&gt;
&lt;p&gt;Life has ups and downs, for sure. We all know this intrinsically, but seem to forget it. When things are sunny, we turn a blind eye to the blinking fuel light. When things are crap, we fall into a hopeless pit of self-deprecation and “Nietzsche-esque” pessimism. Are we doing something wrong? Why do things turn sour when they’re going oh-so-right? (Hello, America 👋). Turns out there’s a mechanic to this, like many natural processes.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Introducing &lt;strong&gt;The Cycle of Life!&lt;/strong&gt; (And no, in case you’re wondering, this has nothing to do with the awkward “birds and bee’s” science lesson you got in 10th grade).&lt;/p&gt;
&lt;p&gt;&lt;img alt="The Cycle Of Life" src="http://spirals.blog/articles/cycles-of-life/the-cycle-of-life.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Let’s break this down into 5 stages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Alpha Wave: (AKA: 😎 I got this life thing sorted!)&lt;/li&gt;
&lt;li&gt;Beta Condition: (AKA: 😫 Please God, Not again)&lt;/li&gt;
&lt;li&gt;Shortcut – Reform option: (AKA: 😅 Whoah! That was close!)&lt;/li&gt;
&lt;li&gt;Gamma Trap: (AKA: 🔥 Living Hell 😡)&lt;/li&gt;
&lt;li&gt;Delta Surge: (AKA: 😃 Woo! We did it! Wait… what’s this?)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We go around and around and around… That’s life 🤷‍♀️.&lt;/p&gt;
&lt;h2&gt;1. The Alpha Wave:&lt;/h2&gt;
&lt;h3&gt;😎 I got this life thing sorted!&lt;/h3&gt;
&lt;p&gt;Ahh, life is bliss, right? The &lt;strong&gt;Alpha Wave&lt;/strong&gt; is when we are “in sync” with what’s going on. In other words, &lt;a href="https://spirals.blog/articles/internal-external/"&gt;our internal matches our external&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As an individual in Alpha, we’ve “got it together”. We’re winning at life. Go you. This might look like someone who has a good job, in a happy relationship and is at peace with where they are. There’s no gloomy rainclouds or fly’s in the butter here.&lt;/p&gt;
&lt;p&gt;For companies and organizations, this is a fantastic time for growth. The service/product/team/vision is matched to the niche, and everything is running like a well-oiled machine.&lt;/p&gt;
&lt;p&gt;At the societal/governmental level, this is a wonderful time for all involved. The needs of the citizens are met by opportunities and resources.&lt;/p&gt;
&lt;p&gt;Humanity is in a state of equilibrium…
Happily ever after. Right…Guys?&lt;/p&gt;
&lt;div class="dramatic-break"&gt;&lt;/div&gt;
Until it’s not.
&lt;hr /&gt;
&lt;p&gt;Perhaps you can recall a time when, from your paradise, the storm clouds began to gather on the distant horizon.&lt;/p&gt;
&lt;p&gt;“Fear not ye happy citizens! We have food and wine plenty!” Our leaders may call.&lt;/p&gt;
&lt;p&gt;“Those are problems for when I’m older!” You might claim, unwilling to accept that the peace is yet again about to be disturbed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Leaving Alpha for Beta:&lt;br /&gt;
Our world appears to be stable, &lt;strong&gt;but it’s not.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In true Spiral fashion, the solutions for where we are now create more problems. Harder ones. Ain’t life a bitch?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;2. The Beta Condition&lt;/h2&gt;
&lt;h3&gt;😫 Please God, Not again&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Sinking Ship" src="http://spirals.blog/articles/cycles-of-life/sinking.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Soon enough, the crack of thunder bellows from above, beckoning change and new types of problems. The Beta Condition is a time of uncertainty, questioning, frustration, and doubt.&lt;/p&gt;
&lt;p&gt;“Things just aren’t like they used to be!” Cries the disgruntled hippy, “These Yuppies are knocking down all the trees for shiny condos, and killing our culture! THEY’RE CULTURE KILLERS!”&lt;/p&gt;
&lt;p&gt;Perhaps you’ve found yourself thinking, “Something is wrong…but what &lt;em&gt;is it&lt;/em&gt;?” For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A strained marriage&lt;/li&gt;
&lt;li&gt;Organization is beginning to lose its vital talent and productivity&lt;/li&gt;
&lt;li&gt;That “Netflix and Chill” friend you have has stopped responding to your texts&lt;/li&gt;
&lt;li&gt;People are moving out of the country to look for better work&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oh, what are we to do! More of the same, perhaps? Indeed, this is the mentality many of us adopt when the winds of change begin to howl. After all, it worked so well back in Alpha. Right?&lt;/p&gt;
&lt;p&gt;Wrong. We’ll often say things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Let’s just focus more”&lt;/li&gt;
&lt;li&gt;“Work harder and smarter”&lt;/li&gt;
&lt;li&gt;“We’ve got to purge the negativity”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so, we put more and more energy into the sinking ship of the old Alpha way of life (system).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Fire" src="http://spirals.blog/articles/cycles-of-life/fire.gif" /&gt;&lt;/p&gt;
&lt;p&gt;For those &lt;a href="http://spirals.blog/articles/cycles-of-life/spirals.blog/articles/what-is-spiral-dynamics/"&gt;studying Spiral Dynamics&lt;/a&gt;, here is a little excerpt from &lt;em&gt;Spiral Dynamics - Mastering Values - Leadership and Changes&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;(If none of this makes any sense, you can skip this ⏩)&lt;/p&gt;
&lt;h4&gt;Beige:&lt;/h4&gt;
&lt;p&gt;Habitat can no longer support human bands as food becomes more difficult to find.&lt;/p&gt;
&lt;h4&gt;Purple:&lt;/h4&gt;
&lt;p&gt;Offerings and rituals fail to fend off evil spirits as tribal order beings to collapse.&lt;/p&gt;
&lt;h4&gt;Red:&lt;/h4&gt;
&lt;p&gt;Have/have-not contract begins to erode as the powerful haves are ‘weighed in the balance and found wanting’.&lt;/p&gt;
&lt;h4&gt;Blue:&lt;/h4&gt;
&lt;p&gt;The Truth no longer guarantees order, and the future is masked as doubt. Skepticism and new options appear.&lt;/p&gt;
&lt;h4&gt;Orange:&lt;/h4&gt;
&lt;p&gt;The “good life” is frayed and tarnished by consumptiveness—the search for inner peace flourishes.&lt;/p&gt;
&lt;h4&gt;Green:&lt;/h4&gt;
&lt;p&gt;Warm, human aspirations wear thin as the realities of complex societal problems, and limited resources are laid bare.&lt;/p&gt;
&lt;h4&gt;Yellow:&lt;/h4&gt;
&lt;p&gt;Reliance on individual choices and freedom fails to provide the cooperative action necessary for overall survival.&lt;/p&gt;
&lt;p&gt;With the good ol’ days behind us, we have two choices. Sit here and pout (which will undoubtedly lead to bigger issues) or look for new solutions.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;3. Shortcut – Reform option&lt;/h2&gt;
&lt;h3&gt;😅 Whoah! That was close!&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Made It!" src="http://spirals.blog/articles/cycles-of-life/made-it.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Have you ever almost stood on a snake before someone yelled and screamed at you to watch out? Having a knowledgable environment can save your life. Literally.&lt;/p&gt;
&lt;p&gt;As the Beta Conditions grow louder, and the wind blows stronger, a savvy mentor can mean the difference between losing everything and making safe passage to the promised land. Someone who’s “been and done it all before” (and lived to tell the tale) can point out the tiny trap door that briefly presents itself—a pathway out of the Gamma Trap and into the way of solving life’s new problems.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;The name of the game here is “pro-active” rather than “re-active”&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Some examples might include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A concerned family holding an “intervention” for someone with alcohol problems&lt;/li&gt;
&lt;li&gt;The CEOs personal coach, who whispers that he needs to look after his staff, lest they find greener pastures&lt;/li&gt;
&lt;li&gt;A wisened business owner, offering advice to the young and reckless entrepreneur&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Reform option lies somewhere on the road to the Gamma Trap, as things stop working. Take it, and you may pass unscathed (mostly) to the next cycle (or color). Ignore it… and you’re in for a rough ride.&lt;/p&gt;
&lt;div class="slack-invite"&gt;
If you are unsure of where you might be in the cycle, join our Slack community and ask! We’re here to assist with your existentialism.
&lt;p&gt;&lt;a class="button" href="http://spirals.blog/articles/cycles-of-life/%E2%80%9Chttps://join.slack.com/t/spiralsblog/shared_invite/zt-h4zmiolw-tCZAYSJn2YNm5bMcvYaoQA%E2%80%9D" style="width: 100%;"&gt;😫 HAAAALP!&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h2&gt;4. Gamma Trap&lt;/h2&gt;
&lt;h3&gt;🔥 Living Hell 😡&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Car driving off cliff" src="http://spirals.blog/articles/cycles-of-life/crash.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Oh, dear. We &lt;em&gt;were&lt;/em&gt; warned. But we didn’t listen. And now look where we are. The shortcut is gone, the ship has sunk, the storm is here, and we’re kinda screwed.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Gamma Trap&lt;/strong&gt; is a state of &lt;em&gt;anger, hopelessness, and desperate revolution&lt;/em&gt;. We become trapped by the barriers we’ve constructed by ignoring the new problems. Often, we enter this stage if we become too attached to a way of life (or color), and refuse to do anything different.&lt;/p&gt;
&lt;p&gt;The frustration and confusion of the &lt;strong&gt;Beta Conditions&lt;/strong&gt; give way to anger and hostility. The scary thing is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Once we’re in &lt;strong&gt;The Gamma Trap&lt;/strong&gt;, there is no turning back to how it used to be, yet no place to go.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="Shieeet" src="http://spirals.blog/articles/cycles-of-life/shit.gif" /&gt;&lt;/p&gt;
&lt;p&gt;According to Don Beck and Edward Cowen, “the pain penetrates into the depth of the soul”. Even scarier is this trap can become an entire lifestyle. This is serious business, folks.&lt;/p&gt;
&lt;p&gt;Have you ever caught yourself saying or doing any of the following?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Damn the torpedoes, full speed ahead!”&lt;/li&gt;
&lt;li&gt;Curling up in a fetal position, preparing one’s self for imminent death&lt;/li&gt;
&lt;li&gt;Sinking into a righteous crusade (My Truth is the only Truth)&lt;/li&gt;
&lt;li&gt;Engaging in some shady shit (blackmail, bribery, lying, etc.)&lt;/li&gt;
&lt;li&gt;Arrogantly questioning everyone else’s motives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jokes aside, many of us (the author is shuddering at their own examples) posses elements of our lives where we’re stuck in this trap. We refuse to acknowledge there’s a problem with &lt;strong&gt;US&lt;/strong&gt; and instead blame the rest of the world.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gamma" src="http://spirals.blog/articles/cycles-of-life/gamma.gif" /&gt;&lt;/p&gt;
&lt;p&gt;If you find yourself in this position (and many of us are if we’re honest with ourselves), please consult your local Spiral Wizard, psycho-therapist, shaman, or philosopher.&lt;/p&gt;
&lt;p&gt;Did we mention we have a &lt;a href="https://join.slack.com/t/spiralsblog/shared_invite/zt-h4zmiolw-tCZAYSJn2YNm5bMcvYaoQA"&gt;Slack channel?&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;5. Delta Surge&lt;/h2&gt;
&lt;h3&gt;😃 Woo! We did it! Wait… what’s this?&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Crawl out of ocean" src="http://spirals.blog/articles/cycles-of-life/delta-surge.gif" /&gt;&lt;/p&gt;
&lt;p&gt;And we’re out! The barriers of Gamma are broken, and we are free of our problems! Grab the champaign, we are liberated from the –&lt;/p&gt;
&lt;p&gt;Hold your horse 🐴, here be dragons.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Breaking free of the barriers in Gamma, &lt;strong&gt;is not&lt;/strong&gt; the same as reaching the next Alpha.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I know it’s tempting. But the yeasty excitement and rapid changes we’re experiencing can quickly disappear. Sometimes, people even return back to Gamma once the party is over!&lt;/p&gt;
&lt;p&gt;Slow down, take stock, and tread carefully. The promised land is close, &lt;em&gt;&lt;strong&gt;but the old behaviors may still persist for some&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;6. The New Alpha&lt;/h2&gt;
&lt;h3&gt;🥰 Life is sweet, once again&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Winning" src="http://spirals.blog/articles/cycles-of-life/winning.gif" /&gt;&lt;/p&gt;
&lt;p&gt;At long last, the world returns to a steady state. The storm has passed, the enemy has retreated, our company is in harmony, and we once again feel at peace.&lt;/p&gt;
&lt;p&gt;This is the time to reflect, rebuild, and discover our new powers. The problems we faced are long behind us. We are presented with unexplored wonders, abilities, and opportunities that we unlocked with our perspective shift.&lt;/p&gt;
&lt;p&gt;Many believe we have reached the pinnacle. They claim the ultimate stage of human development is here to stay. Beware! By now, we know that this is just the eye of the storm.&lt;/p&gt;
&lt;p&gt;Enjoy the balance while it lasts. It may be months, years, or decades. But one thing is for certain, &lt;em&gt;&lt;strong&gt;life is a cycle&lt;/strong&gt;&lt;/em&gt;. Like that annoying telemarketer that never stops calling, the storm will return. Keep your heart in the present moment, but your eyes to the horizon.&lt;/p&gt;
&lt;p&gt;Cultivate the company of those who have walked your path before you. Their stories are worth their weight in gold.&lt;/p&gt;
&lt;p&gt;Be honest with yourself about your problems when they present themselves. It will save you pain down the road.&lt;/p&gt;
&lt;p&gt;But most of all, remember to enjoy the ride! An open heart, mind, and eyes will allow us to sail smoothly around the storm. Stay vigilant, readers!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Around" src="http://spirals.blog/articles/cycles-of-life/around.gif" /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;These concepts were taken from the wise works of Clare Graves, Don Beck, and Edward Cowen. You can read more about it all &lt;a href="https://www.amazon.com/Spiral-Dynamics-Mastering-Values-Leadership/dp/1405133562"&gt;here, in their book.&lt;/a&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 11 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/cycles-of-life/</guid></item><item><title>Obsession Log: Tactile Switches</title><link>http://evantravers.com/articles/2020/10/10/obsession-log-tactile-switches/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/10/atreus.png" /&gt;&lt;/p&gt;&lt;div class="admonition tldr"&gt;
&lt;p&gt;I currently type on MX Kailh Speed Copper and Gchocs from Gheavy Industries.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The feeling of mechanical switches is a deeply personal, subjective choice. For many, it's a fun hobby pursuit of some kind of typing experience, whether that's a sound, a tactile feel when the key hits… but if you are unwilling to spend lots of money outfitting boards&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;1&lt;/a&gt;&lt;/sup&gt; it can be a bewildering and frustrating endeavor.&lt;/p&gt;
&lt;p&gt;Because everyone assumes everyone wants the same thing, they forget to disclose what qualities they are looking for.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-4" id="fnref-4"&gt;2&lt;/a&gt;&lt;/sup&gt; I make my switch decisions on a couple, unscientific assumptions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I am optimizing for speed and reducing RSI.&lt;/li&gt;
&lt;li&gt;I believe that the minimum amount of finger travel means optimum speed and minimizes impact.&lt;/li&gt;
&lt;li&gt;Having some kind of &amp;quot;signal&amp;quot; at the switch actuation point helps me minimize finger travel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I originally tried to avoid &amp;quot;bottoming out&amp;quot;&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-3" id="fnref-3"&gt;3&lt;/a&gt;&lt;/sup&gt; because Tom told me to. Later, I was trying to type more quietly on my already &lt;a href="/articles/2019/11/08/obsession-log-keyboards/#kbc-poker-ii-with-cherry-blues-2011"&gt;loud MX Blue 60% board&lt;/a&gt;. I discovered that if I could avoid bottoming out, 70% of the noise was diminished! By the time I had taught myself to type this way, some people couldn't believe I was typing on a &amp;quot;noisy&amp;quot; mechanical keyboard. I also noticed that my typing had become faster… although this could have been the result of deliberate practice.&lt;/p&gt;
&lt;p&gt;When I first became interested in mechanical keyboards, it was pretty easy to find people who were interested in the same things: it was simply people who bought tactile switches. This has shifted in the last few years. Many of the popular tactile switches out there at the moment have a much stronger tactile moment than the venerable MX Brown and MX Clear. This stronger tactile moment is mostly for &amp;quot;feel,&amp;quot; rather than providing a signal to &amp;quot;stop pressing&amp;quot; to the typist. This strong tactile moment requires a &lt;strong&gt;lot&lt;/strong&gt; of force to overcome… therefore the finger is almost certainly going to travel the full length of the switch travel and &amp;quot;bottom out,&amp;quot; producing a sound that others don't like. It is getting hard to find a switch that doesn't prioritize this ridiculously strong tactile moment.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I know that there are non-MX switches that seem to appeal to people with the same sort of typing goals... there are Matias, ALPS, and Topre switches come to mind. I never wound up venturing down that path, so I can't speak to those. I have typed on a Topre board before, and I did like it, although at the time I didn't like it as much as the MX Clears that I had.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#switches" id="switches"&gt;&lt;/a&gt;Switches&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#owned-and-liked" id="owned-and-liked"&gt;&lt;/a&gt;Owned and Liked:&lt;/h3&gt;
&lt;h4&gt;&lt;a class="anchor" href="#mx-blue" id="mx-blue"&gt;&lt;/a&gt;MX Blue&lt;/h4&gt;
&lt;p&gt;The classic. I really should order some more to occasionally throw on a hotswap board. The audible sound is lovely (and &lt;em&gt;only&lt;/em&gt; happens on the travel down, unlike the clickbar options out there!) and provides a tactile moment that is sufficient to teach your brain to move to the next switch.&lt;/p&gt;
&lt;p&gt;If you don't have a good typing style and a loud case, it can get your neighbors upset at you though.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#mx-clear" id="mx-clear"&gt;&lt;/a&gt;MX Clear&lt;/h4&gt;
&lt;p&gt;The best non-blue option of the Cherry switches, IMHO. Heavier, but with a decided tactile moment that is strong enough to teach your fingers, but not too strong so that you burst through it and fall all the way to the bottom.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#zealio-67g-v1" id="zealio-67g-v1"&gt;&lt;/a&gt;Zealio 67g v1&lt;/h4&gt;
&lt;p&gt;When I built &lt;a href="/articles/2018/09/12/i-built-a-keyboard/"&gt;my first custom&lt;/a&gt;, I was just going to put MX Clears on it, but I decided to try the fancy switches Reddit raved over.&lt;/p&gt;
&lt;p&gt;Oh man.&lt;/p&gt;
&lt;p&gt;These are still &lt;em&gt;really&lt;/em&gt; nice switches. They are essentially MX Clear with a lighter spring and a cleaned up stem, apparently a mass-produced version of a frankenspring known as the &amp;quot;ergo clear.&amp;quot;&lt;/p&gt;
&lt;p&gt;Sadly, they don't make these anymore. The current version of Zealios don't have the same feeling.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#originative-mod-m-tactile" id="originative-mod-m-tactile"&gt;&lt;/a&gt;Originative MOD-M Tactile&lt;/h4&gt;
&lt;p&gt;The original version of this article detailed me buying around 200 switches of different varieties in order to try and find a worthy heir to my beloved Zealios V1. (Some of the losers in that race are below...)&lt;/p&gt;
&lt;p&gt;The Originative MOD-M tactile is a pretty close substitute to the Zealios V1... and comes with a similar expensive price tag. They are both designed to be luxury &amp;quot;ergo clear&amp;quot; style switches. If you really want to try Zealios V1, this is the closest that I've been able to find on the market at the moment, although the &amp;quot;feel&amp;quot; of the switch is rougher.&lt;/p&gt;
&lt;p&gt;Given that they are so expensive, I can't say that I recommend them at the moment.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#20g-gchocs-from-gheavy-industries" id="20g-gchocs-from-gheavy-industries"&gt;&lt;/a&gt;20g Gchocs from Gheavy Industries&lt;/h4&gt;
&lt;p&gt;My current favorite choc switch is linear. With a crazy low spring weight, you can't even really rest your hands on the keys for fear of typing. That being said, it's a very unique typing experience, and feels very fast and very easy. Being as the choc travel distance is so low, I tend to treat the light slap of the key at the bottom as the actuation point, and it feels relatively similar to a good MX tactile. It's weird, but it's good.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#kailh-speed-copper" id="kailh-speed-copper"&gt;&lt;/a&gt;Kailh Speed Copper&lt;/h4&gt;
&lt;p&gt;My current favorite MX Switch. &lt;strong&gt;Very&lt;/strong&gt; high actuation point. Not terribly expensive. I owe this one to &lt;a href="http://arleym.com/"&gt;Arley McBain&lt;/a&gt;, he was right.&lt;/p&gt;
&lt;p&gt;The Speed Copper has an &lt;em&gt;extremely&lt;/em&gt; high actuation point, very early in travel. The spring experience is relatively light up until a definite tactile moment, then it gets quite heavy afterwards. This &amp;quot;cushion&amp;quot; &lt;em&gt;really&lt;/em&gt; helps with not bottoming out, and doesn't feel bad at all.&lt;/p&gt;
&lt;p&gt;I've been typing on them 100% for the two weeks since I got them, comparing them back and forth with the Zealio V1 I have left and the Originative MOD-Ms I had saved to put on the Atreus. The MOD-Ms are going back in the bag to be sold. 🤷‍♂️&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#owned-and-abandoned" id="owned-and-abandoned"&gt;&lt;/a&gt;Owned and Abandoned:&lt;/h3&gt;
&lt;h4&gt;&lt;a class="anchor" href="#mx-brown" id="mx-brown"&gt;&lt;/a&gt;MX Brown&lt;/h4&gt;
&lt;p&gt;The tactile moment is just not pronounced enough for me to really tell that it's there.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#zilent-67g-v2" id="zilent-67g-v2"&gt;&lt;/a&gt;Zilent 67g v2&lt;/h4&gt;
&lt;p&gt;Zeal knows how to make pleasant switches. They are freaky silent, &lt;em&gt;smooth&lt;/em&gt; and nice... I just don't like the spring/tactile experience. It starts out heavy, hits the tactile moment, then gets too light so that you crash right through to the bottom. In addition, the bump is &lt;em&gt;very&lt;/em&gt; sharp feeling. I liked the &amp;quot;roundness&amp;quot; of the MX Clear bump, it taught your finger that it was approaching actuation, not slapped it as you went past.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#novelkeys-kailh-burnt-orange-chocs" id="novelkeys-kailh-burnt-orange-chocs"&gt;&lt;/a&gt;NovelKeys Kailh Burnt Orange Chocs&lt;/h4&gt;
&lt;p&gt;These switches are technically tactile, but honestly the total switch travel of the kailh low-profile &amp;quot;choc&amp;quot; switch is &lt;em&gt;so&lt;/em&gt; short that you can't feel it unless you are trying &lt;em&gt;really&lt;/em&gt; hard.&lt;/p&gt;
&lt;p&gt;The switch's spring is strong enough for my fingers to learn how to type on it without bottoming out, but honestly it's a bit strong for the tiny keyboards on which I tend to put chocs.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#aliaz" id="aliaz"&gt;&lt;/a&gt;Aliaz&lt;/h4&gt;
&lt;p&gt;These feel &lt;em&gt;just&lt;/em&gt; like silenced lubed MX Browns, which is basically what they are. I couldn't feel the tactile moment.&lt;/p&gt;
&lt;h4&gt;&lt;a class="anchor" href="#hako-clear" id="hako-clear"&gt;&lt;/a&gt;Hako Clear&lt;/h4&gt;
&lt;p&gt;The bump is basically at the top, and is more of a resistance than an actual bump at the actuation point. I did't like these at all. They are heavy, stiff, and don't really emulate clears or zeals. They almost feel like really really heavy linears. I will say that the force curve does seem to lean towards keeping a person from bottoming out, and I think that with some practice I could keep from bottoming out entirely.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#results" id="results"&gt;&lt;/a&gt;Results&lt;/h2&gt;
&lt;p&gt;I'm pretty happy with the combination of switches that I have at the moment. I am floating somewhere between 105-115 wpm on quotes on monkey-type.com at the moment.&lt;/p&gt;
&lt;p&gt;&lt;img alt="typing speed: 115wpm" src="https://images.evantravers.com/articles/2020/10/wpm.png" /&gt;&lt;/p&gt;
&lt;p&gt;As with all endeavors... buying things won't make you faster or better, you can achieve much higher speeds than that with an old dell membrane keyboard. Deliberate practice &amp;gt; buying tools... but if you have to buy tools, I'll try to help. :)&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;Especially before the rise of readily available hot swap PCBs! &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-4"&gt;
&lt;p&gt;I personally &lt;em&gt;don't&lt;/em&gt; care so much about spring noise or stem feel… I care about how accurately and easily I can type. &lt;a class="footnote-backref" href="#fnref-4"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-3"&gt;
&lt;p&gt;bottoming out is the finger pressing to the bottom of the switch travel. &lt;a class="footnote-backref" href="#fnref-3"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;If you like this feel… more power to you. It's deeply personal, and you live in a golden age of meme switches. I just am looking for something different. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Sun, 11 Oct 2020 00:53:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/10/10/obsession-log-tactile-switches/</guid></item><item><title>Which word is missing in "The Internet of Plastic Things"?</title><link>https://stop.zona-m.net/2020/10/which-word-is-missing-in-the-internet-of-plastic-things/</link><description>&lt;p&gt;The same word that is missing in the Internet of NON-plastic things, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 10 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/which-word-is-missing-in-the-internet-of-plastic-things/</guid></item><item><title>Choice Architecture</title><link>https://www.swyx.io/choice-architecture</link><description>Reflection on how both gyms and startups do choice architecture and how we can be more conscious of this</description><author>swyx's site RSS Feed</author><pubDate>Sat, 10 Oct 2020 19:29:19 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/choice-architecture</guid></item><item><title>The Mystery Misfire</title><link>https://shielddigitaldesign.com/posts/2020/misfire/</link><description>&lt;p&gt;
The dreaded &lt;span class="glossary-term" tabindex="0" title="A common OBD-II diagnostic trouble code indicating that the engine's air-fuel mixture is too 'lean' (too much air or not enough fuel)."&gt;
    P0171
&lt;/span&gt;

 code… If you've experienced it, just the mention
likely gives you nightmares. If not - here's the rundown. &lt;span class="glossary-term" tabindex="0" title="A common OBD-II diagnostic trouble code indicating that the engine's air-fuel mixture is too 'lean' (too much air or not enough fuel)."&gt;
    P0171
&lt;/span&gt; is the
automotive &lt;span class="glossary-term" tabindex="0" title="A vehicle's self-diagnostic and reporting capability providing access to the status of various vehicle sub-systems (OBD)."&gt;
    On-Board Diagnostics
&lt;/span&gt; (&lt;span class="glossary-term" tabindex="0" title="On-Board Diagnostics. A vehicle's self-diagnostic and reporting capability providing access to the status of various vehicle sub-systems."&gt;
    OBD
&lt;/span&gt;) code&lt;sup class="footnote-reference"&gt;&lt;a href="#footnote-1" id="footnote-reference-1"&gt;1&lt;/a&gt;&lt;/sup&gt; for a &lt;span class="glossary-term" tabindex="0" title="A situation in an internal combustion engine where the air-fuel mixture contains too much air or not enough fuel for optimal combustion."&gt;
    lean condition
&lt;/span&gt;
on the engine. If the engine is running lean, it simply means that the
&lt;span class="glossary-term" tabindex="0" title="The mass ratio of air to a solid, liquid, or gaseous fuel present in a combustion process."&gt;
    air to fuel ratio
&lt;/span&gt; is not optimized, and there's either too much air or
not enough fuel. Before I get too far ahead here, let's set the scene.&lt;/p&gt;</description><author>Shield Digital Design</author><pubDate>Sat, 10 Oct 2020 19:00:00 GMT</pubDate><guid isPermaLink="true">https://shielddigitaldesign.com/posts/2020/misfire/</guid></item><item><title>The Best Of - 2020 Edition</title><link>https://smcleod.net/2020/10/the-best-of-2020-edition/</link><description>&lt;p&gt;Near the end of every year I note down a summary of the best apps, hardware &amp;amp; podcasts I&amp;rsquo;ve enjoyed throughout the year (and often for some time before).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post has been superseded. You can find the latest version of this post &lt;a href="https://smcleod.net/posts/2022-10-19-apps-of-2022/"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="software-and-services"&gt;Software and Services&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://plex.tv"&gt;Plex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://culturedcode.com/things/"&gt;Things&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pixelmator.com/pro/"&gt;Pixelmator Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://reederapp.com"&gt;Reeder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apps.apple.com/us/app/next-meeting/id1017470484?mt=12"&gt;NextMeeting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.getbumpr.com"&gt;Bumpr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fastmail.com"&gt;Fastmail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://1password.com"&gt;1Password&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://calibre-ebook.com"&gt;Calibre&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.backblaze.com"&gt;Backblaze&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iterm2.com"&gt;iTerm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://gitlab.org"&gt;Gitlab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pfsense.org"&gt;PFsense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cordlessdog.com/stay/"&gt;Stay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.titanium-software.fr/en/onyx.html"&gt;Onyx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://evernote.com"&gt;Evernote&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://handbrake.fr"&gt;Handbrake&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apps.apple.com/us/app/amphetamine/id937984704?mt=12"&gt;Amphetamine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mozilla.org/en-GB/firefox/new/"&gt;Firefox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="software---mobile"&gt;Software - Mobile&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://plex.tv"&gt;Plex&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://culturedcode.com/things/"&gt;Things&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://reederapp.com/ios"&gt;Reeder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://overcast.fm"&gt;Overcast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://evernote.com"&gt;Evernote&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://itunes.apple.com/au/app/minihack-for-hacker-news/id631108846?mt=8"&gt;MiniHack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.reddit.com/r/alienblue"&gt;Alien Blue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://signal.org"&gt;Singal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://panic.com/prompt/"&gt;Prompt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="browser-addons"&gt;Browser Addons&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/"&gt;uBlock Origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/decentraleyes/"&gt;Dencentraleyes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="hardware"&gt;Hardware&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.lg.com/au/tvs/lg-OLED65C9PTA"&gt;LG C9 OLED TV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.daskeyboard.com"&gt;Das Ultimate 4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.logitech.com/en-au/products/mice/mx-master-3.html"&gt;Logitech MX Master 3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.apple.com"&gt;16&amp;rsquo;&amp;rsquo; Macbook Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apple.com"&gt;iPhone 12 Pro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.apple.com"&gt;AppleTV 4K&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.audioquest.com/dacs/dragonfly/dragonfly-red"&gt;Audioquest DragonFly Red USB DAC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ultrasone.com/product/ultrasone-signature-pro/?lang=en"&gt;Ultrasone Signature Pro Headphones&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com.au/gp/feature.html?docId=3077740006"&gt;Kindle Paperwhite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://alldaysocks.com"&gt;All Day Socks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://bellroy.com"&gt;Bellroy Wallets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="podcasts"&gt;Podcasts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.theskepticsguide.org/"&gt;The Skeptics Guide To The Universion (SGU)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youarenotsosmart.com/"&gt;You Are Not So Smart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://risky.biz"&gt;Risky.Biz&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rhlstp.co.uk/"&gt;RHLSTP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bbc.co.uk/programmes/p089sfrz"&gt;Louis Theroux - Grounded&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/au/podcast/hip-hop-saved-my-life-with-romesh-ranganathan/id982388481"&gt;Hiphop Saved My Life&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.geologicpodcast.com/"&gt;Geological&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://99percentinvisible.org/"&gt;99% Invisible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bbc.co.uk/programmes/p02nq0gn/episodes/downloads"&gt;BBC Global News&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="youtube-channels"&gt;YouTube Channels&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UC5I2hjZYiW9gZPVkvzM8_Cw"&gt;Techmoan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLVYeh_3Gx_94IWkO3rfvX9ZTgIoKgHJ9K"&gt;Jim Jefferies - Well I Don&amp;rsquo;t Know About That!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UCyseFvMP4mZVlU5iEEbAamA"&gt;Salvatore Ganacci&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UCFH4dWqQQOYkyJZUGT4q5pg"&gt;Warped Perception&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/c/smartereveryday"&gt;Smarter Every Day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UCwKq447rYMVI5dAQWMmFnfg"&gt;DTM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UCPD_bxCRGpmmeQcbe2kpPaA"&gt;First We Feast (HotOnes)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PL1B627337ED6F55F0"&gt;NPR Tiny Desk Concerts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/channel/UC4EDjfs78AhVgpBqE3WFGJg"&gt;Logic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-absolute-worst-software-ive-experienced"&gt;The Absolute &lt;em&gt;Worst&lt;/em&gt; Software I&amp;rsquo;ve Experienced&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;💩 Microsoft Office365 💩&lt;/li&gt;
&lt;li&gt;💩 Microsoft Teams 💩&lt;/li&gt;
&lt;li&gt;💩 Atlassian Jira 💩&lt;/li&gt;
&lt;li&gt;💩 Atlassian Bamboo 💩&lt;/li&gt;
&lt;li&gt;💩 Atlassian Confluence 💩&lt;/li&gt;
&lt;li&gt;💩 McAffee Endpoint Security 💩&lt;/li&gt;
&lt;li&gt;💩 Facebook 💩&lt;/li&gt;
&lt;/ul&gt;</description><author>smcleod.net</author><pubDate>Sat, 10 Oct 2020 19:00:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2020/10/the-best-of-2020-edition/</guid></item><item><title>Digital Spring Cleaning</title><link>https://utf9k.net/blog/digital-spring-cleaning/</link><description>As I work through deleting a bunch of accounts, I note down the various issues that make it harder than it should be</description><author>utf9k</author><pubDate>Sat, 10 Oct 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/digital-spring-cleaning/</guid></item><item><title>Rethinking Education – 3 talks to watch</title><link>https://yasha.solutions/rethinking-education-3-talks-to-watch/</link><description>If you are not familiar with these 3 speakers and their thesis about education, time to catch up!
Entertaining and well-articulated, they will help you understand where the current education system migh be falling short.
Ken Robinson is more focused on the what, Seth on the why and Sugata Mitra is looking for an alternative approach (hint: it involves the Internet).
Ken Robinson: School kills creativity I am not sure how much Ken Robinson still need an introduction by now, but his was a reknown thinker on creativity and innovation.</description><author>Yasha Solutions</author><pubDate>Sat, 10 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://yasha.solutions/rethinking-education-3-talks-to-watch/</guid></item><item><title>How to Build a Plugin for Docusaurus v2</title><link>https://aknapen.nl/blog/how-to-build-a-plugin-for-docusaurus-v2/</link><description>Cool stuff: This blogpost got featured on the official Docusaurus blog! 🎉
Now, go read on about creating your own Docusaurus plugin 🚀.
 At ClaimR we have been using Docusaurus v2 for our developer and documentation website for a while now. After a couple of months of using it we can confidently say that we’re very happy with our choice.
Docusaurus comes batteries-included, so you immediately get a lot of value, while it is flexible enough to tailor it to your needs if there’s something you like differently.</description><author>Adriaan Knapen</author><pubDate>Sat, 10 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://aknapen.nl/blog/how-to-build-a-plugin-for-docusaurus-v2/</guid></item><item><title>Installing Ubuntu Linux on the Lenovo ThinkPad E14 Gen 2 (AMD)</title><link>https://rd.nz/2020/10/installing-ubuntu-linux-on-the-lenovo-thinkpad-e14-gen-2-amd</link><description>A cheap, decent Linux laptop</description><author>Rich Dougherty</author><pubDate>Sat, 10 Oct 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://rd.nz/2020/10/installing-ubuntu-linux-on-the-lenovo-thinkpad-e14-gen-2-amd</guid></item><item><title>Focus Budget: Updated Implementation</title><link>http://evantravers.com/articles/2020/10/09/focus-budget-updated-implementation/</link><description>&lt;p&gt;Some time ago I wrote a blog post about the rough pattern of my weekly planning of a &amp;quot;focus budget.&amp;quot; The objective is to estimate the time I have available for important tasks.&lt;/p&gt;
&lt;p&gt;Thanks to a &lt;a href="https://twitter.com/evantravers/status/1287768685227147264"&gt;Jacob Collins pointing out a cool feature on Things&lt;/a&gt; I've started using a new trick and written a new &lt;a href="/articles/series/hammerspoon-headspace/"&gt;headspace&lt;/a&gt; that has dramatically sped up my weekly planning and daily scheduling.&lt;/p&gt;
&lt;p&gt;Understanding this new system requires you to know three facts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you copy or drag a to-do in Things you can get the plaintext version of that to-do or project.&lt;/li&gt;
&lt;li&gt;If you drag any body of text into Fantastical, it creates an event using the current default calendar.&lt;/li&gt;
&lt;li&gt;You can set the default calendar for new events in each Calendar Set in Fantastical.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So… armed with these facts, I've written a simple layout &amp;quot;space&amp;quot; using my &lt;a href="http://evantravers.com/articles/series/hammerspoon-headspace"&gt;Headspace&lt;/a&gt; module.&lt;/p&gt;
&lt;p&gt;You can read the whole thing &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/938a4e466494b46a053b205986d9fa085b84c857/spaces/schedule.lua"&gt;here&lt;/a&gt;, but here's the gist of it.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Fantastical and Things, and position them so that I can see the whole week in Fantastical and a list in Things. If it's Sunday, I'm doing my weekly planning, so I show the Upcoming list. Otherwise, I show Today. Both are filtered to my work to-dos.&lt;/li&gt;
&lt;li&gt;Switch the Fantastical calendar set to &amp;quot;Focus Planning,&amp;quot; a calendar set where the default calendar is a private calendar I use to plan my week.&lt;/li&gt;
&lt;li&gt;Once all is in place, I drag todos from my Upcoming view in Things onto my calendar, creating little time blocks! I adjust their length based on how much time I've estimated… and this is a &lt;em&gt;really&lt;/em&gt; good way to see if I've even got enough time to do all that I've planned.&lt;/li&gt;
&lt;li&gt;When I move away from the space, the tear down function will put Fantastical and Things back to their normal states. It's great!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I really love this pattern. Thanks to the tags on my to-dos, I can see if I have enough time to execute on my daily plan.I have to admit that the little bit o' automation that chooses the right Things list based on the time makes me &lt;em&gt;really&lt;/em&gt; happy.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;-- setup the space for Headspace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;spaces&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- […]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;funcs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;focus_budget&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;setup&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;os&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;%a&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;==&lt;/span&gt; &lt;span&gt;&amp;quot;Sun&amp;quot;&lt;/span&gt; &lt;span&gt;or&lt;/span&gt; &lt;span&gt;os&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;%a&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;==&lt;/span&gt; &lt;span&gt;&amp;quot;Sat&amp;quot;&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=upcoming&amp;amp;filter=%40Proctoru%2CEstimates&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=today&amp;amp;filter=%40Proctoru%2CEstimates&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launchOrFocusByBundleID&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.culturedcode.ThingsMac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launchOrFocusByBundleID&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.flexibits.fantastical2.mac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;things&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.culturedcode.ThingsMac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;fantastical&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.flexibits.fantastical2.mac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;upcoming&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;focusedWindow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;upcoming&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Hide Sidebar&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;cal&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;fantastical&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;focusedWindow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;cal&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Hide Sidebar&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;cal&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Focus Budget&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;cal&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;By Week&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;quot;Fantastical&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;primaryScreen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;left70&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;quot;Things&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;primaryScreen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;right30&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;teardown&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;fantastical&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.flexibits.fantastical2.mac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;fantastical&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Show Sidebar&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;fantastical&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Daily Focus&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;</description><author>trv.rs</author><pubDate>Sat, 10 Oct 2020 00:54:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/10/09/focus-budget-updated-implementation/</guid></item><item><title>Custom markdown blocks with marked</title><link>https://qubyte.codes/blog/custom-markdown-blocks-with-marked</link><description>&lt;p&gt;I use &lt;a href="https://marked.js.org"&gt;&lt;code&gt;marked&lt;/code&gt;&lt;/a&gt; to do the markdown rendering for this blog. A recent
feature makes it possible to create custom block types with a little hacking. In
this post I show you how!&lt;/p&gt;
&lt;p&gt;I'll be using mathematics (&lt;a href="https://tug.org/"&gt;TeX&lt;/a&gt;) blocks for my example. The &lt;code&gt;marked&lt;/code&gt; setup
code looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-javascript"&gt;marked.&lt;span class="hljs-title function_"&gt;use&lt;/span&gt;({
  &lt;span class="hljs-title function_"&gt;walkTokens&lt;/span&gt;(&lt;span class="hljs-params"&gt;token&lt;/span&gt;) {
    &lt;span class="hljs-keyword"&gt;const&lt;/span&gt; { type, raw } = token;

    &lt;span class="hljs-comment"&gt;// Modify paragraph blocks beginning and ending with $$.&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (type === &lt;span class="hljs-string"&gt;&amp;#x27;paragraph&amp;#x27;&lt;/span&gt; &amp;amp;&amp;amp; raw.&lt;span class="hljs-title function_"&gt;startsWith&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;#x27;$$\n&amp;#x27;&lt;/span&gt;) &amp;amp;&amp;amp; raw.&lt;span class="hljs-title function_"&gt;endsWith&lt;/span&gt;(&lt;span class="hljs-string"&gt;&amp;#x27;\n$$&amp;#x27;&lt;/span&gt;)) {
      token.&lt;span class="hljs-property"&gt;type&lt;/span&gt; = &lt;span class="hljs-string"&gt;&amp;#x27;code&amp;#x27;&lt;/span&gt;;
      token.&lt;span class="hljs-property"&gt;lang&lt;/span&gt; = &lt;span class="hljs-string"&gt;&amp;#x27;mathematics&amp;#x27;&lt;/span&gt;;
      token.&lt;span class="hljs-property"&gt;text&lt;/span&gt; = token.&lt;span class="hljs-property"&gt;raw&lt;/span&gt;.&lt;span class="hljs-title function_"&gt;slice&lt;/span&gt;(&lt;span class="hljs-number"&gt;3&lt;/span&gt;, -&lt;span class="hljs-number"&gt;3&lt;/span&gt;); &lt;span class="hljs-comment"&gt;// Remove the $$ boundaries.&lt;/span&gt;
      token.&lt;span class="hljs-property"&gt;tokens&lt;/span&gt;.&lt;span class="hljs-property"&gt;length&lt;/span&gt; = &lt;span class="hljs-number"&gt;0&lt;/span&gt;; &lt;span class="hljs-comment"&gt;// Remove child tokens.&lt;/span&gt;
    }
  },
  &lt;span class="hljs-attr"&gt;renderer&lt;/span&gt;: {
    &lt;span class="hljs-title function_"&gt;code&lt;/span&gt;(&lt;span class="hljs-params"&gt;code, language&lt;/span&gt;) {
      &lt;span class="hljs-comment"&gt;// Use custom mathematics renderer.&lt;/span&gt;
      &lt;span class="hljs-keyword"&gt;if&lt;/span&gt; (language === &lt;span class="hljs-string"&gt;&amp;#x27;mathematics&amp;#x27;&lt;/span&gt;) {
        &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-title function_"&gt;renderMathematics&lt;/span&gt;(code);
      }

      &lt;span class="hljs-comment"&gt;// Use default code renderer.&lt;/span&gt;
      &lt;span class="hljs-keyword"&gt;return&lt;/span&gt; &lt;span class="hljs-literal"&gt;false&lt;/span&gt;;
    }
  }
});
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I'm passing two things to &lt;code&gt;marked&lt;/code&gt; to configure it here. The first is a
&lt;a href="https://marked.js.org/using_pro#walk-tokens"&gt;token walker function&lt;/a&gt;, which is the recent feature which makes
this all possible. It is called for each token, traversing the children of a
token before it progresses to its siblings (so it's sort of depth-first).&lt;/p&gt;
&lt;p&gt;The idea is for blocks of text with a &lt;code&gt;$$&lt;/code&gt; above and below them to be handled
as mathematics. To a person this looks like a fenced code block with two dollar
symbols in the place of the three backticks. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-markdown"&gt;Some example text with some mathematics to render below:

$$
a^2 = b^2 + c^2
$$

Some example text below.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It's a common extension to place LaTeX code inside &lt;code&gt;$$&lt;/code&gt; delimited blocks.
Even if you're not familiar, the dollar symbols above and below are a little
like a fenced code block. To &lt;code&gt;marked&lt;/code&gt; the block looks like a paragraph. This
means that the token walker will receive some paragraph tokens which need to be
modified.&lt;/p&gt;
&lt;p&gt;To know the difference, paragraph tokens are checked by the token walker to see
if they begin with &lt;code&gt;$$\n&lt;/code&gt; and end with &lt;code&gt;\n$$&lt;/code&gt;. When they do, the block is
modified to look like a code block with a special &lt;code&gt;'markdown'&lt;/code&gt; language. Child
tokens are removed because the content shouldn't be treated as markdown, and the
&lt;code&gt;text&lt;/code&gt; property is set by snipping the leading and trailing dollar symbols and
newlines off.&lt;/p&gt;
&lt;p&gt;The second part of this trick is in the renderer option. The renderer for code
blocks is modified with special handling for the &lt;code&gt;'mathematics'&lt;/code&gt; language. The
code parameter received by it is the text we set on the token, so it's ready to
be rendered to mathematics. The rendering itself is beyond the scope of this
post, but I use &lt;a href="https://www.mathjax.org/"&gt;MathJax&lt;/a&gt;. When code is of any other language the
custom code renderer returns &lt;code&gt;false&lt;/code&gt; to instruct &lt;code&gt;marked&lt;/code&gt; to use the default
code rendering behaviour.&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Sat, 10 Oct 2020 00:45:00 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/blog/custom-markdown-blocks-with-marked</guid></item><item><title>Crowdsourced fact checking? Hmm...</title><link>https://stop.zona-m.net/2020/10/crowdsourced-fact-checking-hmm.../</link><description>&lt;p&gt;Why not look at pandemics, instead?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 09 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/crowdsourced-fact-checking-hmm.../</guid></item><item><title>On the current state of privacy</title><link>https://apurva-shukla.me/blog/current-state-privacy/</link><description>Where are we? It’s 2020. The year so far has been nothing short of a global collapse of order, yet frighteningly the realities we’re facing…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Fri, 09 Oct 2020 08:30:23 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/blog/current-state-privacy/</guid></item><item><title>Adding a search tags interface</title><link>https://www.pinecoder.dev/blog/2020-10-09/search-tags-interface/</link><description>Introduction In my last attempt to build this app, search organically grew in prominence as I added new features. Originally the app was just date ordered markdown documents, and search was free text with a few added features. In this version, I wanted search to be more central and flexible. Rather than an adjunct on the selected journal, I thought it could be the main driver of what was on screen.</description><author>Home on Pinecoder blog</author><pubDate>Fri, 09 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.pinecoder.dev/blog/2020-10-09/search-tags-interface/</guid></item><item><title>2020-10-09/01</title><link>https://ho.dges.online/pictures/2020-10-09-01/</link><description/><author>ho.dges.online</author><pubDate>Fri, 09 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/pictures/2020-10-09-01/</guid></item><item><title>2020-10-09/02</title><link>https://ho.dges.online/pictures/2020-10-09-02/</link><description/><author>ho.dges.online</author><pubDate>Fri, 09 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/pictures/2020-10-09-02/</guid></item><item><title>What makerspaces REALLY (should) make</title><link>https://stop.zona-m.net/2020/10/what-makerspaces-really-should-make/</link><description>&lt;p&gt;Spoiler: it&amp;rsquo;s not objects.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 08 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/what-makerspaces-really-should-make/</guid></item><item><title>Email Shenanigans</title><link>https://rjp.is/blogging/posts/2020/10/email-shenanigans/</link><description>In which we proxy emails.</description><author>infrequent oscillations</author><pubDate>Thu, 08 Oct 2020 18:33:06 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/10/email-shenanigans/</guid></item><item><title>Rest in Peace Jimothy</title><link>https://smcleod.net/2020/10/rest-in-peace-jimothy/</link><description>&lt;p&gt;You magnificent girl, you brought me 14 years of love and happiness&lt;/p&gt;
&lt;h2 id="photos"&gt;Photos&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/1.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/2.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/3.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/4.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/5.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/6.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/7.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/8.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/9.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/10.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/11.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/12.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/13.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/15.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/16.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/17.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/18.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/19.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/20.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/21.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/22.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/23.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/24.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/25.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/26.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/27.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/28.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/29.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/30.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/31.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/32.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/33.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/34.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/35.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/36.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/37.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/38.jpeg?raw=true" /&gt;
&lt;img src="https://github.com/sammcj/smcleod_files/blob/master/images/rip_jimothy/39.jpeg?raw=true" /&gt;&lt;/p&gt;</description><author>smcleod.net</author><pubDate>Thu, 08 Oct 2020 18:20:00 GMT</pubDate><guid isPermaLink="true">https://smcleod.net/2020/10/rest-in-peace-jimothy/</guid></item><item><title>A Whisker Away</title><link>https://olshansky.info/movie/a_whisker_away/</link><description>Olshansky's review of A Whisker Away</description><author>🦉 olshansky 🦁</author><pubDate>Thu, 08 Oct 2020 16:03:08 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/a_whisker_away/</guid></item><item><title>Upload: Season 1</title><link>https://olshansky.info/tv/upload_season_1/</link><description>Olshansky's review of Upload: Season 1</description><author>🦉 olshansky 🦁</author><pubDate>Thu, 08 Oct 2020 16:00:07 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/tv/upload_season_1/</guid></item><item><title>Quick Tip: Don't Sweat the Duplicates</title><link>http://evantravers.com/articles/2020/10/08/quick-tip-dont-sweat-the-duplicates/</link><description>&lt;p&gt;Quick tip prompted by &lt;a href="https://twitter.com/rosemaryorchard"&gt;Rosemary Orchard&lt;/a&gt; in this week's episode of &lt;a href="https://overcast.fm/+S-x1xErk0"&gt;Nested Folders Podcast&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It's ok to capture something more than once.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When I first started using a to-do list I had a bad habit: at the moment of capturing a to-do I wasted time trying to remember whether I had already recorded, usually ending up wandering endlessly through my database to make sure I haven't entered this before.&lt;/p&gt;
&lt;p&gt;This friction kept me from focus and from capturing to-dos. I was afraid of &amp;quot;cluttering my system&amp;quot; or reducing the purity of my system. (I'm a data nerd, ok? Consistency is important!)&lt;/p&gt;
&lt;p&gt;Now, I capture everything I might want to do, without worrying whether it exists yet. I trust my daily review to place the to-do in the right location, and I trust my weekly review to delete duplicates.&lt;/p&gt;
&lt;p&gt;This simple mental shift allows me to capture quickly and effortlessly, returning my precious attention to the task at hand.&lt;/p&gt;</description><author>trv.rs</author><pubDate>Thu, 08 Oct 2020 12:09:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/10/08/quick-tip-dont-sweat-the-duplicates/</guid></item><item><title>How does K-means clustering work?</title><link>https://blog.lukesalamone.com/posts/kmeans-clustering/</link><description>&lt;p&gt;K-means clustering (not to be confused with K-nearest neighbors) is an unsupervised learning algorithm used for grouping similar points together into clusters.&lt;/p&gt;


&lt;div id="demo"&gt;
&lt;button&gt;start&lt;/button&gt;
&lt;canvas id="myChart" style="background-color: #0000;"&gt;&lt;/canvas&gt;
&lt;/div&gt;
&lt;h2 id="algorithm"&gt;Algorithm&lt;/h2&gt;
&lt;p&gt;The basic K-means algorithm is fairly simple and has two steps, repeated until convergence:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;assign points to cluster corresponding to closest centroid&lt;/li&gt;
&lt;li&gt;update centroid locations to the mean of all points assigned to the associated cluster&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The algorithm converges when the centroids stop moving, i.e. no points can be switched between clusters to a closer centroid.&lt;/p&gt;</description><author>Luke Salamone's Blog</author><pubDate>Thu, 08 Oct 2020 03:39:22 GMT</pubDate><guid isPermaLink="true">https://blog.lukesalamone.com/posts/kmeans-clustering/</guid></item><item><title>Lang. Identification in Code Mixed Text - Lit. Review 1</title><link>https://trigonaminima.github.io/2020/10/lang-id-1/</link><description>I am reviewing the literature available on language identification for multilingual documents, focusing on Indic languages. I’ll try to cover it in chronological order, but there might be a few misses here and there. After a decent coverage of the research, I expect to have enough understanding to discuss the challenges present in this task in a code-switched setting and its importance.</description><author>Playground</author><pubDate>Thu, 08 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://trigonaminima.github.io/2020/10/lang-id-1/</guid></item><item><title>Contact Tracing remains irrelevant</title><link>https://stop.zona-m.net/2020/10/contact-tracing-remains-irrelevant/</link><description>&lt;p&gt;Never start from software&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 07 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/contact-tracing-remains-irrelevant/</guid></item><item><title>Service as a Service</title><link>https://www.swyx.io/service-as-a-service</link><description>Before you start offering Software as a Service, perhaps just offer a Service.</description><author>swyx's site RSS Feed</author><pubDate>Wed, 07 Oct 2020 20:16:35 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/service-as-a-service</guid></item><item><title>The Crisis of the Postmaterial Condition</title><link>https://mbutler.org/the-crisis-of-the-postmaterial-condition/</link><description>Originally appeared in Infinite Regress In 1983, at the tender age of 8, I had my first real crisis as an artist.  It involved a new-media project I was working on for Mrs. Widenbacher’s class that called for a particular interactive element that I knew would really drive home what I was trying to say.  [&amp;#8230;]</description><author>mbutler</author><pubDate>Wed, 07 Oct 2020 15:56:00 GMT</pubDate><guid isPermaLink="true">https://mbutler.org/the-crisis-of-the-postmaterial-condition/</guid></item><item><title>Surrogation</title><link>https://blog.harterrt.com/surrogation.html</link><description>&lt;p&gt;A year or so ago, I read
&lt;a href="https://hbr.org/2019/09/dont-let-metrics-undermine-your-business"&gt;this article&lt;/a&gt;
about how Wells Fargo ended up in such a mess.
If you don't remember,
Wells Fargo was opening accounts in their clients' name without their consent
and ended up paying a few hundred million dollars in fines.&lt;/p&gt;
&lt;p&gt;Long story short, a …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Wed, 07 Oct 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/surrogation.html</guid></item><item><title>What is in the box? Ask Airpods..</title><link>https://ankitag9.substack.com/p/what-is-in-the-box-ask-airpods</link><description>what makes the new trend of Bluetooth earbuds/pods/earphones click..</description><author>Perspective by Ankit Agarwal</author><pubDate>Wed, 07 Oct 2020 09:54:21 GMT</pubDate><guid isPermaLink="true">https://ankitag9.substack.com/p/what-is-in-the-box-ask-airpods</guid></item><item><title>General thoughts on product, startups and technology</title><link>https://ankitag9.substack.com/p/coming-soon</link><description>Welcome to Perspective by Ankit Agarwal by me, Ankit.</description><author>Perspective by Ankit Agarwal</author><pubDate>Tue, 06 Oct 2020 21:07:35 GMT</pubDate><guid isPermaLink="true">https://ankitag9.substack.com/p/coming-soon</guid></item><item><title>Castes will be castes. So...</title><link>https://stop.zona-m.net/2020/10/castes-will-be-castes.-so.../</link><description>&lt;p&gt;Applies to ALL castes, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 06 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/castes-will-be-castes.-so.../</guid></item><item><title>Enterprise Software Monetization is Fat-Tailed</title><link>https://whoisnnamdi.com/software-fat-tailed/</link><description>In enterprise software, averages are meaningless. Instead, focus on the tails.</description><author>Who is Nnamdi?</author><pubDate>Tue, 06 Oct 2020 18:59:16 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/software-fat-tailed/</guid></item><item><title>Follow Up</title><link>https://www.swyx.io/follow-up</link><description>Following up and following through is a well known formula for success. Yet people don't do it. Why?</description><author>swyx's site RSS Feed</author><pubDate>Tue, 06 Oct 2020 13:29:38 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/follow-up</guid></item><item><title>How the React Hooks ESLint plugin saved me hours debugging useEffect</title><link>https://maxrozen.com/react-hooks-eslint-plugin-saved-hours-debugging-useeffect</link><description>useEffect is great for fetching and rendering data, but are you using it correctly? There's an eslint plugin to check!</description><author>Max Rozen</author><pubDate>Tue, 06 Oct 2020 12:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/react-hooks-eslint-plugin-saved-hours-debugging-useeffect</guid></item><item><title>Don't check emptyness before loops</title><link>https://blog.gnoack.org/post/dont-check-emptyness-before-loops</link><description>&lt;p&gt;If your plan is to loop over a collection: You shouldn&amp;rsquo;t check for it being non-empty first.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-java"&gt;if (!stuff.empty()) {
  for (Item item : stuff) {
    // ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do this instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-java"&gt;for (Item item : stuff) {
  // ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shorter&lt;/li&gt;
&lt;li&gt;Less nesting&lt;/li&gt;
&lt;li&gt;Same performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I used to do this too at some point in the past, because I thought
this would have performance benefits, but in reality, the performance
benefit is hardly measurable and generally falls into the category
&lt;a href="https://wiki.c2.com/?PrematureOptimization"&gt;&amp;ldquo;premature optimization&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Even if there is a little extra code happening between the &lt;code&gt;if&lt;/code&gt; and
the &lt;code&gt;for&lt;/code&gt;, the performance impact needs to be significant for this to
make a difference in most cases, and it&amp;rsquo;s probably not worth the
additional code convolution.&lt;/p&gt;</description><author>Blog on blog.gnoack.org</author><pubDate>Tue, 06 Oct 2020 08:12:04 GMT</pubDate><guid isPermaLink="true">https://blog.gnoack.org/post/dont-check-emptyness-before-loops</guid></item><item><title>Mystery Knowledge and Useful Tools</title><link>https://nikhilism.com/post/2020/mystery-knowledge-useful-tools/</link><description>Hillel Wayne has a great newsletter, and one recent post had this observation:
The abstract concept here is knowledge or skills that
You are unlikely to discover on your own, neither through practice and reflection nor by observing others apply it. Once somebody tells you about it, you can easily learn and apply it. Once you can use it, it immediately gives you significant benefits, possibly to the point of raising your expertise level.</description><author>Nikhil's blog</author><pubDate>Tue, 06 Oct 2020 03:22:11 GMT</pubDate><guid isPermaLink="true">https://nikhilism.com/post/2020/mystery-knowledge-useful-tools/</guid></item><item><title>Dare to be Good Enough—You'll be Happier for it</title><link>https://thomascountz.com/2020/10/06/dare-to-be-good-enough</link><description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://8thlight.com/blog/thomas-countz/2020/10/06/dare-to-be-good-enough.html"&gt;8th Light’s blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As I sit down to write, I noticed a tug at the back of my neck—a tension forming as I begin editing my words obsessively. It’s a habit of writing characterized by my attempts at achieving the best possible outcome. “I know that I can write well,” I tell myself, “I’ve just got to strike the right tempo, tone, voice…”&lt;/p&gt;

&lt;p&gt;I often have the same sensation when I’m writing code. The giants of our industry, whose shoulders I stand upon, tell me all sorts of things that should be true about my code—the way it reads, the way it’s coupled to other parts of a system, and the amount of complexity it’s allowed to have—it’s all qualified and quantified.&lt;/p&gt;

&lt;p&gt;This tension, of balancing all of the small discrete decisions that crop up when implementing a software feature, causes me to try to painstakingly eke out the “correct” way to do things. It’s as if when faced with a choice, I scan through an endless tree of outcomes trying to game out what my best option would be. “Do I extract a shared setup for these tests, or do I duplicate it for each assertion?” “Under what circumstance should I choose the builder pattern over a factory method?” “Should this method be called &lt;code class="language-plaintext highlighter-rouge"&gt;is_ready&lt;/code&gt; or &lt;code class="language-plaintext highlighter-rouge"&gt;is_prepared&lt;/code&gt;?” The list goes on and on.&lt;/p&gt;

&lt;p&gt;If this sounds familiar to you, you’re not alone. People who tackle decision-making in this way are called &lt;em&gt;maximizers&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In order to determine their optimal decision outcome, maximizers feel compelled to examine each and every alternative available, which is often infeasible in reality due to the limitations in human cognition (Roets, et al., 2012).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In theory, maximizers make the best choices, but research shows that, in practice, maximizers aren’t ever sure that the choices they make &lt;em&gt;are&lt;/em&gt; the best choices, and it’s this “not knowing” that leads to &lt;em&gt;analysis paralysis&lt;/em&gt;, and ultimately, regret.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Satisficers&lt;/em&gt;, on the other hand, are happy with whatever “good enough” choice they make:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Several options may fall within a satisficer‘s threshold for acceptability, providing greater flexibility and latitude in achieving a desired decision outcome. As soon as [they encounter] a good enough option, the satisficer can easily ignore the addition of new choices to the decision domain (Peng, 2013).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Satisficers are pragmatists at their core; the solution that works is the solution they commit to.&lt;/p&gt;

&lt;p&gt;This way of decision-making is embedded in the fabric of agile methodologies, which gives us permission to make small incremental changes over time, rather than grasping for the perfect solution from the start. From this, we know that iterative design can help us build tighter feedback loops, deliver value to stakeholders sooner, and ultimately keep our development reactive and responsive to the needs of our customers.&lt;/p&gt;

&lt;p&gt;Our projects’ bottom line isn’t the only beneficiary to thinking like a satisficer. Even though the research is still out over whether maximizers or satisficers achieve objectively better decision-making (Peng, 2013), what is clear is that satisficers are &lt;em&gt;happier&lt;/em&gt;. In fact, even if a better option occurs to them later, satisficers are less likely to experience regret (Schwartz et al., 2002).&lt;/p&gt;

&lt;p&gt;If you find yourself like me, trying to game out the best future outcomes based on limited knowledge and with bounded cognition, remember the ways of the satisficers. Make a good enough decision today, and remain flexible and forgiving in order to make another good enough decision tomorrow. Of course, we all have metaphorical hills on which we may choose to die, but choose your metaphorical battles wisely and dare to be good enough.&lt;/p&gt;

&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;p&gt;Roets, A., Schwartz, B., &amp;amp; Guan, Y. (2012). The tyranny of choice: a cross-cultural investigation of satisficing effects on well-being. Judgment and Decision Making.&lt;/p&gt;

&lt;p&gt;Peng, Starry. “Maximizing and Satisficing in Decision-Making Dyads.” ScholarlyCommons, 2013, &lt;a href="https://repository.upenn.edu/cgi/viewcontent.cgi?referer=&amp;amp;httpsredir=1&amp;amp;article=1101&amp;amp;context=wharton_research_scholars"&gt;https://repository.upenn.edu/cgi/viewcontent.cgi?referer=&amp;amp;httpsredir=1&amp;amp;article=1101&amp;amp;context=wharton_research_scholars&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Schwartz, B., Ward, A., Monterosso, J.,Lyubomirsky, S., White, K., &amp;amp; Lehman, D. R. (2002). Maximizing versus satisficing: happiness is a matter of choice. Journal of personality and social psychology.&lt;/p&gt;

&lt;p&gt;Agile Alliance. “What is Incremental Development?”, 2019, &lt;a href="https://www.agilealliance.org/glossary/incremental-development"&gt;https://www.agilealliance.org/glossary/incremental-development&lt;/a&gt;&lt;/p&gt;</description><author>Thomas Countz</author><pubDate>Tue, 06 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thomascountz.com/2020/10/06/dare-to-be-good-enough</guid></item><item><title>Don't Ignore Your Functions</title><link>https://daniellittle.dev/dont-ignore-your-functions</link><description>Ignoring return values can often be dangerous in subtle ways but you may be so used to doing it that you don't even notice anymore. It's…</description><author>Daniel Little Dev</author><pubDate>Mon, 05 Oct 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://daniellittle.dev/dont-ignore-your-functions</guid></item><item><title>Building hsdis for OpenJDK 15</title><link>https://www.morling.dev/blog/building-hsdis-for-openjdk-15/</link><description>&lt;div class="paragraph"&gt;
&lt;p&gt;Lately I’ve been fascinated by the possibility to analyse the assembly code emitted by the Java JIT (just-in-time) compiler.
So far I had only looked only into Java class files using &lt;em&gt;javap&lt;/em&gt;;
diving into the world of assembly code feels a bit like Alice must have felt when falling down the rabbit whole into wonderland.&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Mon, 05 Oct 2020 21:30:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/building-hsdis-for-openjdk-15/</guid></item><item><title>An unexpected analysis of our digital economy</title><link>https://stop.zona-m.net/2020/10/an-unexpected-analysis-of-our-digital-economy/</link><description>&lt;p&gt;Sometimes, truth is in the strangest places (and times).&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 05 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/an-unexpected-analysis-of-our-digital-economy/</guid></item><item><title>Relying on the internet as a business</title><link>https://utf9k.net/blog/internet-reliance/</link><description>It's wild that you can couple a physical business to digital technology to the extent that one can't operate without the other</description><author>utf9k</author><pubDate>Mon, 05 Oct 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/internet-reliance/</guid></item><item><title>iTerm2 Paste Buffers on MacOS/OSX - how to increase size</title><link>https://blog.herlein.com/post/iterm2-paste/</link><description>&lt;p&gt;Quick reminder: how to increase the copy-paste buffers size in iTerm2.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Mon, 05 Oct 2020 11:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/iterm2-paste/</guid></item><item><title>Testing Pelican</title><link>https://ivymike.dev/testing-pelican.html</link><description>&lt;p&gt;I'm going to test this puppy out&lt;/p&gt;</description><author>IvyMike.dev</author><pubDate>Mon, 05 Oct 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://ivymike.dev/testing-pelican.html</guid></item><item><title>An Image is Worth 16x16 Words: Transformers for Image Recognition (Paper Explained)</title><link>https://whoisnnamdi.com/transformers-image-recognition/</link><description>Large Transformer trained on large datasets outperform CNN-based architectures and achieve state of the art results on image recognition tasks</description><author>Who is Nnamdi?</author><pubDate>Mon, 05 Oct 2020 02:17:13 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/transformers-image-recognition/</guid></item><item><title>2020–10–05: Reboot to FEL, skipping SD card boot, external display fixes</title><link>https://xnux.eu/log/#021</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 05 Oct 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#021</guid></item><item><title>Corruption Is Attractive!</title><link>https://venam.net/blog/programming/2020/10/05/corruption-at-the-core.html</link><description>We live in a world that is gradually and incessantly attracted by over-rationality and order. In this article we'll burst the enchanted bubble and embrace corruption and chaos — We're going to discuss the topic of image glitch art.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Mon, 05 Oct 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/programming/2020/10/05/corruption-at-the-core.html</guid></item><item><title>Sonos is spying on me… (and you)</title><link>https://www.gingerlime.com/2020/sonos-is-spying-on-me-and-you/</link><description>&lt;p&gt;I recently decided to get a wireless speaker for our Kitchen. Sonos seems like an obvious choice these days. The sound quality and aesthetics were very appealing. So I ordered a Sonos One SL speaker. In terms of sound quality and looks, I was very pleased. I&amp;#8217;m not an audiophile but the sound quality seemed&amp;#8230;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://www.gingerlime.com/2020/sonos-is-spying-on-me-and-you/"&gt;Sonos is spying on me&amp;#8230; (and you)&lt;/a&gt; appeared first on &lt;a href="https://www.gingerlime.com"&gt;Gingerlime&lt;/a&gt;.&lt;/p&gt;</description><author>Gingerlime</author><pubDate>Sun, 04 Oct 2020 17:19:40 GMT</pubDate><guid isPermaLink="true">https://www.gingerlime.com/2020/sonos-is-spying-on-me-and-you/</guid></item><item><title>Enola Holmes</title><link>https://olshansky.info/movie/enola_holmes/</link><description>Olshansky's review of Enola Holmes</description><author>🦉 olshansky 🦁</author><pubDate>Sun, 04 Oct 2020 16:48:18 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/enola_holmes/</guid></item><item><title>Parasite</title><link>https://olshansky.info/movie/parasite/</link><description>Olshansky's review of Parasite</description><author>🦉 olshansky 🦁</author><pubDate>Sun, 04 Oct 2020 16:46:36 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/parasite/</guid></item><item><title>Hello internet</title><link>https://evilcookie.de/hello-internet.html</link><description/><author>blog</author><pubDate>Sun, 04 Oct 2020 15:07:48 GMT</pubDate><guid isPermaLink="true">https://evilcookie.de/hello-internet.html</guid></item><item><title>Why Tailwind CSS</title><link>https://www.swyx.io/why-tailwind</link><description>Why I changed my mind on Tailwind CSS, and why I now consider it the Goldilocks Styling Solution</description><author>swyx's site RSS Feed</author><pubDate>Sun, 04 Oct 2020 05:48:22 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/why-tailwind</guid></item><item><title>Improved Ctrl-p/Ctrl-n macOS movement</title><link>https://xenodium.com/improved-ctrl-p-ctrl-n-macos-movement</link><description>&lt;p&gt;macOS supports many Emacs bindings (out of the box). You can, for example, press C-p and C-n to move the cursor up and down (whether editing text in Emacs or any other macOS app). Jacob Rus's &lt;a href="http://www.hcs.harvard.edu/~jrus/site/cocoa-text.html"&gt;Customizing the Cocoa Text System&lt;/a&gt; offers a more in-depth picture and also shows how to customize global macOS keybindings (via DefaultKeyBinding.dict).&lt;/p&gt;
&lt;p&gt;In addition to moving Emacs &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Point.html"&gt;point&lt;/a&gt; (cursor) up/down using C-p/C-n, I've internalized the same bindings to select an option from a list. Good Emacs examples of these are &lt;a href="https://company-mode.github.io/"&gt;company mode&lt;/a&gt; and &lt;a href="https://github.com/abo-abo/swiper"&gt;ivy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vertical cursor movement using Emacs bindings works well in most macOS apps, including forms and text boxes in web pages. However, selecting from a completion list doesn't quite work as expected. Although the binding is technically handled, it moves the cursor within the text widget, ignoring the suggested choices.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/improved-ctrl-p-ctrl-n-macos-movement/bindings-borked.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Atif Afzal's &lt;a href="https://www.atfzl.com/use-emacs-key-bindings-everywhere"&gt;Use emacs key bindings everywhere&lt;/a&gt; has a solution for the ignored case. He uses &lt;a href="https://github.com/pqrs-org/Karabiner-Elements"&gt;Karabiner Elements&lt;/a&gt; to remap c-p and c-n to arrow-up and arrow-down.&lt;/p&gt;
&lt;p&gt;It's been roughly a week since I started using the Karabiner remapping, and I've yet to find a case where a web page (or any other macOS app) did not respond to c-p and c-n to move selection from a list.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/improved-ctrl-p-ctrl-n-macos-movement/bindings-fixed.gif" /&gt;&lt;/p&gt;
&lt;p&gt;My ~/.config/karabiner/karabiner.json configuration is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
    &amp;quot;global&amp;quot;: {
        &amp;quot;check_for_updates_on_startup&amp;quot;: true,
        &amp;quot;show_in_menu_bar&amp;quot;: true,
        &amp;quot;show_profile_name_in_menu_bar&amp;quot;: false
    },
    &amp;quot;profiles&amp;quot;: [
        {
            &amp;quot;complex_modifications&amp;quot;: {
                &amp;quot;parameters&amp;quot;: {
                    &amp;quot;basic.simultaneous_threshold_milliseconds&amp;quot;: 50,
                    &amp;quot;basic.to_delayed_action_delay_milliseconds&amp;quot;: 500,
                    &amp;quot;basic.to_if_alone_timeout_milliseconds&amp;quot;: 1000,
                    &amp;quot;basic.to_if_held_down_threshold_milliseconds&amp;quot;: 500,
                    &amp;quot;mouse_motion_to_scroll.speed&amp;quot;: 100
                },
                &amp;quot;rules&amp;quot;: [
                    {
                        &amp;quot;description&amp;quot;: &amp;quot;Ctrl+p/Ctrl+n to arrow up/down&amp;quot;,
                        &amp;quot;manipulators&amp;quot;: [
                            {
                                &amp;quot;from&amp;quot;: {
                                    &amp;quot;key_code&amp;quot;: &amp;quot;p&amp;quot;,
                                    &amp;quot;modifiers&amp;quot;: {
                                        &amp;quot;mandatory&amp;quot;: [
                                            &amp;quot;control&amp;quot;
                                        ]
                                    }
                                },
                                &amp;quot;to&amp;quot;: [
                                    {
                                        &amp;quot;key_code&amp;quot;: &amp;quot;up_arrow&amp;quot;
                                    }
                                ],
                                &amp;quot;conditions&amp;quot;: [
                                    {
                                        &amp;quot;type&amp;quot;: &amp;quot;frontmost_application_unless&amp;quot;,
                                        &amp;quot;bundle_identifiers&amp;quot;: [
                                            &amp;quot;^org\\.gnu\\.Emacs&amp;quot;
                                        ]
                                    }
                                ],
                                &amp;quot;type&amp;quot;: &amp;quot;basic&amp;quot;
                            },
                            {
                                &amp;quot;from&amp;quot;: {
                                    &amp;quot;key_code&amp;quot;: &amp;quot;n&amp;quot;,
                                    &amp;quot;modifiers&amp;quot;: {
                                        &amp;quot;mandatory&amp;quot;: [
                                            &amp;quot;control&amp;quot;
                                        ]
                                    }
                                },
                                &amp;quot;to&amp;quot;: [
                                    {
                                        &amp;quot;key_code&amp;quot;: &amp;quot;down_arrow&amp;quot;
                                    }
                                ],
                                &amp;quot;conditions&amp;quot;: [
                                    {
                                        &amp;quot;type&amp;quot;: &amp;quot;frontmost_application_unless&amp;quot;,
                                        &amp;quot;bundle_identifiers&amp;quot;: [
                                            &amp;quot;^org\\.gnu\\.Emacs&amp;quot;
                                        ]
                                    }
                                ],
                                &amp;quot;type&amp;quot;: &amp;quot;basic&amp;quot;
                            }
                        ]
                    }
                ]
            },
            &amp;quot;devices&amp;quot;: [],
            &amp;quot;fn_function_keys&amp;quot;: [],
            &amp;quot;name&amp;quot;: &amp;quot;Default profile&amp;quot;,
            &amp;quot;parameters&amp;quot;: {
                &amp;quot;delay_milliseconds_before_open_device&amp;quot;: 1000
            },
            &amp;quot;selected&amp;quot;: true,
            &amp;quot;simple_modifications&amp;quot;: [],
            &amp;quot;virtual_hid_keyboard&amp;quot;: {
                &amp;quot;country_code&amp;quot;: 0,
                &amp;quot;mouse_key_xy_scale&amp;quot;: 100
            }
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Bonus (C-g to exit)&lt;/h2&gt;
&lt;p&gt;Pressing Esc often dismisses or cancels macOS windows, menus, etc. This is also the case for web pages. As an Emacs user, I'm pretty used to pressing C-g to cancel, quit, or exit things. With that in mind, mapping C-g to Esc is surprisingly useful outside of Emacs. Here's the relevant Karabiner C-g binding for that:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
    &amp;quot;description&amp;quot;: &amp;quot;Ctrl+G to Escape&amp;quot;,
    &amp;quot;manipulators&amp;quot;: [
        {
            &amp;quot;description&amp;quot;: &amp;quot;emacs like escape&amp;quot;,
            &amp;quot;from&amp;quot;: {
                &amp;quot;key_code&amp;quot;: &amp;quot;g&amp;quot;,
                &amp;quot;modifiers&amp;quot;: {
                    &amp;quot;mandatory&amp;quot;: [
                        &amp;quot;left_control&amp;quot;
                    ]
                }
            },
            &amp;quot;to&amp;quot;: [
                {
                    &amp;quot;key_code&amp;quot;: &amp;quot;escape&amp;quot;
                }
            ],
            &amp;quot;conditions&amp;quot;: [
                {
                    &amp;quot;type&amp;quot;: &amp;quot;frontmost_application_unless&amp;quot;,
                    &amp;quot;bundle_identifiers&amp;quot;: [
                        &amp;quot;^org\\.gnu\\.Emacs&amp;quot;
                    ]
                }
            ],
            &amp;quot;conditions&amp;quot;: [
                {
                    &amp;quot;type&amp;quot;: &amp;quot;frontmost_application_unless&amp;quot;,
                    &amp;quot;bundle_identifiers&amp;quot;: [
                        &amp;quot;^org\\.gnu\\.Emacs&amp;quot;
                    ]
                }
            ],
            &amp;quot;type&amp;quot;: &amp;quot;basic&amp;quot;
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ps. Note to self: Lennart's blog has &lt;a href="https://blog.karssen.org/2024/06/05/using-emacs-key-bindings-in-gnome-firefox-and-other-applications/"&gt;notes on the topic but for linux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UPDATE: Ensure bindings are only active when Emacs is [not]{.underline} active.&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 04 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/improved-ctrl-p-ctrl-n-macos-movement</guid></item><item><title>Basmati rice pudding recipe</title><link>https://xenodium.com/basmati-rice-pudding-recipe</link><description>&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/basmati-rice-pudding-recipe/rice_pudding.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;Combine in a pot&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;2/3 cup of basmati rice&lt;/li&gt;
&lt;li&gt;400 ml of coconut milk&lt;/li&gt;
&lt;li&gt;4 cups of milk [^6]&lt;/li&gt;
&lt;li&gt;3 tablespoons of honey [^7]&lt;/li&gt;
&lt;li&gt;1/4 teaspoon of crushed cardamom seeds [^8]&lt;/li&gt;
&lt;li&gt;1/8 teaspoon of salt&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Simple. Combine all ingredients in a pot.&lt;/p&gt;
&lt;h2&gt;Boil and simmer&lt;/h2&gt;
&lt;p&gt;Bring ingredients to a boil and simmer at low heat for 45 minutes. Stir occasionally.&lt;/p&gt;
&lt;h2&gt;Mix in butter&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;1 tablespoon of butter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Turn stove off, add a tablespoon of butter, and mix in.&lt;/p&gt;
&lt;h2&gt;Serve warm or cold&lt;/h2&gt;
&lt;p&gt;After mixing in the butter, the rice pudding is done. You can serve warm or cold.&lt;/p&gt;
&lt;h2&gt;Garnish (optional)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pistachios&lt;/li&gt;
&lt;li&gt;Cinnamon&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Optionally garnish with either pistachios or cinnamon (or both).&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 04 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/basmati-rice-pudding-recipe</guid></item><item><title>A brief history of technology</title><link>https://jasoneckert.github.io/myblog/a-brief-history-of-technology/</link><description>&lt;p&gt;Technology is a crazy ride, and like that lyric in the Talking Heads song &lt;em&gt;&lt;strong&gt;Once in a Lifetime&lt;/strong&gt;&lt;/em&gt;, &amp;ldquo;&amp;hellip;you may ask yourself, well, how did I get here?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;If that&amp;rsquo;s the case, you&amp;rsquo;re in luck, because this post is a no-nonsense, give-me-the-big-picture timeline of what the heck happened in the technology landscape these past 50 years. Of course, not every little detail is in there. Just those that are actually important (in my expert opinion, of course ;-) Enjoy!&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Sun, 04 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/a-brief-history-of-technology/</guid></item><item><title>Artificial Intelligence in Python</title><link>https://stribny.name/posts/artificial-intelligence-in-python/</link><author>Posts by Petr Stribny</author><pubDate>Sun, 04 Oct 2020 02:27:26 GMT</pubDate><guid isPermaLink="true">https://stribny.name/posts/artificial-intelligence-in-python/</guid></item><item><title>Rust 2021</title><link>https://nikhilism.com/post/2020/rust-2021/</link><description>This is a contribution to the Rust 2021 Roadmap Blogs request.
As a developer using Rust in a proprietary, polyglot code base, I want Rust to improve non-Cargo builds My story comes from spending the better part of a year migrating a roughly 700,000 line code base (and several hundred upstream dependencies) to build using Bazel circa 2019. As Rust becomes more popular, a large chunk of developers will want to use it as a complement to existing code in other languages.</description><author>Nikhil's blog</author><pubDate>Sat, 03 Oct 2020 22:16:57 GMT</pubDate><guid isPermaLink="true">https://nikhilism.com/post/2020/rust-2021/</guid></item><item><title>The Apple parable, from creativity to hoarding</title><link>https://stop.zona-m.net/2020/10/the-apple-parable-from-creativity-to-hoarding/</link><description>&lt;p&gt;No (more) innovation here. Please move along.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 03 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/the-apple-parable-from-creativity-to-hoarding/</guid></item><item><title>Beware the fascist driverless car</title><link>https://stop.zona-m.net/2020/10/beware-the-fascist-driverless-car/</link><description>&lt;p&gt;Old problems have an annoying habits to return, wearing different hats.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 02 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/beware-the-fascist-driverless-car/</guid></item><item><title>Artsakh Must Be Independent 🗺️</title><link>https://ashvardanian.com/posts/artsakh/</link><description>A data-driven argument for why Artsakh must be independent — examining historical claims, demographic evidence, and the indisputable pattern of ethnic violence.</description><author>Ash's Blog</author><pubDate>Fri, 02 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ashvardanian.com/posts/artsakh/</guid></item><item><title>ZFS rename devices in pool to disk ID</title><link>https://b.agilob.net/linux/zfs/map-devices-by-id/</link><description>zpool import -d /dev/disk/by-id poolname Converts:
NAME STATE READ WRITE CKSUM poolname ONLINE 0 0 0 mdisk1 ONLINE 0 0 204 mdisk2 ONLINE 0 0 627K mdisk3 ONLINE 0 0 0 to map disks by ID (example):
NAME STATE READ WRITE CKSUM poolname ONLINE 0 0 0 wwn-0x1000000 ONLINE 0 0 204 wwn-0x2000000 ONLINE 0 0 627K wwn-0x3000000 ONLINE 0 0 0</description><author>Random Notes by agilob</author><pubDate>Fri, 02 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://b.agilob.net/linux/zfs/map-devices-by-id/</guid></item><item><title>Alien Machinery • Art</title><link>https://muffinman.io/art/alien-machinery/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;It was generated using the same algorithm as the previous drawing. Metallic pens give it a really nice effect in person.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;October 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;32x19cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Fabriano Black Black 300gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Sakura Gelly Rolls Metallic&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery art-gallery--wide"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1488" src="./0.jpg" width="2500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1650" src="./w_500-h_500--1.jpg" width="2200" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./2.jpg"&gt;&lt;img alt="" class="gallery__image" height="1650" src="./w_500-h_500--2.jpg" width="2200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Fri, 02 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/alien-machinery/</guid></item><item><title>Do you realize that you are socially cooling?</title><link>https://stop.zona-m.net/2020/10/do-you-realize-that-you-are-socially-cooling/</link><description>&lt;p&gt;&amp;ldquo;[Theoretically] well behaved, surely less human&amp;rdquo;.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 01 Oct 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/10/do-you-realize-that-you-are-socially-cooling/</guid></item><item><title>Why We Sleep: Unlocking the Power of Sleep and Dreams</title><link>https://apurva-shukla.me/bookshelf/why-we-sleep/</link><description>⭐ ⭐ ⭐ ⭐ ⭐ One of the most important books I’ve ever read. It has completely changed my relationship with sleep, and made me fall in love…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Thu, 01 Oct 2020 14:54:09 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/bookshelf/why-we-sleep/</guid></item><item><title>Youtube-dl format code cheatsheet</title><link>https://voussoir.net/writing/youtubedl_formats</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Youtube-dl format code cheatsheet&lt;/h1&gt;&lt;ol id="table_of_contents"&gt;Table of contents&lt;li&gt;&lt;a href="#video_formats"&gt;Video formats&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="#avc_only"&gt;AVC only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#vp9_only"&gt;VP9 only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#av1_only"&gt;AV1 only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#4320p_only"&gt;4320p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#2160p_only"&gt;2160p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#1440p_only"&gt;1440p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#1080p_only"&gt;1080p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#720p_only"&gt;720p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#480p_only"&gt;480p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#360p_only"&gt;360p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#240p_only"&gt;240p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#144p_only"&gt;144p only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#60fps_only"&gt;60fps only&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#30fps_only"&gt;30fps only&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#audio_formats"&gt;Audio formats&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#combined_formats"&gt;Combined formats&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Here are all the youtube format codes I'm aware of.
Please let me know if there are more, or if something here is outdated.
contact@voussoir.net&lt;/p&gt;
&lt;p&gt;You can pass them to youtube-dl as &lt;code&gt;--format a+b/c+d/e&lt;/code&gt;,
where a+b is your preferred video+audio pair, c+d is your second-best
preference, and e is your last resort.
Don't forget the magic words like "bestvideo", "bestaudio" to round out your selection.&lt;/p&gt;
&lt;p&gt;See &lt;a href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection"&gt;https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are more formats listed in &lt;a href="https://github.com/ytdl-org/youtube-dl/blob/eb6181759f3a784d7b77ec9d2ec1a65dfd695d92/youtube_dl/extractor/youtube.py#L430"&gt;youtube-dl's source code&lt;/a&gt;,
but some of them seem to be obsolete and are no longer returned by &lt;code&gt;-F&lt;/code&gt;
even when using the example video IDs listed there. I will only include
codes for which I have an example.&lt;/p&gt;
&lt;h2 id="video_formats"&gt;Video formats&lt;a class="header_anchor_link" href="#video_formats"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;571&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;272&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;337&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;401&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;305&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;315&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;266&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;313&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;336&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;400&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;304&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;308&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;264&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;271&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;335&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;399&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;299&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;303&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;137&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;248&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;334&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;398&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;298&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;302&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;136&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;247&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;333&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;397&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;135&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;244&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;332&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;396&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;134&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;243&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;331&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;395&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;133&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;242&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;330&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;394&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;160&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;278&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="avc_only"&gt;AVC only&lt;a class="header_anchor_link" href="#avc_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;305&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;266&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;304&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;264&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;299&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;137&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;298&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;136&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;135&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;134&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;133&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;160&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="vp9_only"&gt;VP9 only&lt;a class="header_anchor_link" href="#vp9_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;272&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;337&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;315&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;313&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;336&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;308&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;271&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;335&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;303&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;248&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;334&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;302&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;247&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;333&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;244&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;332&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;243&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;331&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;242&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;330&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;278&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="av1_only"&gt;AV1 only&lt;a class="header_anchor_link" href="#av1_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;571&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;401&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;400&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;399&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;398&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;397&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;396&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;395&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;394&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="4320p_only"&gt;4320p only&lt;a class="header_anchor_link" href="#4320p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;571&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;272&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="2160p_only"&gt;2160p only&lt;a class="header_anchor_link" href="#2160p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;337&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;305&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;315&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;401&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;266&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;313&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="1440p_only"&gt;1440p only&lt;a class="header_anchor_link" href="#1440p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;336&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;304&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;308&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;400&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;264&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;271&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="1080p_only"&gt;1080p only&lt;a class="header_anchor_link" href="#1080p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;335&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;299&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;303&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;399&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;137&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;248&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="720p_only"&gt;720p only&lt;a class="header_anchor_link" href="#720p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;334&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;298&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;302&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;398&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;22&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30+128k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC+m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;136&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;247&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="480p_only"&gt;480p only&lt;a class="header_anchor_link" href="#480p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;333&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;135&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;244&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;397&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="360p_only"&gt;360p only&lt;a class="header_anchor_link" href="#360p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;332&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;18&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30+96k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC+m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;134&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;243&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;396&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="240p_only"&gt;240p only&lt;a class="header_anchor_link" href="#240p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;331&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;133&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;242&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;395&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="144p_only"&gt;144p only&lt;a class="header_anchor_link" href="#144p_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;330&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;160&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;278&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;394&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="60fps_only"&gt;60fps only&lt;a class="header_anchor_link" href="#60fps_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;571&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;337&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;305&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;315&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;401&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;336&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;304&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;308&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;400&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;335&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;299&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;303&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;399&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;334&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;298&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;302&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ -xNN-bJQ4vI&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;398&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p60&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;333&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;332&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;331&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;330&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p60 HDR&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="30fps_only"&gt;30fps only&lt;a class="header_anchor_link" href="#30fps_only"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;272&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4320p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;266&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;313&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2160p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;264&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;271&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F kFz9afj8lu0 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;137&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;248&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1080p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;22&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30+128k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC+m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;136&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;247&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;135&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;244&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;397&lt;/td&gt;
&lt;td style="text-align: right;"&gt;480p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;18&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30+96k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC+m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;134&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;243&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;396&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;133&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;242&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;395&lt;/td&gt;
&lt;td style="text-align: right;"&gt;240p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;160&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;278&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;VP9&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ -xNN-bJQ4vI i6fWG4FxDZw&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;394&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144p30&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AV1&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU 1La4QzGeaaQ&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="audio_formats"&gt;Audio formats&lt;a class="header_anchor_link" href="#audio_formats"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;258&lt;/td&gt;
&lt;td style="text-align: right;"&gt;386k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F NMANRHz4UAY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;256&lt;/td&gt;
&lt;td style="text-align: right;"&gt;195k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F NMANRHz4UAY&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;251&lt;/td&gt;
&lt;td style="text-align: right;"&gt;160k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;Opus&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;140&lt;/td&gt;
&lt;td style="text-align: right;"&gt;128k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;250&lt;/td&gt;
&lt;td style="text-align: right;"&gt;70k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;Opus&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;249&lt;/td&gt;
&lt;td style="text-align: right;"&gt;50k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;Opus&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="combined_formats"&gt;Combined formats&lt;a class="header_anchor_link" href="#combined_formats"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th style="text-align: right;"&gt;id&lt;/th&gt;
&lt;th style="text-align: right;"&gt;quality&lt;/th&gt;
&lt;th style="text-align: right;"&gt;codec&lt;/th&gt;
&lt;th style="text-align: left;"&gt;examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;22&lt;/td&gt;
&lt;td style="text-align: right;"&gt;720p30+128k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC+m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right;"&gt;18&lt;/td&gt;
&lt;td style="text-align: right;"&gt;360p30+96k&lt;/td&gt;
&lt;td style="text-align: right;"&gt;AVC+m4a&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;code&gt;youtube-dl -F S8Zt6cB_NPU&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This document is generated &lt;a href="/writing/youtubedl_formats/youtubedl_formats.sql"&gt;programmatically&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sqlite3 :memory: ".read youtubedl_formats.sql" &amp;gt; youtubedl_formats.md&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/youtubedl_formats/youtubedl_formats.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/07543ba3323ada09807b7614b536912c628011bd"&gt;&lt;time datetime="2022-03-25T21:55:49-07:00"&gt;2022-03-25&lt;/time&gt; Add resolution and fps tables.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/94b0274925fdf1c8d86ec2c14045a32a79e98794"&gt;&lt;time datetime="2020-11-06T11:32:17-08:00"&gt;2020-11-06&lt;/time&gt; Add audio bitrates to 18, 22 quality column.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/afecf692aa9f0ccc430431c4197a5ba9a0fb0137"&gt;&lt;time datetime="2020-10-01T10:19:58-07:00"&gt;2020-10-01&lt;/time&gt; Add more formats, examples, and auto-generate the md table aligners.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/f7109f9ceaa3e31a80c01414b853b9ba56a0e3ee"&gt;&lt;time datetime="2020-09-30T19:25:25-07:00"&gt;2020-09-30&lt;/time&gt; Add youtubedl_formats.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Thu, 01 Oct 2020 05:25:25 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/youtubedl_formats</guid></item><item><title>The 7 Sins of Turkish Autocracy 🇹🇷</title><link>https://ashvardanian.com/posts/turkey/</link><description>Seven stories tracing Turkey's path from secular reforms to neo-Ottoman ambitions — examining crimes unpunished, allies betrayed, and the dangerous pattern repeating today.</description><author>Ash's Blog</author><pubDate>Thu, 01 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ashvardanian.com/posts/turkey/</guid></item><item><title>A simple CSS ruleset</title><link>https://nutcroft.mataroa.blog/blog/a-simple-css-ruleset/</link><description>&lt;p&gt;The content of this article is a set of 8 rules along with a CSS writer's workflow, grown out of developing small web projects. It's designed for simple layouts with minimal JavaScript interactiveness, and its top concern is code readability, rather than &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="ruleset"&gt;Ruleset&lt;/h2&gt;
&lt;h3 id="1-no-preprocessors"&gt;1. No preprocessors&lt;/h3&gt;
&lt;p&gt;Using a preprocessor, such as Sass, for a few thousand lines of CSS code is a clear case of overengineering. The scope of a project is the most crucial datum for the preprocessor decision, but what happens in modern web development is that the preprocessor overhead is downplayed because of the omnipresence of the Node.js toolset.&lt;/p&gt;
&lt;h3 id="2-no-frameworks"&gt;2. No frameworks&lt;/h3&gt;
&lt;p&gt;Unless one plans to use every Bootstrap component it's not worth adding 160KB of un-gzipped CSS files. In addition to the size tradeoff, the framework buy-in is an important engineering decision as one is potentially adding something that they will have to fight either in a case of over-growing it or in a case of not understanding how it's designed to be extended.&lt;/p&gt;
&lt;h3 id="3-yes-css-reset"&gt;3. Yes CSS reset&lt;/h3&gt;
&lt;p&gt;Browser implementation inconsistencies&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; are undying. Therefore, while no framework is advised, a CSS reset library is. I've been using &lt;a href="https://github.com/necolas/normalize.css"&gt;normalize.css&lt;/a&gt; for the last many years with no issues.&lt;/p&gt;
&lt;h3 id="4-no-externally-loaded-fonts"&gt;4. No externally loaded fonts&lt;/h3&gt;
&lt;p&gt;Typography is great and fun. In cases of doubt &lt;a href="https://practicaltypography.com/"&gt;Practical Typography&lt;/a&gt; provides enlightenment. But this is the case against fonts, and especially against Google Fonts&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, as the only real contender for free web fonts. Our criteria are quality and speed. All OSes have good enough &lt;a href="https://css-tricks.com/snippets/css/system-font-stack/"&gt;default fonts&lt;/a&gt;, thus it's not worth loading a &lt;em&gt;slightly different&lt;/em&gt; font and introducing yet another third-party dependency. But maybe one wants a more-than-slightly different font. Then, my argument is that most Google Fonts are not of high quality, and a
&lt;a href="https://practicaltypography.com/font-basics.html#why-use-professional-fonts"&gt;professional font&lt;/a&gt; might be worth buying.&lt;/p&gt;
&lt;h3 id="5-yes-semantic-html-elements"&gt;5. Yes semantic HTML elements&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element"&gt;Semantic HTML&lt;/a&gt; is great. Not only does it enable one to think through the information architecture of their layout, but also improves the accessibility of the website.&lt;/p&gt;
&lt;h3 id="6-yes-css-variables"&gt;6. Yes CSS variables&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties"&gt;CSS variables&lt;/a&gt; have good enough &lt;a href="https://caniuse.com/css-variables"&gt;browser support&lt;/a&gt; for a while now. Colours and margin/padding lengths are ideal usecases for them.&lt;/p&gt;
&lt;h3 id="7-yes-namespaces"&gt;7. Yes namespaces&lt;/h3&gt;
&lt;p&gt;I've found very useful to overload class names with namespaces, based on page or resource names. For example, if form buttons are different than bare buttons, then those classes will be &lt;code&gt;form-btn-submit&lt;/code&gt;. Another recurring example is special styling for the landing page, which I'd namespace as &lt;code&gt;landing-*&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="8-yes-rule-local-responsive-media-queries"&gt;8. Yes rule-local responsive media queries&lt;/h3&gt;
&lt;p&gt;The question is whether to place all rules for a specific breakpoints all together, or rules for the same classes together across different breakpoints. I vote for the second option, so that when one wants to read or change the rules for e.g. &lt;code&gt;nav&lt;/code&gt;, they see all rules for all breakpoints together, rather than jumping to different places of the file for the other breakpoints. Example:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;.&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;projects-grid&lt;/span&gt;&lt;span style="color: #657B83;"&gt; {&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;    &lt;/span&gt;&lt;span style="color: #859900;"&gt;display&lt;/span&gt;&lt;span style="color: #657B83;"&gt;: &lt;/span&gt;&lt;span style="color: #859900;"&gt;grid&lt;/span&gt;&lt;span style="color: #657B83;"&gt;;&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;    &lt;/span&gt;&lt;span style="color: #859900;"&gt;grid-template-columns&lt;/span&gt;&lt;span style="color: #657B83;"&gt;: &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;1&lt;/span&gt;&lt;span style="color: #657B83;"&gt;fr &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;1&lt;/span&gt;&lt;span style="color: #657B83;"&gt;fr &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;1&lt;/span&gt;&lt;span style="color: #657B83;"&gt;fr;&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;}&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;@&lt;/span&gt;&lt;span style="color: #859900;"&gt;media&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;max-width&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;:&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;490px&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;)&lt;/span&gt;&lt;span style="color: #657B83;"&gt; {&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;  .&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;projects-grid&lt;/span&gt;&lt;span style="color: #657B83;"&gt; {&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;    &lt;/span&gt;&lt;span style="color: #859900;"&gt;grid-template-columns&lt;/span&gt;&lt;span style="color: #657B83;"&gt;: &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;1&lt;/span&gt;&lt;span style="color: #657B83;"&gt;fr &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;1&lt;/span&gt;&lt;span style="color: #657B83;"&gt;fr;&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;  }&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;}&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;@&lt;/span&gt;&lt;span style="color: #859900;"&gt;media&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;max-width&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;:&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;340px&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;)&lt;/span&gt;&lt;span style="color: #657B83;"&gt; {&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;  .&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;projects-grid&lt;/span&gt;&lt;span style="color: #657B83;"&gt; {&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;    &lt;/span&gt;&lt;span style="color: #859900;"&gt;grid-template-columns&lt;/span&gt;&lt;span style="color: #657B83;"&gt;: &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;1&lt;/span&gt;&lt;span style="color: #657B83;"&gt;fr;&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;  }&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="limitations"&gt;Limitations&lt;/h2&gt;
&lt;p&gt;The limitations of this system lie mostly on compatibility. &lt;/p&gt;
&lt;p&gt;Firstly, preprocessors would automagically fill the blanks with vendor-prefixed properties and polyfills. Without those, some problems might arise.&lt;/p&gt;
&lt;p&gt;Secondly, IE11 does not support CSS variables, which we say yes to.&lt;/p&gt;
&lt;h2 id="workflow"&gt;Workflow&lt;/h2&gt;
&lt;p&gt;Most of the times I'm designing a new webpage with no existing design, I have found that capturing my vague ideas into a concrete design in a vector editor is the best way to start. After that, I focus on writing the HTML. The reason for not writing the HTML and the CSS in parallel lies mostly in the unknown intricacies of the layout that will be followed. If a CSS grid is needed, for example, this is the step to decide that.&lt;/p&gt;
&lt;p&gt;Final stage is actually writing the CSS code. I try to group the rules together based on where they are used. Generic selectors like &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;h1&lt;/code&gt; go first, then &lt;code&gt;form&lt;/code&gt; and their conceptual children such as &lt;code&gt;input&lt;/code&gt;, and then namespaces of other resources and pages.&lt;/p&gt;
&lt;p&gt;One can find an actual example of all the ideas in action on the &lt;a href="https://git.sr.ht/~sirodoht/mataroa/tree/master/main/static/style.css"&gt;sr.ht repo&lt;/a&gt; of the &lt;a href="https://mataroa.blog/"&gt;mataroa.blog&lt;/a&gt; project.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Stephanie Stimac has a interesting example on &lt;a href="https://blog.stephaniestimac.com/posts/2020/06/browser-fonts/"&gt;font rendering incosistencies&lt;/a&gt;. Also, the &lt;a href="https://github.com/necolas/normalize.css/blob/master/normalize.css"&gt;source code comments&lt;/a&gt; for normalize.css are enlightening.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Matthew Butterick provides another case, a very interesting &lt;a href="https://practicaltypography.com/why-google-fonts-arent-really-open-source.html"&gt;critique&lt;/a&gt; on Google Fonts, in regards to them not being open-source.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>nutcroft</author><pubDate>Thu, 01 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/a-simple-css-ruleset/</guid></item><item><title>Substitution and Equational Reasoning</title><link>https://gilmi.me/post/2020/10/01/substitution-and-equational-reasoning</link><description>In a lazy functional language where variables are immutable and effects are explicit, new powerful tools for understanding what programs mean become available - substitution and equational reasoning.</description><author>λm.me</author><pubDate>Thu, 01 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://gilmi.me/post/2020/10/01/substitution-and-equational-reasoning</guid></item><item><title>Beware The Fallacy of Composition</title><link>https://www.swyx.io/composition-fallacy</link><description>Many things that make sense individually don't make sense as a group.</description><author>swyx's site RSS Feed</author><pubDate>Thu, 01 Oct 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/composition-fallacy</guid></item><item><title>SRE 123</title><link>https://blog.herlein.com/post/sre-123/</link><description>&lt;p&gt;Everyone is all on fire about SRE.  But what is it really?  It&amp;rsquo;s as easy as 1-2-3 if you boil it down to the basics.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Thu, 01 Oct 2020 01:50:08 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/sre-123/</guid></item><item><title>How to handle fights in almost any Facebook group</title><link>https://stop.zona-m.net/2020/09/how-to-handle-fights-in-almost-any-facebook-group/</link><description>&lt;p&gt;Have you been fighting over the purpose and content of a Facebook group? Get real!&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 30 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/how-to-handle-fights-in-almost-any-facebook-group/</guid></item><item><title>Books and Links: September</title><link>http://evantravers.com/articles/2020/09/30/books-and-links-september/</link><description>&lt;p&gt;Around here autumn is lurking... the rising wind has the dry rustle of turning leaves, the air just feels &lt;em&gt;crisper&lt;/em&gt;, and I'm craving baked goods and campfire smoke.&lt;/p&gt;
&lt;p&gt;I am still in limbo with some of my zettelkasten/note-taking work... I'm just going to have to do a post about where I am at the moment and hope that others can build on it. Suffice to say, &lt;a href="https://obsidian.md"&gt;obsidian&lt;/a&gt; is super awesome and influencing a lot of my decisions on that front at the moment.&lt;/p&gt;
&lt;p&gt;We are still safe and happy in our little home... learning to find a new steady-state with our increased population count. I've been spending time messing around with iOS14 automations and keyboard stuff... I'll write about it soon.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;p&gt;This month was pretty good for book-reading. I think I read... four books, not including comics (every month I look forward to my new allotment of Hoopla borrows!)&lt;/p&gt;
&lt;p&gt;On deck: Knowing God by JI Packer, A Programmer's Introduction to Mathematics by Jeremy Kun, Whiskey Tango Foxtrot by Lynne Black Jr.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#talking-to-strangers-by-malcolm-gladwell" id="talking-to-strangers-by-malcolm-gladwell"&gt;&lt;/a&gt;Talking to Strangers by Malcolm Gladwell&lt;/h3&gt;
&lt;p&gt;This is a &lt;em&gt;dark&lt;/em&gt; book. In telling the story of a single traffic stop gone wrong, Gladwell meanders through the history of communication, deception, and the incentives of trust and suspicion. I found the discussions of different conversational fallacies interesting as to how they aligned with the &lt;a href="https://en.wikipedia.org/wiki/Gricean_maxims"&gt;Gricean Maxims&lt;/a&gt;, but I am conflicted because I felt there was a definite bias to how some of the social science was handled and statistics interpreted. Content warning: Language, graphic depictions of violence and sexual violence.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#redshirts-by-john-scalzi" id="redshirts-by-john-scalzi"&gt;&lt;/a&gt;Redshirts by John Scalzi&lt;/h3&gt;
&lt;p&gt;I knew going in that I was going to enjoy this one given the premise, but I surprised at how moving and thoughtful it was. It definitely transcends its initial setup to ask some hard questions about life and meaning. I know that's vague, but to say more would be a spoiler. Content warning: Foul language and coarse joking.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-passage-by-justin-cronin" id="the-passage-by-justin-cronin"&gt;&lt;/a&gt;The Passage by Justin Cronin&lt;/h3&gt;
&lt;p&gt;I really enjoyed the character building. For a book ostensibly about virus-vampire apocalypse, it takes its sweet time telling about all the humans and giving everyone a worthy backstory. Very southern-gothic, Stephen King-esque. Against that tapestry of history, the stakes (see what I did there?) of decisions felt rich and meaningful, and Cronin managed to keep that pace up till the bitter end. I don't think I'll continue through the series though. Content warning: Violence, language, threatening situations.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;p&gt;My link saving automation is mostly broken, and I started doing a weekly newsletter at work that has soaked up a &lt;em&gt;lot&lt;/em&gt; of my desire to post links. I think I've also just spent more time in books than in Instapaper these days.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#stop-doing-design-system-projects" id="stop-doing-design-system-projects"&gt;&lt;/a&gt;&lt;a href="https://uxdesign.cc/stop-doing-design-system-projects-b094369dcfdd"&gt;Stop doing design system projects&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;When new designers and developers join forces to evolve your design system it is tempting to start working in projects. You might even create some epics and sprints to move user stories from your backlog in a Scrum environment. But when your design system is not a full-time effort, this will work counter-productive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm still trying to get our design system off the ground, but I had settled on doing it iteratively, bit by bit rather than a &amp;quot;project&amp;quot; all at once. Nice to see that others agree.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://uxdesign.cc/stop-doing-design-system-projects-b094369dcfdd"&gt;Stop doing design system projects&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#marc-andreessen-on-productivity-scheduling-reading-habits-work-and-more" id="marc-andreessen-on-productivity-scheduling-reading-habits-work-and-more"&gt;&lt;/a&gt;&lt;a href="https://a16z.com/2020/09/07/on-productivity-scheduling-reading-habits-marc-andreessen/"&gt;Marc Andreessen On Productivity, Scheduling, Reading Habits, Work, and More&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;You really have to uplevel and figure out what’s important. I usually take a good hour to look at what I’ve been doing. It’s basically figuring out the threshold for “yes” versus “no”. I try to revise that about once a year.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a student of effective people, there were a couple good gems in this interview.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://a16z.com/2020/09/07/on-productivity-scheduling-reading-habits-marc-andreessen/"&gt;Marc Andreessen On Productivity, Scheduling, Reading Habits, Work, and More&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#phd-student-reporting-what-its-like-to-use-a-zettelkasten-for-classes" id="phd-student-reporting-what-its-like-to-use-a-zettelkasten-for-classes"&gt;&lt;/a&gt;&lt;a href="https://zettelkasten.de/posts/zettelkasten-in-class/"&gt;PhD Student Reporting What It's Like to Use a Zettelkasten for Classes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I'm still a student of this... reading about the &lt;em&gt;system&lt;/em&gt; is more useful than the tools.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://zettelkasten.de/posts/zettelkasten-in-class/"&gt;PhD Student Reporting What It's Like to Use a Zettelkasten for Classes&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Wed, 30 Sep 2020 19:48:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/09/30/books-and-links-september/</guid></item><item><title>Parallel Plate Capacitor Equation - Simulated</title><link>https://shielddigitaldesign.com/posts/2020/cap/</link><description>&lt;div class="outline-2" id="outline-container-headline-1"&gt;
&lt;h2 id="headline-1"&gt;
The Question
&lt;/h2&gt;
&lt;div class="outline-text-2" id="outline-text-headline-1"&gt;
&lt;p&gt;
A recent homework problem had us derive the parallel plate
capacitor&lt;sup class="footnote-reference"&gt;&lt;a href="#footnote-1" id="footnote-reference-1"&gt;1&lt;/a&gt;&lt;/sup&gt; equation for electrostatics. This gives the
capacitance of a parallel plate structure in terms of the plate area,
distance between the plates and relative permittivity. The equation
for this situation is:&lt;/p&gt;
&lt;p&gt;
$
C = \epsilon_{R}\epsilon_{0}\frac{A}{d}
$&lt;/p&gt;
&lt;p&gt;
After solving this problem for the analytical solution, I was curious
to see how closely the result matched a 3D field solver. Using the
Capacitance Extraction mode in Cadence 3D Workbench, I designed a
parametric model of the parallel plate capacitor with variable edge
length, distance and &lt;span class="glossary-term" tabindex="0" title="Also known as Dk or relative permittivity, it is a measure of a material's ability to store electrical energy in an electric field."&gt;
    dielectric constant
&lt;/span&gt;

 (See image above for the
model). &lt;span class="glossary-term" tabindex="0" title="Dielectric Constant. A measure of a material's ability to store electrical energy in an electric field."&gt;
    Dk
&lt;/span&gt;&lt;sup class="footnote-reference"&gt;&lt;a href="#footnote-2" id="footnote-reference-2"&gt;2&lt;/a&gt;&lt;/sup&gt; was varied but the complex component (dissipation factor)
was set to zero to ignore any dielectric losses. The edges were swept
at lengths of 0.1 inch, 1 inch and 10 inch. The distance was swept
with values of 1mil, 10mil and 100mil. Finally, the &lt;span class="glossary-term" tabindex="0" title=""&gt;
    dielectric
constant
&lt;/span&gt; was swept with values of 1, 10 and 100. This resulted in 27
unique cases, and the analytical result was compared to the extracted
result in each case.&lt;/p&gt;</description><author>Shield Digital Design</author><pubDate>Wed, 30 Sep 2020 19:00:00 GMT</pubDate><guid isPermaLink="true">https://shielddigitaldesign.com/posts/2020/cap/</guid></item><item><title>Geo in GL part 1: Flattening Earth</title><link>https://dorotac.eu/posts/flat_earth/</link><description>&lt;h1&gt;Geo in GL part 1: Flattening Earth&lt;/h1&gt;
&lt;p&gt;It's my guilty pleasure to flatten the Earth. To put it on various planar surfaces: pages of paper, scrolls, billboards, screens. Many prominent people attempted that before me: &lt;a href="https://en.wikipedia.org/wiki/Gerardus_Mercator"&gt;Mercator&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Cassini_projection"&gt;Cassini&lt;/a&gt;, just to name two.&lt;/p&gt;
&lt;p&gt;Yes, I'm talking about maps and projections.&lt;/p&gt;
&lt;p&gt;This is the first part of the story of how I used OpenGL &lt;a href="https://en.wikipedia.org/wiki/Shader"&gt;shaders&lt;/a&gt; to project the Earth onto the flat computer screen. Here I introduce the reader to the basics of &lt;a href="https://en.wikipedia.org/wiki/Map_projection"&gt;projections&lt;/a&gt;, write about the scope of my project, and then choose a projection that fits the scope.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: if you believe the Earth is already flat, this blog post won't offer anything interesting for you. You might still be interested in the following parts in the series.&lt;/p&gt;
&lt;h2&gt;What's the point?&lt;/h2&gt;
&lt;p&gt;I read someone online say shaders are bad for drawing maps: they aren't precise enough to distinguish distances a meter apart! Of course, I don't believe everything online, so I decided to check it myself, while refreshing my OpenGL knowledge, while playing with maps.&lt;/p&gt;
&lt;p&gt;Which brings me to the next point.&lt;/p&gt;
&lt;h2&gt;I like maps&lt;/h2&gt;
&lt;p&gt;While there are many representations of the real world, maps feel the most real. Some models turn the real into an unrecognizeable mess of abstract concepts. Maps are elegant, because they copy the real thing, just smaller. They aim to be recognizeable and familiar, so making them is always visually satisfying.&lt;/p&gt;
&lt;h2&gt;Distortions&lt;/h2&gt;
&lt;p&gt;Maps are not perfect, though. They are not scale models, and they contain some abstract parts: a mountain represented on a map will be as flat as the paper or screen it's on. If it's marked, it will be either a drawing of a mountain, or a squiggle of height lines.&lt;/p&gt;
&lt;p&gt;Most maps are also not globes. Our planet is round, and that means a flat map can't capture it accurately. Like a flattened orange peel, the map will get distorted: there will be tears or stretched places. The different ways to flatten the Earth to fit on a map are called &lt;em&gt;projections&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="3D-like Globe" src="ortho.png" /&gt;
This is also not a globe. It's just its picture! The picture is called &lt;em&gt;orthographic projection&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;The scope&lt;/h2&gt;
&lt;p&gt;There are multitudes of projections available. To narrow it down, it helps to define what kind of maps are interesting in this project. With that in mind, the initial version of the program will&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;display only small areas: not more than 100km in size. The smaller the area, the flatter the Earth surface, so distortions are smaller.&lt;/li&gt;
&lt;li&gt;Load a GPS track and display it as a squiggle. My GPS tracks are usually only a few hours long, and fit in the 100km size limit.&lt;/li&gt;
&lt;li&gt;Display nothing else. I don't want to get carried away and never prove what I set out to prove.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Projection choices&lt;/h2&gt;
&lt;p&gt;The last big decision was to choose a projection.&lt;/p&gt;
&lt;h3&gt;WGS84&lt;/h3&gt;
&lt;p&gt;Normally, we're used to seeing geographical coordinates of a point looking like: "&lt;em&gt;54,5°N 23,7°E&lt;/em&gt;". This representation seems obvious. We live on a sphere, and so we use &lt;a href="https://en.wikipedia.org/wiki/Spherical_coordinate_system"&gt;spherical coordinates&lt;/a&gt;. However, the prime meridian, and the precise measurement of the Earth axis, among oteher things, need to be standardized, so this representation is called &lt;a href="https://gisgeography.com/wgs84-world-geodetic-system/"&gt;WGS84&lt;/a&gt;. Since this is what GPS is using, it would be trivial to just plot the points from track on the screen as they are. However, the results would end up rather unappetizing:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Map of the world projected using WGS84" src="wgs84.png" /&gt;&lt;/p&gt;
&lt;p&gt;The distortions are huge! Can you see the grid sizes? Places at the equator are much smaller than at the poles, and the poles are extremely stretched sideways too – if you look at the globe, the grid is composed of wedges close to the poles. This would be a very unpleasant map to look at, even on our small scale.&lt;/p&gt;
&lt;h3&gt;Mercator&lt;/h3&gt;
&lt;p&gt;The stretching is easily fixable by applying a varying stretching factor across the vertical position. This gives us the &lt;a href="https://en.wikipedia.org/wiki/Mercator_projection"&gt;Mercator projection&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Map of the world projected with the Mercator projection" src="600px-Mercator_projection_Square.JPG" /&gt; Image copyright &lt;a href="https://commons.wikimedia.org/wiki/User:Strebe"&gt;Strebe&lt;/a&gt;, CC-BY-SA 3.0 Unported.&lt;/p&gt;
&lt;p&gt;This projection is easy to calculate, and it covers most of the world, so it's very popular on the Internet. Most online maps use it, including OpenStreetMap's own &lt;a href="https://osm.org"&gt;osm.org&lt;/a&gt;. However, it's still rather bad: the stretching factor approaches infinity as we approach the poles, so the map doesn't have a top and bottom edge. Instead it's just cut off somewhere. The other problem is that the areas at the equator are still much smaller than near poles.&lt;/p&gt;
&lt;h3&gt;Something different&lt;/h3&gt;
&lt;p&gt;It seems that both of those projections are quite bad at some places. But they are also both quite good at certain places: in this case, at the equator. So why don't we choose the best projection for our data?&lt;/p&gt;
&lt;p&gt;That's what paper maps do. Unlike general purpose computer map viewers, paper maps are often limited to a small area on the Earth. They can focus on making this area undistorted, and they can ignore all the misshapen mess that's not printed on the paper. I deliberately chose to limit my program's area of interest to a 100km radius to take advantage of this.&lt;/p&gt;
&lt;p&gt;For this, we need a projection that's not general like WGS84, or like the Mercator projection, but instead focussed on the area in question. To look at the North Pole in an undistorted way, we could choose the The North Pole Lambert Azimuthal Equal Area projection:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Map of the North Pole and surrounding continents" src="espg102017.png" /&gt;&lt;/p&gt;
&lt;p&gt;Here, I decided to increase my difficulty: I will not make an assumption about where on the Earth my GPS track is. It could be Europe, the Equator, or the Arctic. Instead, I will try to hit the bullseye and make sure that my projection favors the area I'm displaying, no matter what it is. For that, I need to find a family of projections that I can adjust.&lt;/p&gt;
&lt;p&gt;Thankfully, people have come up with &lt;a href="https://proj.org/operations/projections/index.html"&gt;plenty of different ways of projecting&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://proj.org/operations/projections/alsk.html"&gt;&lt;img alt="Alaska projected stereographically" src="alsk.png" /&gt;&lt;/a&gt;
&lt;a href="https://proj.org/operations/projections/moll.html"&gt;&lt;img alt="Oval world in Mollweide projection" src="moll.png" /&gt;&lt;/a&gt;
&lt;a href="https://proj.org/operations/projections/wink1.html"&gt;&lt;img alt="Oval world in Winkel I projection" src="wink1.png" /&gt;&lt;/a&gt;
&lt;a href="https://proj.org/operations/projections/vandg.html"&gt;&lt;img alt="Circle world in van der Grinten (I) projection" src="vandg.png" /&gt;&lt;/a&gt;
&lt;a href="https://proj.org/operations/projections/gstmerc.html"&gt;&lt;img alt="World as a crumpled ball of paper in Gauss-Schreiber Transverse Mercator projection" src="gstmerc.png" /&gt;&lt;/a&gt;
&lt;a href="https://proj.org/operations/projections/tobmerc.html"&gt;&lt;img alt="Diamond shaped world in Tobler-Mercator projection" src="tobmerc.png" /&gt;&lt;/a&gt;
&lt;a href="https://proj.org/operations/projections/imw_p.html"&gt;&lt;img alt="Cylinder world without poles in International Map of the World Polyconic projection" src="imw_p.png" /&gt;&lt;/a&gt;
&lt;a href="https://proj.org/operations/projections/ocea.html"&gt;&lt;img alt="World with North Pole at the bottom edge, and South Pole at the top edge in Oblique Cylindrical Equal Area projection" src="ocea.png" /&gt;&lt;/a&gt;&lt;br /&gt;
Various projections: Alaska, Mollweide, Winkel I, van der Grinten (I), Gauss-Schreiber Transverse Mercator, Tobler-Mercator, International Map of the World Polyconic, Oblique Cylindrical Equal Area. (Images courtesy &lt;a href="https://proj.org"&gt;PROJ&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;Some of them are tweakable, to name a few: &lt;a href="https://proj.org/operations/projections/aeqd.html"&gt;azimuthal equidistant&lt;/a&gt;, &lt;a href="https://proj.org/operations/projections/cass.html"&gt;Cassini&lt;/a&gt;, &lt;a href="https://proj.org/operations/projections/gnom.html"&gt;gnomonic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most of them preserve shapes over small areas rather well, so the choice is not that important. Nevertheless, I'm not an expert, so it's possible that I'm underestimating distortions. To stay on the safe side, I choose the azimuthal equidistant, because it promises that distances from the central point can be measured with a ruler. I used it previously with an overlaid kilometer grid and it worked well.&lt;/p&gt;
&lt;p&gt;Here's the projection in &lt;a href="https://proj.org/"&gt;proj&lt;/a&gt; form, so you can apply it in &lt;a href="https://www.qgis.org/en/site/"&gt;QGIS&lt;/a&gt;. Don't forget to adjust &lt;code&gt;lat_0&lt;/code&gt; and &lt;code&gt;lon_0&lt;/code&gt; to your area of interest!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+proj=aeqd +lat_0=54 +lon_0=24 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Next steps&lt;/h2&gt;
&lt;p&gt;I have the projection, but I still don't know the math behind it, and don't have any code. Stay tuned for the next part!&lt;/p&gt;</description><author>dcz's posts</author><pubDate>Wed, 30 Sep 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/flat_earth/</guid></item><item><title>Fred Roger's Method For Writing Scripts</title><link>https://josh.works/mr-rogers-method-for-writing-scripts</link><description>&lt;p&gt;Someone said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;People think this is silly, but read about Fred rogers’ method for writing a script for his show. The rules aren’t fully applicable to presentations, but the attention to detail and to the Interpretation of the audience is. Don’t use any words carelessly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’m not normal. I’ve got three articles open right now. Is there a canonical resource you’d recommend, or I should just seat-of-the-pants research it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img alt="screenshot" src="/images_2020/2020-09-30 at 3.16 PM.jpg" /&gt;&lt;/p&gt;

&lt;!--more--&gt;
&lt;p&gt;I’m going to knock out what I can in 20 minutes, share back with said individual, and calibrate on if they think I learned what I need to learn. Timer starts at 3:17p.&lt;/p&gt;

&lt;p&gt;It’s now 3:37.&lt;/p&gt;

&lt;p&gt;Conclusion:&lt;/p&gt;

&lt;p&gt;I didn’t find anything super specific to how he writes his scripts, but I think there’s a lot to glean from his approach to strongly empathizing with his audience. “strong empathy” feels like a criminal understatement.&lt;/p&gt;

&lt;p&gt;I’ve never seen Mr. Rogers. I’m tempted now to find some and watch it. If you’d recommend it, where should I start? Any youtube video overviews I should check out?&lt;/p&gt;

&lt;h3 id="10-things-tom-hangs-learned-by-playing-mr-rogers"&gt;10 things Tom Hangs learned by Playing Mr. Rogers&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://screenrant.com/beautiful-day-in-the-neighborhood-tom-hanks-learned-playing-mr-rogers/"&gt;A Beautiful Day In The Neighborhood: 10 Things Tom Hanks Learned By Playing Mr. Rogers (screenrant)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 10 lessons from the article.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Be kind, be kind, and be kind&lt;/li&gt;
  &lt;li&gt;Every single person you’re talking to should feel like they’re the only person in the world who matters&lt;/li&gt;
  &lt;li&gt;The slow, reflective nature of Mr. Rogers’ kindness&lt;/li&gt;
  &lt;li&gt;Be the message, don’t preach the message&lt;/li&gt;
  &lt;li&gt;Even now, keep looking for the helpers&lt;/li&gt;
  &lt;li&gt;The sweater is the key&lt;/li&gt;
  &lt;li&gt;Embrace the good and true, over the easy and cynical&lt;/li&gt;
  &lt;li&gt;To spread joy is the natural order of things&lt;/li&gt;
  &lt;li&gt;Kindness and compassion as ministry&lt;/li&gt;
  &lt;li&gt;It’s not just a children’s show&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The titles don’t do it justice. Some of these spoke very loudly to me.&lt;/p&gt;

&lt;p&gt;###&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.theatlantic.com/family/archive/2018/06/mr-rogers-neighborhood-talking-to-kids/562352/"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few quotes in particular jumped out at me:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Per the pamphlet, there were nine steps for translating into Freddish:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;“State the idea you wish to express as clearly as possible, and in terms preschoolers can understand.” Example: &lt;code class="language-plaintext highlighter-rouge"&gt;It is dangerous to play in the street.&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;“Rephrase in a positive manner,” as in &lt;code class="language-plaintext highlighter-rouge"&gt;It is good to play where it is safe.&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;“Rephrase the idea, bearing in mind that preschoolers cannot yet make subtle distinctions and need to be redirected to authorities they trust.” As in, &lt;code class="language-plaintext highlighter-rouge"&gt;Ask your parents where it is safe to play.&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;“Rephrase your idea to eliminate all elements that could be considered prescriptive, directive, or instructive.” In the example, that’d mean getting rid of “ask”: &lt;code class="language-plaintext highlighter-rouge"&gt;Your parents will tell you where it is safe to play.&lt;/code&gt;`&lt;/li&gt;
    &lt;li&gt;“Rephrase any element that suggests certainty.” That’d be “will”: &lt;code class="language-plaintext highlighter-rouge"&gt;Your parents can tell you where it is safe to play.&lt;/code&gt;`&lt;/li&gt;
    &lt;li&gt;“Rephrase your idea to eliminate any element that may not apply to all children.” Not all children know their parents, so: &lt;code class="language-plaintext highlighter-rouge"&gt;Your favorite grown-ups can tell you where it is safe to play.&lt;/code&gt;&lt;/li&gt;
    &lt;li&gt;“Add a simple motivational idea that gives preschoolers a reason to follow your advice.” Perhaps: &lt;code class="language-plaintext highlighter-rouge"&gt;Your favorite grown-ups can tell you where it is safe to play. It is good to listen to them.&lt;/code&gt;`&lt;/li&gt;
    &lt;li&gt;“Rephrase your new statement, repeating the first step.” “Good” represents a value judgment, so: &lt;code class="language-plaintext highlighter-rouge"&gt;Your favorite grown-ups can tell you where it is safe to play. It is important to try to listen to them.&lt;/code&gt;`&lt;/li&gt;
    &lt;li&gt;“Rephrase your idea a ﬁnal time, relating it to some phase of development a preschooler can understand.” Maybe: &lt;code class="language-plaintext highlighter-rouge"&gt;Your favorite grown-ups can tell you where it is safe to play. It is important to try to listen to them, and listening is an important part of growing.&lt;/code&gt;`&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;In working on the show, Rogers interacted extensively with academic researchers. Daniel R. Anderson, a psychologist formerly at the University of Massachusetts who worked as an advisor for the show, remembered a speaking trip to Germany at which some members of an academic audience raised questions about Rogers’s direct approach on television. They were concerned that it could lead to false expectations from children of personal support from a televised figure. Anderson was impressed with the depth of Rogers’s reaction, and with the fact that he went back to production carefully screening scripts for any hint of language that could confuse children in that way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;As simple as Mister Rogers’ Neighborhood looked and sounded, every detail in it was the product of a tremendously careful, academically informed process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;p&gt;Now I’m wondering about the financial success of his show.&lt;/p&gt;

&lt;h3 id="wikipedia-fred-rogers"&gt;Wikipedia: Fred Rogers&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Fred_Rogers"&gt;link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The show was popular:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;by 2016 it was the third-longest running program in PBS history&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ah, here’s how involved he was:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;According to King, the process of putting each episode of Mister Rogers’ Neighborhood together was “painstaking”[59] and Rogers’ contribution to the program was “astounding”. Rogers wrote and edited all the episodes, played the piano and sang for most of the songs, wrote 200 songs and 13 operas, created all the characters (both puppet and human), played most of the major puppet roles, hosted every episode, and produced and approved every detail of the program.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;He had two stages to the show:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;n 1975 Rogers stopped producing Mr. Rogers’ Neighborhood to focus on adult programming. […] In 1979, after an almost five-year hiatus, Rogers returned to producing the Neighborhood; King calls the new version “stronger and more sophisticated than ever”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahhh…. influence, and storytelling:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Even though Rogers was not yet nationally known, he was chosen to testify because of his ability to make persuasive arguments and to connect emotionally with his audience. The clip of Rogers’ testimony, which was televised and has since been viewed by millions of people on the internet, helped to secure funding for PBS for many years afterwards.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lets watch the clip, or queue it up for later at least. He starts to speak at 0:20:&lt;/p&gt;



&lt;p&gt;I &lt;em&gt;will&lt;/em&gt; watch this video, just not quite right now.&lt;/p&gt;

&lt;p&gt;Oh, and he’s from Pittsburgh. I went to school near there, just finished working remotely for a company in Pittsburgh. I loved visiting the city.&lt;/p&gt;

&lt;h2 id="optional-next-steps"&gt;Optional Next Steps&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;I could read &lt;a href="https://www.amazon.com/Good-Neighbor-Life-Work-Rogers/dp/1419735160/ref=sr_1_2?dchild=1&amp;amp;keywords=the+good+neighbor&amp;amp;qid=1601501543&amp;amp;sr=8-2"&gt;Good Neighbor: The Life and Work of Fred Rogers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Actually watch some Mr. Rogers clips. I’m tempted to do that anyway, now.&lt;/li&gt;
  &lt;li&gt;Any recommended youtube videos?&lt;/li&gt;
&lt;/ol&gt;</description><author>Josh Thompson</author><pubDate>Wed, 30 Sep 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/mr-rogers-method-for-writing-scripts</guid></item><item><title>How to write a Principle</title><link>https://adamcraven.com/writing/how-to-write-a-principle/</link><description/><author>Writing on Adam Craven</author><pubDate>Wed, 30 Sep 2020 13:53:24 GMT</pubDate><guid isPermaLink="true">https://adamcraven.com/writing/how-to-write-a-principle/</guid></item><item><title>Object Detection from 9 FPS to 650 FPS in 6 Steps</title><link>https://paulbridger.com/posts/video-analytics-pipeline-tuning/</link><description>Making code run fast on GPUs requires a very different approach to making code run fast on CPUs because the hardware architecture is fundamentally different. Machine learning engineers of all kinds should care about squeezing performance from their models and hardware — not just for production purposes, but also for research and training. In research as in development, a fast iteration loop leads to faster improvement. This article is a practical deep dive into making a specific deep learning model (&lt;a href="https://pytorch.org/hub/nvidia_deeplearningexamples_ssd/"&gt;Nvidia&amp;rsquo;s SSD300&lt;/a&gt;) run fast on a powerful GPU server, but the general principles apply to all GPU programming.</description><author>Machine Learning Articles on paulbridger.com</author><pubDate>Wed, 30 Sep 2020 09:43:23 GMT</pubDate><guid isPermaLink="true">https://paulbridger.com/posts/video-analytics-pipeline-tuning/</guid></item><item><title>Bullshit Jobs to Basic Income : Redesiging economic rewards</title><link>https://yasha.solutions/bullshit-jobs-to-basic-income-redesigning-economic-rewards/</link><description>Bullshit Job : not what you think David Graeber has turned what would have happily stayed a colourful expression of our daily lives into an actual concept. In his book Bullshit Jobs - A Theory published fairly recently in 2018, he expands on the concept :
 A bullshit job is one that even the person doing it secretly believes need not, or should not, exist. That if the job, or even the whole industry, were to vanish, either it would make no difference to anyone, or the world might even be a slightly better place.</description><author>Yasha Solutions</author><pubDate>Wed, 30 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://yasha.solutions/bullshit-jobs-to-basic-income-redesigning-economic-rewards/</guid></item><item><title>Untitled • Art</title><link>https://muffinman.io/art/hex-truchet-untitled/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;Be sure to check the timelapse in the gallery below.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;September 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;52x27cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;200gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Sakura Gelly Roll 0.8mm pen&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery art-gallery--wide"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1562" src="./0.jpg" width="3000" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1500" src="./w_500-h_500--1.jpg" width="2000" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./plot_1920x1080.mp4"&gt;&lt;video class="gallery__video" src="./plot_1920x1080.mp4#t=0.001"&gt;&lt;/video&gt;&lt;svg class="gallery__play-icon" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20 c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Wed, 30 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/hex-truchet-untitled/</guid></item><item><title>Leading Up to Shadowlands</title><link>https://benovermyer.com/blog/2020/09/leading-up-to-shadowlands/</link><description>&lt;p&gt;The Shadowlands expansion for World of Warcraft comes out next month. A lot of things seem to be happening in October this year. I'm opting to focus my gaming time on WoW, given the new expansion.&lt;/p&gt;
&lt;p&gt;A month ago, I was playing a lot of WoW. The new expansion offers a lot of opportunities for starting new characters, and I wanted to unlock the Vulpera allied race to try something new. Unlocking that race previously required completing a particular story arc and reaching Exalted status with the Vulpera. I'd finished the story arc, but the reputation grind was quite a slog, and I hadn't come close to finishing it.&lt;/p&gt;
&lt;p&gt;Then, I discovered that the pre-patch for Shadowlands was going to remove the reputation grind from unlocking allied races. This completely killed my interest in playing WoW before the pre-patch hits, and I haven't played since, despite keeping my subscription active.&lt;/p&gt;
&lt;p&gt;As soon as the pre-patch is live, I'm diving back into the game with a vengeance. My new character will be a Vulpera shaman. I want to play a healer, and the Vulpera shaman's totems are fox-shaped which I love.&lt;/p&gt;
&lt;p&gt;The new leveling experience takes you from 1 to 50 (the new pre-expansion cap) in a single expansion's content. I'm going to go through Wrath of the Lich King as my choice, since that remains my favorite expansion so far. It remains to be seen if I will blog about this process or not, but it might be fun to journal my experience. I don't think I'll be able to reach level 50 with my Vulpera before the expansion lands, but that's going to be my goal anyway.&lt;/p&gt;
&lt;p&gt;I don't know if pet battle levels will be rewired too, but if they are, I definitely want to try and bring at least one group of pets up to level cap during my leveling. We'll see how that works out.&lt;/p&gt;
&lt;p&gt;So yeah. I'll be retiring Exsecratus as my main, which is only the second time I've ever changed mains since I first started playing WoW back in 2004. Here's to new beginnings!&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Wed, 30 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/09/leading-up-to-shadowlands/</guid></item><item><title>Faster Literal String Matching in Go</title><link>https://boyter.org/posts/faster-literal-string-matching-in-go/</link><description>&lt;p&gt;&lt;strong&gt;TL/DR:&lt;/strong&gt; I wrote a fast literal string matching library in Go get it here &lt;a href="https://github.com/boyter/go-string/"&gt;https://github.com/boyter/go-string/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Recently I rebuilt &lt;a href="https://searchcode.com/"&gt;searchcode&lt;/a&gt; in Go, as &lt;a href="https://boyter.org/posts/searchcode-rebuilt-with-go/"&gt;mentioned&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While there was a variety of reasons for this one was that performance in the previous Python version was not great. Please note this was mostly due to my own shortcomings and not the language itself. However I have always used searchcode as a test bed for interesting problems, since it gets enough traffic to verify things at scale, and I wanted to get better at Go.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Wed, 30 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/faster-literal-string-matching-in-go/</guid></item><item><title>Pre-training via Paraphrasing (Paper Explained)</title><link>https://whoisnnamdi.com/pre-training-paraphrasing/</link><description>Transformer model pre-trained on document retrieval and reconstruction performs well on both fine-tuned and zero-shot downstream tasks</description><author>Who is Nnamdi?</author><pubDate>Wed, 30 Sep 2020 00:03:16 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/pre-training-paraphrasing/</guid></item><item><title>Recovering after a root-partition resize gone wrong</title><link>https://www.zufallsheld.de/2020/09/29/recover-root-partition-resize-gone-wrong/</link><description>&lt;p&gt;Recently I tried to resize a &lt;span class="caps"&gt;LVM&lt;/span&gt; logical volume with its volume group and the physical disk belonging to the vg.
Because the logical volume contained all partitions except&amp;nbsp;for &lt;code&gt;/boot&lt;/code&gt; I knew it would be&amp;nbsp;hard.&lt;/p&gt;
&lt;!-- PELICAN_END_SUMMARY --&gt;

&lt;p&gt;I also knew that I had no backup and no snapshot of the …&lt;/p&gt;</description><author>zufallsheld</author><pubDate>Tue, 29 Sep 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://www.zufallsheld.de/2020/09/29/recover-root-partition-resize-gone-wrong/</guid></item><item><title>What Amy Coney Barrett on the Supreme Court would REALLY mean for the future of tech</title><link>https://stop.zona-m.net/2020/09/what-amy-coney-barrett-on-the-supreme-court-would-really-mean-for-the-future-of-tech/</link><description>&lt;p&gt;Let&amp;rsquo;s put things in perspective, please.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 29 Sep 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/what-amy-coney-barrett-on-the-supreme-court-would-really-mean-for-the-future-of-tech/</guid></item><item><title>The Definitive Guide to Commonly Used Words in React</title><link>https://maxrozen.com/definitive-glossary-guide-commonly-used-words-react</link><description>Do some words in React have you scratching your head? Ref? Stateless component? Let's learn some words!</description><author>Max Rozen</author><pubDate>Tue, 29 Sep 2020 12:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/definitive-glossary-guide-commonly-used-words-react</guid></item><item><title>Intentional Documentation</title><link>https://blog.harterrt.com/randy_au_d11n.html</link><description>&lt;p&gt;Randy Au has a great post on documentation for data scientists here:
&lt;a href="https://counting.substack.com/p/lets-get-intentional-about-documentation"&gt;Let's get intentional about documentation&lt;/a&gt;.
Take a look, it's worth a read.&lt;/p&gt;
&lt;p&gt;I've been able to find some decent guides for writing documentation
but they're usually targeted at engineers.
That's a shame. 
Data scientists have significantly different 
constraints …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Tue, 29 Sep 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/randy_au_d11n.html</guid></item><item><title>Adapting Learning Systems To Today's World</title><link>https://yasha.solutions/adapting-learning-systems-to-todays-world/</link><description>Covid-19 has forced us into a reality where colocallity can only be virtual.
While the press, inspired by the promises from some Silicon Valley giants, has tried to forecast how and when humanity would become a remote-first society, nobody came up with the creative scenario where a pandemic would be the trigger for global digital transformation.
In this new reality, schools and universities need to adapat.
Beyond the Zoom-Classroom experience.</description><author>Yasha Solutions</author><pubDate>Tue, 29 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://yasha.solutions/adapting-learning-systems-to-todays-world/</guid></item><item><title>2020–09–29: New codec driver in my 5.9 kernel</title><link>https://xnux.eu/log/#020</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 29 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#020</guid></item><item><title>Minimum elucidating examples</title><link>https://bastian.rieck.me/blog/2020/elucidating_examples/</link><description>&lt;p&gt;I tend to learn new concepts best by seeing an &lt;em&gt;example&lt;/em&gt; of them. This
dates back to when I first started studying mathematics: I felt that I
was able to actually &lt;em&gt;work&lt;/em&gt; with a certain definition once I had at
least an intuitive grasp of what is meant. I quickly discovered that
there are at least three kinds of examples. The first kind is trivial,
leading to even more confusion, the second kind is too complex, and the
third kind is actually elucidating. It is the third kind of example that
I am primarily interested in here, so let&amp;rsquo;s quickly discuss the other
two and move on.&lt;/p&gt;
&lt;p&gt;Examples of the first kind are trivial. Suppose you want to illustrate
the concept of addition and state that $1 + 0 = 1$. This is obviously
correct but does not teach you anything because it contains the idea
that $a + 0 = a$ as a &lt;em&gt;confounding property&lt;/em&gt;. Likewise, mentioning the
empty set $\emptyset$ as an example of a certain kind of structure is
always good for some laughs,&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; but it does not really help you
understand what is going on.&lt;/p&gt;
&lt;p&gt;Examples of the second kind are not more helpful. They are characterised
by a rapid increase in complexity that just bogs you down without really
helping you gain intuition or understanding. &lt;a href="https://abstrusegoose.com/474"&gt;This Abstruse Goose comic&lt;/a&gt;
provides a marvellous instance.&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt; Other examples include, say, teaching
you about &lt;a href="https://en.wikipedia.org/wiki/Determinant"&gt;determinants&lt;/a&gt; by
letting you invert a $10 \times 10$ matrix, when a smaller dimension
would have been sufficient.&lt;/p&gt;
&lt;p&gt;Examples of the third kind help you grow and understand. I call these
examples &lt;em&gt;minimum elucidating examples&lt;/em&gt;: they have &lt;em&gt;just&lt;/em&gt; the right
amount of complexity to not be wholly trivial, but they are simple
enough to be remembered and understood correctly. For instance, when
learning about group theory, some elucidating examples are the additive
group over the integers, $\mathbb{Z}/2\mathbb{Z}$ (the group with
only two elements), or, to be a little bit more complex, the general
linear group of all real invertible matrices. The utility of such an
elucidating example depends heavily on the context&amp;mdash;as a student,
I preferred learning about the &amp;rsquo;number groups&amp;rsquo; first, but nowadays, my preferred
go-to example is the general linear group, because it is more
abstract and provides a better glimpse into the power of group theory.&lt;/p&gt;
&lt;p&gt;Closely related to such elucidating examples are elucidating
&lt;em&gt;non-examples&lt;/em&gt; (or counterexamples). In group theory, the natural
numbers $\mathbb{N}$ come to mind: lacking an additive
inverse for every element except $0$, every student can easily grasp
that the additional requirements raise the bar for something to be
called a group, while at the same time illustrating that a much richer
structure is exposed by demanding these properties.&lt;/p&gt;
&lt;p&gt;Of particular pedagogical interest are examples that &lt;em&gt;defy&lt;/em&gt; our
presuppositions. These are counterexamples to our misplaced intuitions!
For instance, the &lt;a href="https://en.wikipedia.org/wiki/Cantor_set"&gt;Cantor set&lt;/a&gt;
is a marvellous counterexample in measure theory:&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; typically,
students only encounter sets with measure zero that are &lt;em&gt;countable&lt;/em&gt;.
This can lead to the wrong impression that &amp;lsquo;measure zero&amp;rsquo; and
&amp;lsquo;countable&amp;rsquo; are somewhat equivalent. The Cantor set destroys this
illusion, as it constitutes a set that is &lt;em&gt;uncountable&lt;/em&gt; while having
measure zero! My mind was shattered when I first learned about this, and
since then, the Cantor set has been a cherished counterexample in my
toolbox.&lt;/p&gt;
&lt;p&gt;Having switched academic fields for a while now, I sometimes wonder what
minimum elucidating examples &lt;em&gt;we&lt;/em&gt; should develop for machine
learning (ML).  What is the smallest useful architecture and data set that demonstrates
issues such as &lt;a href="https://en.wikipedia.org/wiki/Vanishing_gradient_problem"&gt;vanishing gradients&lt;/a&gt;?
Is there a way to store and disseminate such counterexamples? Would the
aspiring ML researcher find them useful and digest them, or are we still
in the &amp;lsquo;pragmatic phase&amp;rsquo; of our field and use whatever works, without
caring too much about the theoretical underpinnings? Time will
tell&amp;mdash;and I for one hope to collect as many juicy minimum elucidating
(counter)examples as I possibly can.&lt;/p&gt;
&lt;p&gt;Until next time, have fun being exemplary!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Full disclosure: as a cheeky undergraduate, I did this a few times
in oral exams. It is funny but probably less so for the professors who
have to endure that sort of humour all day long.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;I disagree with the comic on one thing, though: maths textbooks
tend to follow this recipe more often than computer science textbooks,
in my experience.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Measure theory deals with &lt;em&gt;measuring&lt;/em&gt; subsets of Euclidean space,
assigning them a number that describes their &amp;lsquo;size&amp;rsquo;; think of a generalisation of
the concepts of &lt;em&gt;area&lt;/em&gt; or &lt;em&gt;volume&lt;/em&gt;. Measure theory is often invoked
when dealing with problematic solutions or inputs to
functions&amp;mdash;essentially, one tries to show that while such degenerate
inputs may exist, they are &amp;rsquo;too small&amp;rsquo; (in the sense of measure
theory) to worry about.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Mon, 28 Sep 2020 22:00:40 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/elucidating_examples/</guid></item><item><title>Why did you choose Microsoft? Sorry, don't know</title><link>https://stop.zona-m.net/2020/09/why-did-you-choose-microsoft-sorry-dont-know/</link><description>&lt;p&gt;A sad, sadly unsurprising story about an italian Ministry.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 28 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/why-did-you-choose-microsoft-sorry-dont-know/</guid></item><item><title>How To Set Up a Ruby Dev Environment on Ubuntu Linux</title><link>https://www.mikekasberg.com/blog/2020/09/27/set-up-a-ruby-dev-environment.html</link><description>&lt;p&gt;Setting up a development environment correctly might not seem like a big deal at
first, but an incorrectly set-up environment can cause a lot of problems down
the road if you’re not careful. In my experience, the internet’s full of
solutions – both good and bad – for environment problems, but often does a poor
job of explaining &lt;em&gt;why&lt;/em&gt; a solution’s good or bad. And installing Ruby can be
tricky if you’ve never done it before. So here’s my advice.&lt;/p&gt;

&lt;p&gt;Let’s say you want to run a gem – for example, &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt;.
To run the gem, you’ll have to install Ruby and then install the gem. Rather
than jumping straight to the best solution, I’m first going to look at &lt;strong&gt;what
not to do&lt;/strong&gt; so you can understand what problems this might cause. After seeing
what not do to, we’ll look at a couple better solutions, and we’ll see the
advantages and disadvantages of each. By the end, I’ll show you what I think is
the best way to install Ruby so you can avoid environment headaches.&lt;/p&gt;

&lt;div class="message"&gt;
&lt;p&gt;&lt;b&gt;In a hurry?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Want to go straight to the instructions for the proper way (in my opinion) to install Ruby without reading about what not to do?&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.mikekasberg.com/blog/2020/09/27/set-up-a-ruby-dev-environment.html#the-best-solution-how-to-install-ruby-with-rbenv"&gt;Skip ahead&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id="what-not-to-do"&gt;What Not To Do&lt;/h2&gt;

&lt;p&gt;When you’re a beginner with Ruby or Linux (we’ve all been there) and all you
want to do is run a gem, &lt;code class="language-plaintext highlighter-rouge"&gt;sudo&lt;/code&gt; appears to solve all your problems. You might
come across advice like this:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Install Ruby&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install ruby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install the gem&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ sudo gem install jekyll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Use the gem. Done.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ jekyll --version
jekyll 4.1.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While this might appear to solve everything, it can also create a host of new
problems. For example, maybe you’ll need to install some gems with
&lt;a href="https://bundler.io/"&gt;Bundler&lt;/a&gt; a few days later. If you try using &lt;code class="language-plaintext highlighter-rouge"&gt;sudo&lt;/code&gt; to
install gems with Bundler, you’ll probably see a warning like this one:&lt;/p&gt;

&lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ sudo bundle install
Don't run Bundler as root. Bundler can ask for sudo if it is needed, and
installing your bundle as root will break this application for all non-root
users on this machine.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Bundler warns you that this isn’t the best way to do things - root will be the
owner of all the files bundler installs, and from that point on you’ll have to
continue using &lt;code class="language-plaintext highlighter-rouge"&gt;sudo&lt;/code&gt; to get gem updates until you fix your file permissions.&lt;/p&gt;

&lt;p&gt;But beyond this, installing gems with &lt;code class="language-plaintext highlighter-rouge"&gt;sudo&lt;/code&gt; can actually be dangerous -
particularly since gems can execute scripts when they install. For example, see
&lt;a href="https://github.com/wmorgan/killergem"&gt;killergem&lt;/a&gt;. Even if you didn’t install
this malicious gem directly, if one of the gems you try to install even depends
on a malicious or compromised gem, it could be bad news. Let’s look at a better
solution…&lt;/p&gt;

&lt;h2 id="a-quick--simple-solution"&gt;A Quick &amp;amp; Simple Solution&lt;/h2&gt;

&lt;p&gt;So if the above steps are problematic, what can we do that’s safer? Maybe you
just want to run a quick script or gem and you don’t care about managing
specific versions of Ruby. You want a simple solution that works and doesn’t
have permissions problems.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Install Ruby. For simplicity, we’ll use whatever version is in Ubuntu’s
repositories. Using sudo is OK here because we’re using apt-get.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ sudo apt-get install ruby
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install the gem. Since we’re installing a gem (rather than a system package
from apt), we won’t use sudo. Instead, we’ll pass the &lt;code class="language-plaintext highlighter-rouge"&gt;--user-install&lt;/code&gt; flag when
we install our gem.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ gem install --user-install jekyll
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;The &lt;code class="language-plaintext highlighter-rouge"&gt;--user-install&lt;/code&gt; portion is key – it installs the gem in a directory our
user has permissions to. You’ll probably see a warning like this:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;WARNING:  You don’t have /home/mike/.gem/ruby/2.7.1/bin in your PATH, gem executables will not run.&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;That’s OK – we’ll fix it in the next step.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;As the warning says, &lt;code class="language-plaintext highlighter-rouge"&gt;~/.gem/ruby/2.7.1/bin&lt;/code&gt; isn’t in our PATH. So let’s put
it there. Ubuntu comes with a &lt;code class="language-plaintext highlighter-rouge"&gt;~/.profile&lt;/code&gt; file that adds a couple things to our
path by default, and I like to build on that file. Modify it to include these
lines:&lt;/p&gt;

    &lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;# Add User Ruby Gems
if [ -d "$HOME/.gem/ruby/2.7.1/bin" ]; then
    PATH="$HOME/.gem/ruby/2.7.1/bin:$PATH"
fi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;For the changes to take effect, we can either log out and log back in or
simply run &lt;code class="language-plaintext highlighter-rouge"&gt;source ~/.profile&lt;/code&gt;. We can confirm it worked by running &lt;code class="language-plaintext highlighter-rouge"&gt;which
jekyll&lt;/code&gt;, which should return &lt;code class="language-plaintext highlighter-rouge"&gt;~/.gem/ruby/2.7.1/bin/jekyll&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Done. We’ve installed the &lt;code class="language-plaintext highlighter-rouge"&gt;jekyll&lt;/code&gt; gem without using &lt;code class="language-plaintext highlighter-rouge"&gt;sudo&lt;/code&gt;. In this case, for
simplicity, we’re relying on our OS to provide an easy-to-user Ruby installer.
This is fine, but it does mean &lt;strong&gt;we’re stuck with the version of Ruby that our
OS provides&lt;/strong&gt;. Which is fine for simple needs (like running a few simple scripts
or gems), but might not be ideal if, for example, you’re developing a Ruby
application that requires a specific version and want to upgrade your version of
Ruby independently of your OS. If you’re regularly programming in Ruby, it will
be important for you to install the version of Ruby required by your
application, and possibly install multiple versions of Ruby for multiple
applications or during upgrades.&lt;/p&gt;

&lt;h2 id="the-best-solution-how-to-install-ruby-with-rbenv"&gt;The Best Solution: How to Install Ruby with rbenv&lt;/h2&gt;

&lt;p&gt;The best solution for installing Ruby and managing your installation is a Ruby
version manager. Using a version manager allows you to have multiple versions of
Ruby installed at once and select the one you want to use. It also decouples
your Ruby installation from your OS package manager, and provides a solution for
doing everything without sudo. There are a few options for version managers.
&lt;a href="https://rvm.io/"&gt;RVM&lt;/a&gt; is reputable and has a good following, but in my humble
opinion &lt;a href="https://github.com/rbenv/rbenv"&gt;rbenv&lt;/a&gt; is simpler and easier to use. To
install rbenv, you can find the most up-to-date official instructions
&lt;a href="https://github.com/rbenv/rbenv#basic-github-checkout"&gt;here&lt;/a&gt;, but they can be a
little confusing, and they’ll boil down to something like this:&lt;/p&gt;

&lt;div class="warning"&gt;
&lt;p&gt;&lt;b&gt;Remove old Ruby versions first!&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;It is confusing to have Ruby installed by both apt-get and rbenv on the same system. If you've already installed Ruby with apt-get, you should remove it before continuing. You can do so with &lt;code&gt;sudo apt-get purge ruby&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;We’ll need git and curl to run the rbenv installer. Run the following to
make sure they’re installed.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ sudo apt-get install git curl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Run the rbenv installer.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-installer | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add rbenv to your path by adding it to your &lt;code class="language-plaintext highlighter-rouge"&gt;~/.bashrc&lt;/code&gt;. You’ll have to log
out and log back in or &lt;code class="language-plaintext highlighter-rouge"&gt;source ~/.bashrc&lt;/code&gt; for the changes to take effect.
(And we’re tackling 2 steps at once by including the &lt;code class="language-plaintext highlighter-rouge"&gt;rbenv init&lt;/code&gt; line
here.)&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ echo '
if [ -d "$HOME/.rbenv/bin" ]; then
    PATH="$HOME/.rbenv/bin:$PATH"
    eval "$(rbenv init - bash)"
fi' &amp;gt;&amp;gt; ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Check to make sure it worked with &lt;code class="language-plaintext highlighter-rouge"&gt;rbenv-doctor&lt;/code&gt;. This will save you some
headaches by printing errors if anything’s not quite right.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/HEAD/bin/rbenv-doctor | bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;You’ll see something like this, letting you know that rbenv is installed but
no versions of Ruby are installed yet.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Counting installed Ruby versions: none
  There aren’t any Ruby versions installed under `/home/mkasberg/.rbenv/versions’.
  You can install Ruby versions like so: rbenv install 2.7.1&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We’re going to use rbenv to install a version of Ruby, but before we do that
we need to make sure we have the tools to build ruby installed. (If you
skip this step, the installer won’t work and will give you an error message
about what you need to install to compile Ruby. We can save time by just
installing what we need now.)&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ sudo apt-get install build-essential libssl-dev libyaml-dev zlib1g-dev libffi-dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, we’re ready to install Ruby. I like to run the help command first to
see what I’m about to do. You should generally install whatever the latest
stable version is. At the time of writing, it’s &lt;code class="language-plaintext highlighter-rouge"&gt;2.7.1&lt;/code&gt;.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ rbenv help install
$ rbenv install --list
$ rbenv install 2.7.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;At this point, you’re basically &lt;strong&gt;done&lt;/strong&gt;! Again, we can skim the help menu to
see what other commands are available. And it’s a good idea to set the
version we just installed as the global ruby version.&lt;/p&gt;

    &lt;div class="language-plaintext terminal highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;$ rbenv help
$ rbenv global 2.7.1
$ rbenv version
$ ruby --version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One thing that’s great about rbenv is it does not tie you in to a specific ruby
version. You can set up &lt;a href="https://github.com/rbenv/rbenv#rbenv-local"&gt;local&lt;/a&gt;
(per-directory) and shell (per-terminal) versions if you want. Simply &lt;code class="language-plaintext highlighter-rouge"&gt;rbenv
install x.x.x&lt;/code&gt; and then use the correct commands (see the docs) to pick your
version. In addition to this, by default, rbenv will allow you to &lt;a href="https://github.com/rbenv/rbenv#installing-ruby-gems"&gt;install
gems&lt;/a&gt; to a location that
doesn’t require sudo (with a normal &lt;code class="language-plaintext highlighter-rouge"&gt;gem install&lt;/code&gt; command), which should prevent
a lot of headaches.&lt;/p&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Sun, 27 Sep 2020 18:15:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/09/27/set-up-a-ruby-dev-environment.html</guid></item><item><title>How behaviour can shape the culture</title><link>https://ilearnt.com/blog/culturebehaviour/</link><description>&lt;p&gt;Andrew Cherrie is the pastor of Home Church. In a recent sermon entitled &amp;ldquo;7 lessons from 7 years at Home Church&amp;rdquo; he gave the following quote:&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sun, 27 Sep 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/culturebehaviour/</guid></item><item><title>Solitude and conversations lead to great ideas</title><link>https://ilearnt.com/blog/solitudeandconversation/</link><description>&lt;p&gt;There was a tweet recently by Sahil Lavingia that stated&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sun, 27 Sep 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/solitudeandconversation/</guid></item><item><title>5 TILs about Node.js Fundamentals from the Node.js Design Patterns Book</title><link>https://www.swyx.io/til-node-fundamentals-design-patterns-book</link><description>5 Things I Learned about Node.js Fundamentals from the Node.js Design Patterns Book</description><author>swyx's site RSS Feed</author><pubDate>Sun, 27 Sep 2020 11:48:33 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/til-node-fundamentals-design-patterns-book</guid></item><item><title>Adding images to pdfs (macOS)</title><link>https://xenodium.com/adding-images-to-pdfs-macos</link><description>&lt;p&gt;The macOS Preview app does a great job inserting signatures to existing pdfs. I was hoping it could overlay images just as easily. Doesn't look like it's possible, without exporting/reimporting to image formats and losing pdf structure. Did I miss something?&lt;/p&gt;
&lt;p&gt;In any case, I found &lt;a href="https://code.google.com/archive/p/formulatepro/"&gt;formulatepro&lt;/a&gt;. Dormant at Google Code Archive, but also &lt;a href="https://github.com/adlr/formulatepro"&gt;checked in to github&lt;/a&gt;. With a tiny &lt;a href="https://github.com/xenodium/formulatepro/commit/cd43b1e73c2f180f4b4b7fb11fdec975b6960dc6"&gt;patch&lt;/a&gt;, it builds and runs on Catalina. One can easily insert an image via &amp;quot;File &amp;gt; Place Image…&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/adding-images-to-pdfs-macos/formulatepro.png" /&gt;&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 27 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/adding-images-to-pdfs-macos</guid></item><item><title>DIY bookmarks</title><link>https://xenodium.com/diy-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://linuxhint.com/best_electrical_insulation_tape/"&gt;Best electrical insulation tape&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/rosen/status/1317843289530376196"&gt;I’ve spent the last 3 months building the home office of my dreams&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 27 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/diy-bookmarks</guid></item><item><title>Armenia, Azerbaijan, Turkey. Who's the Aggressor? ⚔️</title><link>https://ashvardanian.com/posts/aggressor/</link><description>Three countries, vastly different resources and freedoms. The numbers reveal who's really threatening peace in the region.</description><author>Ash's Blog</author><pubDate>Sun, 27 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ashvardanian.com/posts/aggressor/</guid></item><item><title>Our New Species (Part 2/2)</title><link>http://spirals.blog/articles/our-new-species-pt-2/</link><description>&lt;div class="toc"&gt;
This is part two of this story. &lt;a href="http://spirals.blog/articles/our-new-species-pt-1"&gt;You can read part one here!&lt;/a&gt;
&lt;/div&gt;
&lt;h2&gt;The Age of the Spiritual Machine&lt;/h2&gt;
&lt;h3&gt;Lunch with a “Connected One”&lt;/h3&gt;
&lt;p&gt;The unbranded restaurant was eerily silent as Harrison climbed the marble steps to meet the host.&lt;/p&gt;
&lt;p&gt;“Hi, ugh, I’m here to meet someone?” He asked.&lt;/p&gt;
&lt;p&gt;“Right this way please, Mr. Fuller,” the restaurant’s host was dressed in smart trousers, a white dress shirt, and a black bow-tie.&lt;/p&gt;
&lt;p&gt;“Wait, how do you know my–“Harrison started.&lt;/p&gt;
&lt;p&gt;“Ah, my apologies, sir. The Link allows for easy facial recognition matching from a public dataset. It’s standard practice. I did not mean to invade your privacy” He smiled, but professionally, almost… practiced. His British accent and cool demeanor intimidated Harrison. What was this place?&lt;/p&gt;
&lt;p&gt;He lead them down a dark hallway, modern art dripping from the long, polished, concrete walls, which opened out into a circular, cobblestone courtyard. A large tree rose from the center, reaching for the blue sky. The open ceiling shone a cold light on the small restaurant, dotted with exotic plants, polished wooden tables, and suave guests eating in silence. The entire scene gave Harrison the chills.&lt;/p&gt;
&lt;p&gt;The host directed Harrison to a table on the opposite side of the circle. A young, attractive man was sitting at the wooden table alone, his eyes closed. He seemed peaceful, almost meditative, as Harrison approached.&lt;/p&gt;
&lt;p&gt;Jacob awoke from wherever he was.&lt;/p&gt;
&lt;p&gt;“Hello Harrison,” his voice was calm and smooth, “It’s nice to meet you finally.”&lt;/p&gt;
&lt;p&gt;Harrison was a little taken aback. He pulled out the chair and sat opposite this strange character.&lt;/p&gt;
&lt;p&gt;“You too. This place is–”&lt;/p&gt;
&lt;p&gt;“Different to what you’re use to?” Jacob finished.&lt;/p&gt;
&lt;p&gt;“Yeah, it’s like; everyone knows me, but I have no idea who they are” Harrison explained. It really was very disconcerting.&lt;/p&gt;
&lt;p&gt;Jacob smiled knowingly. He pushed back his styled blonde hair and looked at Harrison with an intense, green-eyed gaze. It seemed to pierce Harrison, almost like he was being searched.&lt;/p&gt;
&lt;p&gt;“You’ll get used to it,” he explained, “There are many things you’ll get used to. The Link will show you.”&lt;/p&gt;
&lt;p&gt;“Wait, did Jacob know something about my application?” Harrison wondered. The waiter stepped in to fill Harrison’s glass with water.&lt;/p&gt;
&lt;p&gt;“So, tell me why we’re here,” Jacob asked, “Your Telegram comments are always amusing. I’m glad we finally made it in person.”&lt;/p&gt;
&lt;p&gt;Harrison paused, Jacob’s energy was almost overwhelming. And those eyes…&lt;/p&gt;
&lt;p&gt;“Me too. And, well, you mentioned you were linked on the group. I’ve been trying to understand what it’s going to be like. What it’s &lt;em&gt;really&lt;/em&gt; like, from someone who gets things, you know?” Harrison explained.&lt;/p&gt;
&lt;p&gt;Jacob nodded patiently, “I sense your frustrations. I was the same way when I was on the wait-list. Well, how much do you know?” Jacob’s eyes sparkled with the inquiry.&lt;/p&gt;
&lt;p&gt;“Not much, I guess. Just what’s in the news, Reddit, movies, you know. A guy at work is taking over everything.” Harrison tried to hide his disappointment, but Jacob saw through him. He frowned.&lt;/p&gt;
&lt;p&gt;“Yeah, that happens.” Jacob looked out over the courtyard, furrowing his brow. He paused for a good minute, and Harrison began to fidget, unwilling to disturb this pensive man.&lt;/p&gt;
&lt;h2&gt;A Magnifying Glass&lt;/h2&gt;
&lt;p&gt;“What is it you think the Neuralink is, Harrison? What do you think it does?” Jacob broke the silence returning his gaze to the conversation.&lt;/p&gt;
&lt;p&gt;“It connects us. Enables us to engage with technology at a level we’ve never had before,” Harrison attempted, “It makes us smarter, right? The bandwidth problem.”&lt;/p&gt;
&lt;p&gt;“Yes, and also no” Jacob mysteriously replied, “Think of the Neuralink like all technology that has come before us. It’s a magnifying glass.&lt;/p&gt;
&lt;p&gt;“What did electricity promise us? Planes? Phones? The Internet? They all heralded quantum shifts in how we approached the fundamentals of daily life. The internet gives us the ability, for example, to search for anything, anywhere, anytime—the entire catalog of recorded history and information at our fingertips. And yet, what do most people use it for? Looking at cat videos and pictures of naked women.&lt;/p&gt;
&lt;p&gt;“All the internet did was exaggerate behaviors that were already present—a giant magnifying glass over human values. The Neuralink is no different. It doesn’t solve the world’s problems, as much as it enables us to me more… us. And that’s not always a good thing.”&lt;/p&gt;
&lt;p&gt;Jacob’s words crashed over Harrison like waves. The waiter returned with two plates, placing them down in front of the pair. Harrison didn’t remember ordering, but he was so caught up in Jacob’s ideas he barely noticed.&lt;/p&gt;
&lt;p&gt;“So it accentuates our pre-existing selves?”&lt;/p&gt;
&lt;p&gt;“Exactly. Well, for most of us. It changes some and opens up doors. There are those who understand the technology at a deeper level. Those who push it… The Legion” Jacob’s voice quietened, and he looked up from his salad.&lt;/p&gt;
&lt;p&gt;“Legion? I thought that was just an internet myth?” Harrison laughed nervously. Was he serious?&lt;/p&gt;
&lt;p&gt;“You’re a programmer, right?” Jacob quizzed, “Then, think about developers for a second. They command our world because technology commands our world. The technology that is so useful that you can’t live without it. It’s become ubiquitous. Therefore, developers – or those who own them – have the power because they control the world’s most useful thing.&lt;/p&gt;
&lt;p&gt;“Legion is the same thing, but for the intersection of humans and AI. We command it because, like developers, we create it and understand it more than anyone else. Legion is open to anyone who can command themselves and technology in a way that contributes to the whole. These are the people we’re interested in.”&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Harrison hadn’t touched his lunch – this was too much. Was this a test?&lt;/p&gt;
&lt;p&gt;“So what, you’re part of an elite group of programmers that have Neuralink’s that control AI?” Harrison retorted.&lt;/p&gt;
&lt;p&gt;“Not just programmers. And we’re not ‘the elite’. We are doctors, lawyers, politicians, teachers, cleaners, and taxi drivers. We are Legion. And we also don’t control the ‘AI’.” He paused dramatically.&lt;/p&gt;
&lt;p&gt;“I don’t understand. What’s the purpose of a ‘Legion’?”&lt;/p&gt;
&lt;p&gt;“Most humans view themselves as distinct, as separate from each other and the world—independent controllers of their fate and actions. In reality, this is ludicrous, but our egoic fascination is a powerful lure. Our ego wants to identify with form. We forget that we belong to a larger eco-system and race, and we are more intrinsically interconnected than we give ourselves credit for. The internet has only increased this and the Neuralink even more so.&lt;/p&gt;
&lt;p&gt;Listen, let’s take a blood cell from your body. This cell doesn’t claim independence from its siblings, engaging in self-serving behavior to benefit only its ‘Self’. No, it operates in harmony and accordance with the body’s needs, doing what it can to provide. We have forgotten this as humans.&lt;/p&gt;
&lt;p&gt;The Link removes the barrier of communication, ego, and privacy. Should you be open to it, the flood gates are flung wide open, and the union of you and everyone is met. It’s truly beautiful. You mentioned you’re a fan of mushrooms, right?”&lt;/p&gt;
&lt;p&gt;“Then what about the AI?” Harrison was on the edge of his seat, this morning’s slack messages a distant memory.&lt;/p&gt;
&lt;p&gt;“Right. Well, that’s a little more tricky to explain. Look, humans have a way to go in terms of what we were saying earlier. Until you can act as a unified collective, you’re in trouble. The digital space opens possibilities for virtualization and symbiosis with something we’re all feeding. We become one in a sense.” Jacob’s smooth voice was no more than a whisper.&lt;/p&gt;
&lt;p&gt;“You say, ‘humans’ like you’re not one of us.” It was unsettling for Harrison. Jacob chuckled.&lt;/p&gt;
&lt;p&gt;“Ha! I guess I did. Funny!”, Jacob’s eyes sparkled, but Harrison did not find anything funny. “Harrison, if we are to conquer space, time, and the great mysteries this universe presents, is it possible we may need a new form?”&lt;/p&gt;
&lt;p&gt;The question hung in the air, resonating like a struck gong.&lt;/p&gt;
&lt;p&gt;“That’s enough for today; I think” Jacob wiped his mouth with his napkin and folded it neatly on the table. “Let’s bounce!”&lt;/p&gt;
&lt;p&gt;The waiter collected Harrison’s untouched salad, and the two walked back onto the upmarket street.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;“Wait, don’t we have to pay?” Harrison started.&lt;/p&gt;
&lt;p&gt;“Don’t worry, I’ve already got us” Jacob exclaimed, tapping his head with a grin, “You’ll get used to it soon enough. But, before I go, are there any other questions you have?”&lt;/p&gt;
&lt;p&gt;Harrison’s mind exploded in a million directions, his thoughts of technical-symbiosis, ethics, and wonder scattering like a firework.&lt;/p&gt;
&lt;p&gt;“Would you call yourself human?” Harrison blurted. The words felt clumsy, but the curiosity was too much to bear.&lt;/p&gt;
&lt;p&gt;“What is human anyway, Harrison?” Jacob flashed a wicked smile and disappeared into a Fetch that had suddenly whipped around the corner. He was gone.&lt;/p&gt;
&lt;p&gt;Harrison stood on the steps of their perplexing interaction, consumed by a cocktail of confusion, fear, and excitement. He remembered Alice.&lt;/p&gt;
&lt;h3&gt;Emergence&lt;/h3&gt;
&lt;p&gt;The walk home felt longer than any he had taken. Harrison’s phone incessantly buzzed with immediate responsibilities, updates, and tasks – but Harrison was oblivious. Jacob had opened the door to a new world, and Harrison was standing on the precipice.&lt;/p&gt;
&lt;p&gt;He knew the world was changing, but Jacob’s illustration presented something else entirely. A new species. A blend of network, consciousness, flesh, and steel. Was this even possible?&lt;/p&gt;
&lt;p&gt;“Perhaps I put too much in my tea this morning” Harrison deliberated.&lt;/p&gt;
&lt;p&gt;He returned to his small apartment, high above the world. The afternoon’s blend of techno-infused spirituality had rendered Harrison restless and anxious.&lt;/p&gt;
&lt;p&gt;Harrison sat down at his desk and forced an attempt at his nightly ritual of coding practice. The algorithmic puzzle glared smugly at him from the code window. The answer was right before him, and faded just out of reach anytime he came to close. Leetcode’s complexity drove his thoughts way, and they wandered back to Jacob.&lt;/p&gt;
&lt;p&gt;“Who is Jacob anyway?” Harrison meditated, “I know so little about him.” He made a promise to himself to never go to lunch with Connies he’d met online again. It only seemed to complicate an already chaotic situation.&lt;/p&gt;
&lt;p&gt;He opened a new tab and searched for “Legion”. A disappointing array of links splashed on the page. A collection of demons from the New Testament, an old TV series, details on a faction of the Roman Empire’s army. Nothing about Neuralink. Nothing about AI. The DarkWeb shed no answers either.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Who were they? Was it all a joke?&lt;/p&gt;
&lt;p&gt;Harrison sighed. Today had been a long one. He looked up at Alice, swimming in her impervious bubble of glass and water. He recalled the main character of a YouTube show once lamenting to his wife, “I wish I were a farmer. I wish I had grown up in a simple life, with simple ambitions, and simple desires. Take away the complexities of this modern life, and hand me a plow. I’d be happier for it”. Indeed, ignorance appeared to be a blissful blessing.&lt;/p&gt;
&lt;p&gt;The day’s troubles swirled around the cauldron of Harrison’s brain. He undressed, brushed his teeth, and stared out the window. His reflection gazed back at him, and Jacob’s final question echoing like a lonely, repetitive drum.&lt;/p&gt;
&lt;p&gt;What is human?&lt;/p&gt;
&lt;p&gt;Crawling into bed, Harrison stole one last glance into his technical world before retreating to his unconscious. There were only two notifications, both emails.&lt;/p&gt;
&lt;div&gt;
  &lt;strong&gt;11:50 pm – From Neuralink&lt;/strong&gt;
  &lt;br /&gt;
  &lt;span&gt;Your wait is over! Next week’s operation&lt;/span&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;strong&gt;11:59 pm – From Anonymous&lt;/strong&gt;
  &lt;br /&gt;
  &lt;span&gt;Welcome to Legion&lt;/span&gt;
&lt;/div&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 27 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/our-new-species-pt-2/</guid></item><item><title>Rick and Morty: Season 4</title><link>https://olshansky.info/tv/rick_and_morty_season_4/</link><description>Olshansky's review of Rick and Morty: Season 4</description><author>🦉 olshansky 🦁</author><pubDate>Sat, 26 Sep 2020 22:14:06 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/tv/rick_and_morty_season_4/</guid></item><item><title>Some evergreen insights from a survey on makers in Italy</title><link>https://stop.zona-m.net/2020/09/some-evergreen-insights-from-a-survey-on-makers-in-italy/</link><description>&lt;p&gt;Spoiler: they are not about technology.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 26 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/some-evergreen-insights-from-a-survey-on-makers-in-italy/</guid></item><item><title>Fixing Hugo Social Media Icons in Blackburn</title><link>https://blog.herlein.com/post/hugo-social-media-icons/</link><description>&lt;p&gt;The Blackburn theme for Hugo has a bug in how it shows social media icons.  Here&amp;rsquo;s how to fix it.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 26 Sep 2020 11:00:04 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/hugo-social-media-icons/</guid></item><item><title>Hello Ubuntu - Kinda</title><link>https://blog.herlein.com/post/hello-ubuntu-kinda/</link><description>&lt;p&gt;Debian not good for me on the desktop - back to Ubuntu, lost the snaps.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 26 Sep 2020 11:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/hello-ubuntu-kinda/</guid></item><item><title>Raspberry Pi Zero W Fun</title><link>https://blog.herlein.com/post/rpi-zero-w/</link><description>&lt;p&gt;The Raspberry Pi Zero W is likely the basis of my next few projects.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 26 Sep 2020 11:00:01 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/rpi-zero-w/</guid></item><item><title>Creating Notes Site</title><link>https://prashamhtrivedi.in/creating_notes_site.html</link><description>In this article, we will see how I built my notes site using a simple node script and deployed using Github actions.</description><author>Prasham H Trivedi</author><pubDate>Sat, 26 Sep 2020 09:17:53 GMT</pubDate><guid isPermaLink="true">https://prashamhtrivedi.in/creating_notes_site.html</guid></item><item><title>Industrial Strength Arch Linux</title><link>https://blog.tjll.net/industrial-strength-arch-linux/</link><description>&lt;p&gt;
These days, I &lt;i&gt;almost&lt;/i&gt; exclusively run Arch Linux in my homelab and personal machines.
Had I the brain cells to spare, I&amp;rsquo;d try and get NixOS running on ARMv7, but in the meantime, a mix of vanilla &lt;code&gt;x86_64&lt;/code&gt; Arch and Arch Linux ARM is my chosen flavor just to keep things consistent.
I&amp;rsquo;ve run Arch as my primary server OS for almost a decade now, and although I&amp;rsquo;m sure some will balk at the idea, I&amp;rsquo;ve found that the distribution has performed wonderfully for me, even in contrast to traditional &amp;ldquo;server&amp;rdquo; distributions like CentOS.
It sounds counterinuitive, but the simple model of Arch Linux has, overall, helped mitigate some maintenance burdens.
&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;
Here&amp;rsquo;s some of best practices I&amp;rsquo;ve accumulated over the years of personally administering ~20 Arch Linux machines in my homelab.
&lt;/p&gt;
&lt;div class="outline-4" id="outline-container-prelude-why-arch"&gt;
&lt;h4 id="prelude-why-arch"&gt;Prelude: Why Arch?&lt;/h4&gt;
&lt;div class="outline-text-4" id="text-org23d4264"&gt;
&lt;p&gt;
I don&amp;rsquo;t want to get into a distribution holy war here; there&amp;rsquo;s endless forums for that debate.
However, I &lt;i&gt;will&lt;/i&gt; get into the reasons why I now default to Arch Linux when provisioning hosts, as many of those reasons naturally flow into why I include certain best practices.
&lt;/p&gt;

&lt;ul class="org-ul"&gt;
&lt;li&gt;A &amp;ldquo;rolling release&amp;rdquo; distribution is a nice methodology for server maintenance.
&lt;a href="https://rootco.de/2020-02-10-regular-releases-are-wrong/"&gt;See this other blog post enumerating why rolling releases make sense within the context of openSUSE&lt;/a&gt;.
Want a &amp;ldquo;version&amp;rdquo;? Use the &lt;a href="https://wiki.archlinux.org/index.php/Arch_Linux_Archive"&gt;Arch Linux Archive&lt;/a&gt; to pinpoint a moment in time.
(I still begrudge that CentOS 6&amp;rsquo;s upgrade path to 7 discourages in-place upgrades)&lt;/li&gt;
&lt;li&gt;In contrast to &amp;ldquo;kitchen sink&amp;rdquo; distributions, when I &lt;i&gt;do&lt;/i&gt; need to bolt on additions to my install, I know exactly how I&amp;rsquo;ve done it, so fixing problems and building systems isn&amp;rsquo;t a game of guesswork about how the distribution chose to configure those services.
I&amp;rsquo;m the one that did it, so I can better maintain it.&lt;/li&gt;
&lt;li&gt;The catalog of packages, when you factor in the AUR, is almost complete for most people.
When I can&amp;rsquo;t find an Arch package, which is very seldom these days, I package it on the AUR and move on - &lt;code class="src src-sh"&gt;PKGBUILD&lt;/code&gt;s aren&amp;rsquo;t terribly difficult to write.&lt;/li&gt;
&lt;li&gt;The aforementioned simplicity of Arch systems is also reflected in the Arch-specific software projects like &lt;code&gt;pacman&lt;/code&gt;.
Setting up a private pacman repo within my LAN was so easy I thought I was doing something wrong.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="outline-4" id="outline-container-pacman-hygiene"&gt;
&lt;h4 id="pacman-hygiene"&gt;Pacman Hygiene&lt;/h4&gt;
&lt;div class="outline-text-4" id="text-org2d57bdc"&gt;
&lt;p&gt;
One of the trickiest aspects of Linux distribution maintenance that I didn&amp;rsquo;t understand was keeping configuration files up to date.
By that I mean catching and updating files somewhere like &lt;code&gt;/etc/&lt;/code&gt; so that when package &lt;code&gt;foobar&lt;/code&gt; upgrades from 1.0 to 2.0 and the default configuration file &lt;code&gt;/etc/foobar.conf&lt;/code&gt; adds the setting &lt;code&gt;telemetry = true&lt;/code&gt;, you can merge in the new configuration files and optionally set them to desired values.
&lt;/p&gt;

&lt;p&gt;
&lt;a href="https://wiki.archlinux.org/index.php/Pacman/Pacnew_and_Pacsave"&gt;The Arch Wiki has a good page about this&lt;/a&gt; but the most important thing to remember is that, in the vast majority of cases, an interactive process (via a human at a terminal) is needed to judge which parts of your existing configuration file needs to be edited.
I suggest using &lt;a href="http://kmkeen.com/pacmatic/"&gt;pacmatic&lt;/a&gt; for this.
The pacmatic web site outlines how to use the utility, but in short: &lt;code&gt;pacmatic&lt;/code&gt; will a) alert you to any announcements from the Arch Linux project in case there&amp;rsquo;s news about needed intervention in the course of normal system operations and b) automatically prompt and help update configuration files.
I like this method because it&amp;rsquo;s closely linked to &lt;code&gt;pacman&lt;/code&gt; operations so you can&amp;rsquo;t forget to update these files and the &lt;code&gt;pacmatic&lt;/code&gt; command is a drop-in replacement for &lt;code&gt;pacman&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;code&gt;pacmatic&lt;/code&gt; is starting to age a little, but you can still get the same effect by using the &lt;code&gt;pacdiff&lt;/code&gt; command from the &lt;code&gt;pacman-contrib&lt;/code&gt; package.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="outline-4" id="outline-container-aur-automation"&gt;
&lt;h4 id="aur-automation"&gt;AUR Automation&lt;/h4&gt;
&lt;div class="outline-text-4" id="text-orgef16b41"&gt;
&lt;p&gt;
Using Arch for non-trivial use-cases is almost certainly going to lead you towards relying on some &lt;a href="https://aur.archlinux.org/"&gt;AUR&lt;/a&gt; packages.
&lt;/p&gt;

&lt;p&gt;
Unlike official packages that are curated by Arch Linux Trusted Users, the AUR has less control surrounding submission of packages.
Validating the legitimacy of a &lt;code&gt;PKGBUILD&lt;/code&gt; is &lt;i&gt;always&lt;/i&gt; a good idea, and for first-time users, building and installing an AUR package is typically comprised of a) downloading the package snapshot, checking out the &lt;code&gt;PKGBUILD&lt;/code&gt;, and building it with &lt;code&gt;makepkg&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
That&amp;rsquo;s all well and good, but if you use a non-trivial number of AUR packages, this process is &lt;i&gt;way&lt;/i&gt; too manual.
You really want some automation in place around this, but I&amp;rsquo;m not talking about a tool like &lt;code&gt;yay&lt;/code&gt; that automates the fetching and building for a package&amp;rsquo;s source.
You need a tool that handles all update steps as part of a schedule so that installing updated AUR packages is inlined as part of the normal &lt;code&gt;-Syu&lt;/code&gt; process.
&lt;/p&gt;

&lt;p&gt;
In my opinion, the most reliable option here is &lt;a href="https://github.com/alexheretic/aurto"&gt;aurto&lt;/a&gt; (which, in turn, uses &lt;a href="https://github.com/AladW/aurutils"&gt;aurutils&lt;/a&gt; under the hood).
Why should you use something like &lt;code&gt;aurto&lt;/code&gt;?
&lt;/p&gt;

&lt;ul class="org-ul"&gt;
&lt;li&gt;Scheduled updates. &lt;code&gt;aurto&lt;/code&gt; comes bundled with systemd timers to check for package updates, so you don&amp;rsquo;t burn time checking for updates and building packages manually.&lt;/li&gt;
&lt;li&gt;Custom repositories. Following the Arch paradigm of building and indexing packages into proper repositories means that you don&amp;rsquo;t think about pulling in updates, they just happen for you. You can also easily share built packages across a network (which I rely on heavily).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aurutils&lt;/code&gt; follows lots of good operational hygiene (for example, building in clean chroots and explicitly trusting maintainers as a build step).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Remember that, like any sort of AUR automation, you&amp;rsquo;re trusting the maintainer of the packages you track to not bundle malicious code, but that&amp;rsquo;s a risk you take with any sort of interaction with the AUR.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="outline-4" id="outline-container-snapshotting"&gt;
&lt;h4 id="snapshotting"&gt;Snapshotting&lt;/h4&gt;
&lt;div class="outline-text-4" id="text-orgd7bb1f7"&gt;
&lt;p&gt;
If you&amp;rsquo;re using Linux in 2020, there&amp;rsquo;s no reason why you can&amp;rsquo;t be using a modern, advanced, copy-on-write filesystem.
Are you comfortable relying on &lt;a href="https://en.wikipedia.org/wiki/Dynamic_Kernel_Module_Support"&gt;dkms&lt;/a&gt;?
Then use &lt;a href="https://en.wikipedia.org/wiki/OpenZFS#Distributions"&gt;ZFS on Linux&lt;/a&gt;.
Honestly, it&amp;rsquo;s fantastic, and you get copy-on-write, snapshots, compression, and more.
It&amp;rsquo;s the current best-of-breed filesystem for Linux, in my opinion.
If you want, &lt;a href="https://wiki.archlinux.org/index.php/Btrfs"&gt;btrfs&lt;/a&gt; can fit a similar role, but I trust ZFS more.
&lt;/p&gt;

&lt;p&gt;
Providing a point-in-time backup before system upgrades becomes &lt;i&gt;extremely&lt;/i&gt; easy on these filesystems.
Run a snapshot as a pacman hook before you make changes, and you can rollback to a known good state easily.
There are some ready-made packages out there that stitch together ZFS/btrfs with pacman hooks so you don&amp;rsquo;t even need to write the automation yourself.
&lt;/p&gt;

&lt;p&gt;
If you&amp;rsquo;re already snapshotting a filesystem, cheap (as in effort) backups are just a small extra step if you want to replicate the snapshot images somewhere else.
My ZFS and btrfs filesystems get duplicated offsite over simple &lt;code&gt;ssh&lt;/code&gt; commands as added disaster recovery insurance, which means that not only do you have system backups saved outside your network, but your whole history of backups if you need to restore from a point in time.
There are actually a wide variety of projects that do this, but personally, I use &lt;a href="https://github.com/khenderick/zfs-snap-manager"&gt;zfs-snap-manager&lt;/a&gt; for my zpools and &lt;a href="https://github.com/csirac2/snazzer"&gt;snazzer&lt;/a&gt; for my btrfs volumes.
Both automate retention and incremental backups, which are the tricky parts.
&lt;/p&gt;

&lt;p class="info"&gt;
&lt;b&gt;Note&lt;/b&gt;: Some of these suggestions eat up disk space.
I&amp;rsquo;d definitely suggest using filesystem compression to help with that.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="outline-4" id="outline-container-grab-bag"&gt;
&lt;h4 id="grab-bag"&gt;Grab Bag&lt;/h4&gt;
&lt;div class="outline-text-4" id="text-orgee564ad"&gt;
&lt;p&gt;
The preceding three points have had the greatest impact on my Arch Linux system maintainability, but there are a few minor mentions just for sake of completeness:
&lt;/p&gt;

&lt;ul class="org-ul"&gt;
&lt;li&gt;Remember to run &lt;code&gt;pacman -Sc&lt;/code&gt; every once in a while.
Those old packages take up space.&lt;/li&gt;
&lt;li&gt;A periodic &lt;a href="https://wiki.archlinux.org/index.php/Reflector"&gt;reflector&lt;/a&gt; script can be handy in keeping your mirrorlist healthy.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;
Using &lt;code&gt;aurto&lt;/code&gt; and &lt;code&gt;aurutils&lt;/code&gt; to host a repository of local AUR packages? Share it on your network easily:
&lt;/p&gt;
&lt;span class="org-src-tab"&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/span&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="src src-shell"&gt;&lt;code&gt;&lt;code&gt;sudo pacmatic -S darkhttpd&lt;/code&gt;
&lt;code&gt;sudo systemctl edit darkhttpd&lt;/code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;span class="org-src-tab"&gt;&lt;span&gt;Systemd&lt;/span&gt;&lt;/span&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="src src-systemd"&gt;&lt;code&gt;&lt;code&gt;&lt;span class="org-type"&gt;[Service]&lt;/span&gt;&lt;/code&gt;
&lt;code&gt;&lt;span class="org-keyword"&gt;ExecStart&lt;/span&gt;=&lt;/code&gt;
&lt;code&gt;&lt;span class="org-keyword"&gt;ExecStart&lt;/span&gt;=/usr/bin/darkhttpd /var/cache/pacman --ipv6 --uid http --gid http --chroot --mimetypes /etc/conf.d/mimetypes&lt;/code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;span class="org-src-tab"&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/span&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="src src-shell"&gt;&lt;code&gt;&lt;code&gt;sudo systemctl enable --now darkhttpd&lt;/code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Then just add the following section to your other machines&amp;rsquo; &lt;code&gt;pacman.conf&lt;/code&gt;:
&lt;/p&gt;
&lt;span class="org-src-tab"&gt;&lt;span&gt;Conf[Unix]&lt;/span&gt;&lt;/span&gt;&lt;div class="org-src-legend"&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="org-variable-name"&gt;Font used to highlight variable names.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="org-type"&gt;Font used to highlight type and class names.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="org-src-container"&gt;
&lt;pre class="src src-conf"&gt;&lt;code&gt;&lt;code&gt;[&lt;span class="org-type"&gt;aurto&lt;/span&gt;]&lt;/code&gt;
&lt;code&gt;&lt;span class="org-variable-name"&gt;Server&lt;/span&gt; = http://&amp;lt;hostname&amp;gt;/aurto&lt;/code&gt;
&lt;code&gt;&lt;span class="org-variable-name"&gt;SigLevel&lt;/span&gt; = Optional&lt;/code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
&lt;b&gt;Edits&lt;/b&gt;: rhysperry​111 &lt;a href="https://forum.tjll.net/t/tyblog-industrial-strength-arch-linux/235/4"&gt;caught&lt;/a&gt; a &lt;code&gt;systemctl&lt;/code&gt; typo, and AladW &lt;a href="https://www.reddit.com/r/archlinux/comments/j4hqj2/industrial_strength_arch_linux/g7j7im6/"&gt;noted I conflated&lt;/a&gt; &lt;code&gt;aurto&lt;/code&gt; and &lt;code&gt;aurutils&lt;/code&gt; in a few places.
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description><author>Tyblog</author><pubDate>Sat, 26 Sep 2020 09:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.tjll.net/industrial-strength-arch-linux/</guid></item><item><title>Physics textbooks for self-study</title><link>https://diffxweyl.wordpress.com/2020/09/25/physics-textbooks-for-self-study/</link><description>Here are some physics textbooks that I&amp;#8217;ve read over the years. Each textbook is rated from 1-5 Diracs () on quality for self-study. Most topics are divided into (basic) and (advanced). Tips for self-study: Shorter is better when it comes to textbooks. The problem with self-study is missing the forest for the trees. Most textbooks &amp;#8230; &lt;a class="more-link" href="https://diffxweyl.wordpress.com/2020/09/25/physics-textbooks-for-self-study/"&gt;Continue reading&lt;span class="screen-reader-text"&gt; "Physics textbooks for&amp;#160;self-study"&lt;/span&gt;&lt;/a&gt;</description><author>diff × weyl</author><pubDate>Sat, 26 Sep 2020 07:16:59 GMT</pubDate><guid isPermaLink="true">https://diffxweyl.wordpress.com/2020/09/25/physics-textbooks-for-self-study/</guid></item><item><title>Multi-repos KISS</title><link>https://pricey.uk/blog/project-and-repos/</link><description>&lt;p&gt;I have never worked in a monorepo professionally.&lt;/p&gt;</description><author>Joseph Price</author><pubDate>Sat, 26 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://pricey.uk/blog/project-and-repos/</guid></item><item><title>Europe and Western Civilization in the Modern Age</title><link>https://olshansky.info/book/europe_and_western_civilization_in_the_modern_age/</link><description>Olshansky's review of Europe and Western Civilization in the Modern Age by Thomas Childers</description><author>🦉 olshansky 🦁</author><pubDate>Sat, 26 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/europe_and_western_civilization_in_the_modern_age/</guid></item><item><title>Making this blog bilingual…?</title><link>https://shadow.sombragris.org/?p=1087</link><description>As you might know, I&amp;#8217;m a native Spanish speaker, and this is an English-language blog. It has served me well for over 15 years and counting, and still does. However, most of my writing have been done lately in Spanish. Not because of anything special; they were just extended status updates in Facebook. But somehow...</description><author>The Grey Shadow</author><pubDate>Fri, 25 Sep 2020 22:35:04 GMT</pubDate><guid isPermaLink="true">https://shadow.sombragris.org/?p=1087</guid></item><item><title>Against possessionsless utopias</title><link>https://stop.zona-m.net/2020/09/against-possessionsless-utopias/</link><description>&lt;p&gt;How can you distinguish utopias from dystopias?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 25 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/against-possessionsless-utopias/</guid></item><item><title>LinkedBlockingDeque 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/09/25/LinkedBlockingDeque.html</link><description>&lt;h1 id="linkedblockingdeque"&gt;LinkedBlockingDeque&lt;/h1&gt;
&lt;p&gt;LinkedBlockingDeque 是基于&lt;strong&gt;链表&lt;/strong&gt;的&lt;strong&gt;双端阻塞队列&lt;/strong&gt;，&lt;strong&gt;线程安全&lt;/strong&gt;，元素不允许为 null。&lt;/p&gt;

&lt;p&gt;空间容量最大一般为&lt;code class="language-plaintext highlighter-rouge"&gt;Integer.MAX_VALUE&lt;/code&gt;，如果构造器中指定了最大值则队列长度将会被限制在该值以下。&lt;/p&gt;

&lt;p&gt;大部分方法都以固定时间运行，批量操作，例如：&lt;code class="language-plaintext highlighter-rouge"&gt;remove&lt;/code&gt;， &lt;code class="language-plaintext highlighter-rouge"&gt;removeFirstOccurrence&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;removeLastOccurrence&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;contains&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;iterator.remove()&lt;/code&gt;，将以线性时间运行。&lt;/p&gt;

&lt;p&gt;LinkedBlockingDeque 是&lt;strong&gt;阻塞队列&lt;/strong&gt;，是指对于一些指定的操作，在插入或者获取队列元素时如果队列状态不允许该操作可能会阻塞住该线程直到队列状态变更为允许操作，这里的阻塞一般有两种情况。
&lt;!--more--&gt;
第一种是插入元素时，如果当前队列已满将会进入阻塞状态，一直等到队列有空的位置时再讲该元素插入，该操作可以通过设置超时参数，超时后返回 false 表示操作失败，也可以不设置超时参数一直阻塞，中断后抛出&lt;code class="language-plaintext highlighter-rouge"&gt;InterruptedException&lt;/code&gt;异常。&lt;/p&gt;

&lt;p&gt;第二种是读取元素时如果当前队列为空会阻塞住直到队列不为空然后返回元素，同样可以通过设置超时参数。&lt;/p&gt;

&lt;p&gt;一般多用于&lt;strong&gt;生产者消费者模式&lt;/strong&gt;。&lt;/p&gt;

&lt;h1 id="方法"&gt;方法&lt;/h1&gt;
&lt;p&gt;LinkedBlockingDeque 实现了 BlockingDeque 接口，除了原本双端队列中的方法外还另外提供了一些&lt;strong&gt;阻塞操作&lt;/strong&gt;的方法。每种操作分为阻塞与超时两种，阻塞方法调用将会一直阻塞知道队列可用，中间如果中断则抛出&lt;code class="language-plaintext highlighter-rouge"&gt;InterruptedException&lt;/code&gt;异常。超时方法同样也会阻塞，允许设置超时时间，超时后返回 false 表示操作失败。&lt;/p&gt;

&lt;p&gt;下面我们先看下这几个方法。&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;操作：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;类型&lt;/th&gt;
      &lt;th&gt;阻塞&lt;/th&gt;
      &lt;th&gt;超时&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;插入&lt;/td&gt;
      &lt;td&gt;putFirst(e)&lt;/td&gt;
      &lt;td&gt;offerFirst(e, time, unit)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;移除&lt;/td&gt;
      &lt;td&gt;takeFirst()&lt;/td&gt;
      &lt;td&gt;pollFirst(time, unit)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;操作：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;类型&lt;/th&gt;
      &lt;th&gt;阻塞&lt;/th&gt;
      &lt;th&gt;超时&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;插入&lt;/td&gt;
      &lt;td&gt;putLast(e)&lt;/td&gt;
      &lt;td&gt;offerLast(e, time, unit)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;移除&lt;/td&gt;
      &lt;td&gt;takeLast()&lt;/td&gt;
      &lt;td&gt;pollLast(time, unit)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id="源码"&gt;源码&lt;/h1&gt;
&lt;p&gt;我们先看看类中定义的几个重要的属性：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;//当前链表长度&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;//链表最大长度&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ReentrantLock&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReentrantLock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Condition&lt;/span&gt; &lt;span class="n"&gt;notEmpty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCondition&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Condition&lt;/span&gt; &lt;span class="n"&gt;notFull&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCondition&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;capacity&lt;/code&gt;表示链表的最大长度，默认是&lt;code class="language-plaintext highlighter-rouge"&gt;Integer.MAX_VALUE&lt;/code&gt;，可以在构造器中指定。&lt;/p&gt;

&lt;p&gt;下面的&lt;code class="language-plaintext highlighter-rouge"&gt;lock&lt;/code&gt;是可重入锁，用于在读取或修改链表时使用，保证线程安全。&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;notEmpty&lt;/code&gt;表示不为空时的&lt;code class="language-plaintext highlighter-rouge"&gt;Condition&lt;/code&gt;，当不为空时会调用&lt;code class="language-plaintext highlighter-rouge"&gt;notEmpty.signal()&lt;/code&gt;通知被&lt;code class="language-plaintext highlighter-rouge"&gt;notEmpty&lt;/code&gt;阻塞的线程。&lt;code class="language-plaintext highlighter-rouge"&gt;notFull&lt;/code&gt;是未满状态的&lt;code class="language-plaintext highlighter-rouge"&gt;Condition&lt;/code&gt;，用法同上。&lt;/p&gt;

&lt;p&gt;类中的方法可分为三类，第一类是只保证线程安全，但不会阻塞住的方法，第二是会阻塞方法，第三是超时方法。下面我们通过几个典型的方法看看是如何实现的。&lt;/p&gt;

&lt;p&gt;通过阅读源码发现，不管是上面三种的哪一种，最终都会调用同一个方法先对节点进行操作，只不过每个方法内部有不同的处理，以读取&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点为例，主要有三个典型的方法：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;pollFirst()&lt;/code&gt;：保证线程安全，但不会阻塞&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;takeFirst()&lt;/code&gt;：阻塞方法&lt;/li&gt;
  &lt;li&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;pollFirst(timeout, unit)&lt;/code&gt;：超时方法&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上面是三个最终都先调用了&lt;code class="language-plaintext highlighter-rouge"&gt;unlinkFirst()&lt;/code&gt;移除&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点，那么我们先看看这个。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;unlinkFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// assert lock.isHeldByCurrentThread();&lt;/span&gt;
    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// help GC&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;notFull&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面代码其实就是一个移除head节点的操作，重点是最后会调用&lt;code class="language-plaintext highlighter-rouge"&gt;notFull.signal()&lt;/code&gt;通知被&lt;code class="language-plaintext highlighter-rouge"&gt;notFull&lt;/code&gt;阻塞的线程，例如我们使用阻塞/超时方法添加元素时（例如&lt;code class="language-plaintext highlighter-rouge"&gt;putFirst&lt;/code&gt;）如果队列已满则会进入阻塞状态，当有其他线程调用了 remove 操作之后此时队列有了空缺的位置，就可以通知阻塞线程继续将元素添加进去。&lt;/p&gt;

&lt;h3 id="pollfirst"&gt;pollFirst&lt;/h3&gt;
&lt;p&gt;下面我们再看看&lt;code class="language-plaintext highlighter-rouge"&gt;pollFirst()&lt;/code&gt;是如何实现线程安全的：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;pollFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ReentrantLock&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;unlinkFirst&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unlock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这个方法其实很简单，先用&lt;code class="language-plaintext highlighter-rouge"&gt;ReentrantLock&lt;/code&gt;锁定之后对链表进行操作，操作完成后在解锁，然后返回数据，操作完成。&lt;/p&gt;

&lt;h3 id="takefirst"&gt;takeFirst&lt;/h3&gt;
&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;takeFirst()&lt;/code&gt;大概是阻塞队列中最常用的一个方法，用于移除并返回&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;元素，队列为空则阻塞调用线程直到可以返回数据。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;takeFirst&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ReentrantLock&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unlinkFirst&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;notEmpty&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;await&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unlock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里阻塞方式是通过自旋的方式持续从&lt;code class="language-plaintext highlighter-rouge"&gt;unlinkFirst&lt;/code&gt;获取&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点，空则调用&lt;code class="language-plaintext highlighter-rouge"&gt;notEmpty.await()&lt;/code&gt;阻塞，&lt;code class="language-plaintext highlighter-rouge"&gt;signal&lt;/code&gt;之后再重复这一步骤，直到获取到值为止。&lt;/p&gt;

&lt;p&gt;另外一点，该方法也会先调用&lt;code class="language-plaintext highlighter-rouge"&gt;lock.lock()&lt;/code&gt;获得锁，然后继续操作，这点我开始比较疑惑，因为该方法会阻塞住，如果获得了锁别的线程不就没法获得锁从而操作队列了吗，查找资料之后才发现，&lt;code class="language-plaintext highlighter-rouge"&gt;notEmpty.await()&lt;/code&gt;方法出于线程调度目的，&lt;strong&gt;该锁会被原子释放&lt;/strong&gt;，线程进入阻塞状态，因此其他线程可以正常获得锁并继续操作。&lt;/p&gt;

&lt;h3 id="pollfirsttimeout-unit"&gt;pollFirst(timeout, unit)&lt;/h3&gt;
&lt;p&gt;与&lt;code class="language-plaintext highlighter-rouge"&gt;takeFirst&lt;/code&gt;不用的是，&lt;code class="language-plaintext highlighter-rouge"&gt;pollFirst&lt;/code&gt;可以设置一个超时时间，当阻塞时间超过该时间之后将会从阻塞状态中恢复并返回 null。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;pollFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;nanos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toNanos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ReentrantLock&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lockInterruptibly&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unlinkFirst&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nanos&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;nanos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notEmpty&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;awaitNanos&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nanos&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unlock&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;跟&lt;code class="language-plaintext highlighter-rouge"&gt;takeFirst()&lt;/code&gt;基本类似，不过调用的是&lt;code class="language-plaintext highlighter-rouge"&gt;notEmpty.awaitNanos(nanos)&lt;/code&gt;方法设置超时时间，而且每次循环都会检测一遍是否超时，超时则直接返回 null 值。&lt;/p&gt;

&lt;p&gt;还有一个不同点，&lt;code class="language-plaintext highlighter-rouge"&gt;pollFirst&lt;/code&gt;获取锁的方式是调用&lt;code class="language-plaintext highlighter-rouge"&gt;lock.lockInterruptibly()&lt;/code&gt;方法，该方法与&lt;code class="language-plaintext highlighter-rouge"&gt;lock&lt;/code&gt;不同的是，它允许等待线程被中断，中断后直接抛出&lt;code class="language-plaintext highlighter-rouge"&gt;InterruptedException&lt;/code&gt;异常，而调用&lt;code class="language-plaintext highlighter-rouge"&gt;lock&lt;/code&gt;方法等待线程即使中断仍然会继续等待获取锁，只不过获取成功后会中断线程。&lt;/p&gt;</description><author>张可的博客</author><pubDate>Fri, 25 Sep 2020 18:16:27 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/09/25/LinkedBlockingDeque.html</guid></item><item><title>The Least Dangerous Game: How (And Why) To Hunt Miners In Eve Echoes</title><link>https://greaterdanorequalto.com/the-least-dangerous-game/</link><description>&lt;p&gt;Eve Echoes is the mobile version of the MMORPG Eve Online. &amp;#xa0;In it, you play as a Capsuleer, a cloned human that can pilot space ships all around a giant galaxy, mining, hunting pirates, or being a pirate yourself. &amp;#xa0;If you get blown up, you lose your ship,&lt;/p&gt;</description><author>Greater Dan Or Equal To</author><pubDate>Fri, 25 Sep 2020 06:24:34 GMT</pubDate><guid isPermaLink="true">https://greaterdanorequalto.com/the-least-dangerous-game/</guid></item><item><title>How to make a live wallpaper on Android</title><link>https://sal.dev/android/android-live-wallpaper/</link><description>&lt;p&gt;Let’s create a very very very basic live wallpaper on Android.&lt;/p&gt;

&lt;h1 id="background-on-backgrounds"&gt;Background on Backgrounds&lt;/h1&gt;
&lt;p&gt;Android has had live wallpapers since Android 2.1 (Eclair, API 7) which was released in January of 2010 &lt;sup id="fnref:which_api_version"&gt;&lt;a class="footnote" href="#fn:which_api_version" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;. If you were using Android back then, you might have remembered this gem of a wallpaper.&lt;sup id="fnref:nexus_revamped"&gt;&lt;a class="footnote" href="#fn:nexus_revamped" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;img alt="Gosh it was so darn cool." src="/assets/article_images/2020-09-25-android-live-wallpaper/Nexus One Revamped.jpg" /&gt;&lt;/p&gt;

&lt;h1 id="step-0---prep-an-android-project"&gt;Step 0 - Prep an Android project&lt;/h1&gt;
&lt;p&gt;Create an Android project using the creation wizard. I used all of &lt;a href="https://developer.android.com/studio"&gt;Android Studio&lt;/a&gt;’s default settings with Kotlin, and it went well. If you already have a project lying around, you could probably use that too.&lt;/p&gt;

&lt;p&gt;&lt;img alt="You know the drill" src="/assets/article_images/2020-09-25-android-live-wallpaper/Create Project Android Studio.jpg" /&gt;&lt;/p&gt;

&lt;h1 id="step-1---initialize-the-wallpaperservice"&gt;Step 1 - Initialize the WallpaperService&lt;/h1&gt;
&lt;p&gt;The main class that runs the live wallpaper is the &lt;a href="https://developer.android.com/reference/android/service/wallpaper/WallpaperService.Engine"&gt;WallpaperService.Engine&lt;/a&gt; which is an &lt;code class="language-plaintext highlighter-rouge"&gt;inner class&lt;/code&gt; of &lt;a href="https://developer.android.com/reference/android/service/wallpaper/WallpaperService"&gt;WallpaperService&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Start by making an implementation of &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService&lt;/code&gt; with an inner class  that implements &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService.Engine&lt;/code&gt;. We’ll come back to it later.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-kotlin"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWallpaperService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreateEngine&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;inner&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id="step-2---modify-your-various-xml-files"&gt;Step 2 - Modify your various XML files&lt;/h1&gt;
&lt;p&gt;For your app to provide the phone with your live wallpaper, you’ll need to make a resource for it and declare your &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService&lt;/code&gt; in your &lt;code class="language-plaintext highlighter-rouge"&gt;AndroidManifest.xml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Make an XML file in your resources folder &lt;code class="language-plaintext highlighter-rouge"&gt;main/res/xml/my_wallpaper.xml&lt;/code&gt;. It only really needs a &lt;code class="language-plaintext highlighter-rouge"&gt;&amp;lt;wallpaper /&amp;gt;&lt;/code&gt; tag, but this is where you can define a thumbnail, settings activity, &lt;a href="https://developer.android.com/reference/android/R.styleable#Wallpaper"&gt;and other neat things&lt;/a&gt;.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-xml"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;wallpaper&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Jump over to your &lt;code class="language-plaintext highlighter-rouge"&gt;AndroidManifest.xml&lt;/code&gt; file. You’ll need to let Android know that you’re using the live wallpaper API.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-xml"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;manifest&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!--  ... some stuff ...  --&amp;gt;&lt;/span&gt;
  
  &lt;span class="nt"&gt;&amp;lt;uses-feature&lt;/span&gt;
      &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.software.live_wallpaper"&lt;/span&gt;
      &lt;span class="na"&gt;android:required=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!--  ... other stuff  --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In that same Android Manifest, you’ll also need to declare your &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService&lt;/code&gt; to give it permissions to do wallpaper-y things.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-xml"&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;manifest&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;application&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- ... some stuff ... --&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;service&lt;/span&gt;
        &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"MyWallpaperService"&lt;/span&gt;
        &lt;span class="na"&gt;android:enabled=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
        &lt;span class="na"&gt;android:permission=&lt;/span&gt;&lt;span class="s"&gt;"android.permission.BIND_WALLPAPER"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.service.wallpaper.WallpaperService"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;meta-data&lt;/span&gt;
          &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.service.wallpaper"&lt;/span&gt;
          &lt;span class="na"&gt;android:resource=&lt;/span&gt;&lt;span class="s"&gt;"@xml/my_wallpaper"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- ... other stuff ... --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/application&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id="step-3---launch-your-empty-wallpaper"&gt;Step 3 - Launch your empty wallpaper&lt;/h1&gt;
&lt;p&gt;Now that the system knows about your fun (currently blank) wallpaper, it’s time to get it going! To wire it up, you need to start the &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER&lt;/code&gt; action with your &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService&lt;/code&gt;. You can do this from within an &lt;code class="language-plaintext highlighter-rouge"&gt;OnClickListener&lt;/code&gt;, or anywhere that can start an &lt;code class="language-plaintext highlighter-rouge"&gt;Activity&lt;/code&gt;.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-kotlin"&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;intent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;WallpaperManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACTION_CHANGE_LIVE_WALLPAPER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;putExtra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;WallpaperManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EXTRA_LIVE_WALLPAPER_COMPONENT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ComponentName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MyWallpaperService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;startActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It should look something like this.&lt;/p&gt;

&lt;p&gt;&lt;img alt="This could be the end of the tutorial if you like blank wallpapers." src="/assets/article_images/2020-09-25-android-live-wallpaper/Blank Wallpaper Is Best Wallpaper.png" /&gt;&lt;/p&gt;

&lt;h1 id="step-4---have-fun-with-art"&gt;Step 4 - Have fun with ✨art✨&lt;/h1&gt;

&lt;p&gt;Go back to your &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService&lt;/code&gt; and &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService.Engine&lt;/code&gt; implementation from &lt;em&gt;Step 1&lt;/em&gt;. We’ll just make changes in these classes for the rest of this tutorial.&lt;/p&gt;

&lt;h2 id="solid-background"&gt;Solid Background&lt;/h2&gt;

&lt;p&gt;To make a background, get the canvas, draw on it, and then post the update. In our first example, override the &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService.Engine#onSurfaceCreated&lt;/code&gt; method.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-kotlin"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWallpaperService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreateEngine&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;inner&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onSurfaceCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SurfaceHolder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;canvas&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lockCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="c1"&gt;// ... do ✨art✨ stuff&lt;/span&gt;
      &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlockCanvasAndPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To set everything as one color, draw a &lt;code class="language-plaintext highlighter-rouge"&gt;Paint&lt;/code&gt; object with fill style and color of your choice.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-kotlin"&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onSurfaceCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SurfaceHolder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;canvas&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lockCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;paint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CYAN&lt;/span&gt;
    &lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FILL&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawPaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;holder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlockCanvasAndPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img alt="I would maybe pick a different color if I were you." src="/assets/article_images/2020-09-25-android-live-wallpaper/Cyan Wallpaper Is Good Too.png" /&gt;&lt;/p&gt;

&lt;h2 id="its-alive"&gt;It’s (a)live!&lt;/h2&gt;

&lt;p&gt;To show the wallpaper updating as we touch our device, we’re going to override the &lt;code class="language-plaintext highlighter-rouge"&gt;WallpaperService.Engine#onTouchEvent&lt;/code&gt; callback. We want to only update when we actually touch our device and not when we also lift our finger up, so we’ll filter for the &lt;code class="language-plaintext highlighter-rouge"&gt;MotionEvent.ACTION_DOWN&lt;/code&gt; action.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-kotlin"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWallpaperService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreateEngine&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;inner&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onTouchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MotionEvent&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// on finder press events&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;MotionEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACTION_DOWN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// get the canvas from the Engine or leave&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;canvas&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;surfaceHolder&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;lockCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="c1"&gt;// ... do ✨art✨ stuff&lt;/span&gt;
        &lt;span class="c1"&gt;// update the surface&lt;/span&gt;
        &lt;span class="n"&gt;surfaceHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlockCanvasAndPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To show the touch events are working, let’s change the color to a random one every time. Here’s a quick and easy way to pick a random color between &lt;code class="language-plaintext highlighter-rouge"&gt;#000000&lt;/code&gt; and &lt;code class="language-plaintext highlighter-rouge"&gt;#FFFFFF&lt;/code&gt;.&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-kotlin"&gt;&lt;span class="c1"&gt;// value between #000000 and #FFFFFF&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;randomColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16_777_216&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// convert it to hex/base 16&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// gurantee it's six characters long&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// still need to prefix with a '#',&lt;/span&gt;
  &lt;span class="c1"&gt;// but you get the idea.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And when we put it all together…&lt;/p&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-kotlin"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyWallpaperService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreateEngine&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;inner&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WallpaperEngine&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WallpaperService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onTouchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MotionEvent&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;MotionEvent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACTION_DOWN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;canvas&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;surfaceHolder&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;lockCanvas&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;paint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;randomColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nextInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16_777_216&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#$randomColor"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Paint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FILL&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawPaint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;surfaceHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unlockCanvasAndPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;… we get a live wallpaper! Here’s a bunch of colors that come up randomly on my first few taps.&lt;sup id="fnref:how_to_tile"&gt;&lt;a class="footnote" href="#fn:how_to_tile" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;img alt="So many colors!" src="/assets/article_images/2020-09-25-android-live-wallpaper/Changing-Color-Wallpaper.png" /&gt;&lt;/p&gt;

&lt;h1 id="keep-going"&gt;Keep going!&lt;/h1&gt;

&lt;p&gt;Now that you have a basic live live wallpaper, try things out! &lt;a href="https://twitter.com/vogella"&gt;Lars Vogel&lt;/a&gt; also &lt;a href="https://www.vogella.com/tutorials/AndroidLiveWallpaper/article.html"&gt;wrote a nice tutorial&lt;/a&gt; which I learned from before writing this. Their post has more on using a &lt;code class="language-plaintext highlighter-rouge"&gt;Handler&lt;/code&gt; and &lt;code class="language-plaintext highlighter-rouge"&gt;Runnable&lt;/code&gt; which will be useful if you want your live wallpaper to move continuously. If you end up making anything (including this example), please record it and &lt;a href="https://twitter.com/SalTesta14"&gt;share it with me on Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for your time, and I hope you enjoyed this post!&lt;/p&gt;

&lt;hr /&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:which_api_version"&gt;
      &lt;p&gt;The Wikipedia article for Android incorrectly lists &lt;a href="https://web.archive.org/web/20200919035409/https://en.wikipedia.org/wiki/Android_version_history#Android_2.0_Eclair_(API_5)"&gt;Android 2.0 (API 5)&lt;/a&gt; as the origin of the live wallpaper. However, if you read the &lt;a href="https://web.archive.org/web/20110302100035/http://developer.android.com/sdk/android-2.0-highlights.html"&gt;release notes for Android 2.0 (API 5)&lt;/a&gt; and &lt;a href="https://web.archive.org/web/20110302101832/http://developer.android.com/sdk/android-2.1.html"&gt;Android 2.1 (API 7)&lt;/a&gt;, you’ll see what I’m talking about. &lt;a class="reversefootnote" href="#fnref:which_api_version"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:nexus_revamped"&gt;
      &lt;p&gt;I couldn’t find an emulator running Android 2.1, but I did find &lt;a href="https://play.google.com/store/apps/details?id=com.stealthcopter.nexusrevamped"&gt;Nexus Revamped&lt;/a&gt;, a strikingly similar wallpaper. &lt;a class="reversefootnote" href="#fnref:nexus_revamped"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:how_to_tile"&gt;
      &lt;p&gt;To make a tiled image like this, I installed &lt;a href="https://imagemagick.org/index.php"&gt;ImageMagick&lt;/a&gt; and ran the following &lt;a href="https://www.imagemagick.org/Usage/montage/"&gt;montage&lt;/a&gt; command: &lt;code class="language-plaintext highlighter-rouge"&gt;montage folder-with-screenshots/* -tile 7x4 -geometry +40+40 -background none tiled-wallpaper-montage.png&lt;/code&gt; &lt;a class="reversefootnote" href="#fnref:how_to_tile"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>Salvatore's Blog</author><pubDate>Fri, 25 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://sal.dev/android/android-live-wallpaper/</guid></item><item><title>searchmysite.net update: Seeding and scaling</title><link>https://michael-lewis.com/posts/searchmysite.net-update-seeding-and-scaling/</link><description>&lt;p&gt;Note: this post is now on blog.searchmysite.net at &lt;a class="external-link" href="https://blog.searchmysite.net/posts/searchmysite.net-update-seeding-and-scaling/" rel="noopener" target="_blank"&gt;https://blog.searchmysite.net/posts/searchmysite.net-update-seeding-and-scaling/&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="introduction"&gt;
  Introduction
  &lt;a class="heading-link" href="#introduction"&gt;
    &lt;i class="fa-solid fa-link" title="Link to heading"&gt;&lt;/i&gt;
    &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
  &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;It has been just over 2 months since I launched &lt;a class="external-link" href="https://searchmysite.net" rel="noopener" target="_blank"&gt;https://searchmysite.net&lt;/a&gt;. I&amp;rsquo;ve had some good feedback from the IndieWeb community in that time, and made some key changes as a result, so thought it was time for an update. You may still want to refer to &lt;a href="https://michael-lewis.com/posts/searchmysite.net-building-a-simple-search-for-non-commercial-websites/"&gt;searchmysite.net: Building a simple search for non-commercial websites&lt;/a&gt; for the original overview.&lt;/p&gt;</description><author>Michael Ian Lewis</author><pubDate>Fri, 25 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://michael-lewis.com/posts/searchmysite.net-update-seeding-and-scaling/</guid></item><item><title>Burn Out at the Hydrogen Bar</title><link>https://macleodsawyer.com/music/burn-out-at-the-hydrogen-bar/</link><description/><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Thu, 24 Sep 2020 23:39:00 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/music/burn-out-at-the-hydrogen-bar/</guid></item><item><title>ConcurrentLinkedDeque 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/09/24/ConcurrentLinkedDeque.html</link><description>&lt;h1 id="concurrentlinkeddeque"&gt;ConcurrentLinkedDeque&lt;/h1&gt;
&lt;p&gt;ConcurrentLinkedDeque 是基于&lt;strong&gt;链表&lt;/strong&gt;的&lt;strong&gt;无限双端队列&lt;/strong&gt;，&lt;strong&gt;线程安全&lt;/strong&gt;，不允许 null 元素。&lt;/p&gt;

&lt;p&gt;ConcurrentLinkedDeque 内部通过 CAS 来实现线程同步，一般来说，如果需要使用线程安全的双端队列，那么推荐使用该类。&lt;/p&gt;

&lt;p&gt;由于双端队列的特性，该类同样可以当做&lt;strong&gt;栈&lt;/strong&gt;来使用，所以如果需要在并发环境下使用栈，也可以使用该类。&lt;/p&gt;

&lt;p&gt;迭代器设计为&lt;a href="https://en.wikipedia.org/wiki/Weak_consistency" title="弱一致性"&gt;弱一致性&lt;/a&gt;的（weakly consistent），此外还可以通过&lt;code class="language-plaintext highlighter-rouge"&gt;descendingIterator&lt;/code&gt;方法获取一个通过相反方向遍历的迭代器。&lt;/p&gt;

&lt;p&gt;虽然跟 LinkedList 一样都是双端队列的链表实现，但由于其并发特性，导致无法简单点的通过计数来确定队列的长度，所以&lt;code class="language-plaintext highlighter-rouge"&gt;size&lt;/code&gt;方法将会&lt;strong&gt;以线性时间&lt;/strong&gt;运行，并且如果在执行期间被其它线程修改可能返回&lt;strong&gt;不准确的结果&lt;/strong&gt;。
&lt;!--more--&gt;
对于批量操作，例如：&lt;code class="language-plaintext highlighter-rouge"&gt;addAll，removeAll，retainAll，containsAll，equals,toArray&lt;/code&gt;来说，不能保证这些操作的原子性。&lt;/p&gt;

&lt;h1 id="方法"&gt;方法&lt;/h1&gt;

&lt;p&gt;ConcurrentLinkedDeque 作为队列（&lt;strong&gt;FIFO&lt;/strong&gt;）使用时的方法：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;队列方法&lt;/th&gt;
      &lt;th&gt;等效的双端队列方法&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;add(e)&lt;/td&gt;
      &lt;td&gt;addLast(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;offer(e)&lt;/td&gt;
      &lt;td&gt;offerLast(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;remove()&lt;/td&gt;
      &lt;td&gt;removeFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;poll()&lt;/td&gt;
      &lt;td&gt;pollFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;element()&lt;/td&gt;
      &lt;td&gt;getFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;peek()&lt;/td&gt;
      &lt;td&gt;peekFirst()&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;ConcurrentLinkedDeque 作为堆栈（&lt;strong&gt;FILO&lt;/strong&gt;）使用时的方法：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;堆栈方法&lt;/th&gt;
      &lt;th&gt;等效的双端队列方法&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;push(e)&lt;/td&gt;
      &lt;td&gt;addFirst(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pop(e)&lt;/td&gt;
      &lt;td&gt;removeFirst(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;peek()&lt;/td&gt;
      &lt;td&gt;peekFirst()&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id="源码"&gt;源码&lt;/h1&gt;
&lt;p&gt;因为 ConcurrentLinkedDeque 是基于链表的数据结构，我们先看看该类中使用的链表节点 Node 的相关代码。&lt;/p&gt;
&lt;h2 id="node"&gt;Node&lt;/h2&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;sun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;misc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Unsafe&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;prevOffset&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;itemOffset&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;nextOffset&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="no"&gt;UNSAFE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sun&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;misc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUnsafe&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;prevOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;objectFieldOffset&lt;/span&gt;
                    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"prev"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;itemOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;objectFieldOffset&lt;/span&gt;
                    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"item"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;nextOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;objectFieldOffset&lt;/span&gt;
                    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"next"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上半部分代码就是一个标准的 Node 节点的定义，我们主要看静态初始化块中的代码。&lt;/p&gt;

&lt;p&gt;首先介绍一下 Unsafe 类，关于这个类的详细信息及使用可以看美团技术的&lt;a href="https://tech.meituan.com/2019/02/14/talk-about-java-magic-class-unsafe.html" title="这篇文章"&gt;这篇文章&lt;/a&gt;，这里大概介绍一下，Unsafe 中提供了一些执行级别低，不安全的方法，例如内存操作以及待会会看到的 CAS，一般来说不推荐使用，因此命名为 Unsafe。&lt;/p&gt;

&lt;p&gt;Node 内部类中定义的三个 offset 变量：&lt;code class="language-plaintext highlighter-rouge"&gt;prevOffset&lt;/code&gt;、&lt;code class="language-plaintext highlighter-rouge"&gt;itemOffset&lt;/code&gt;、&lt;code class="language-plaintext highlighter-rouge"&gt;nextOffset&lt;/code&gt; 分别对应 &lt;code class="language-plaintext highlighter-rouge"&gt;prev&lt;/code&gt;、&lt;code class="language-plaintext highlighter-rouge"&gt;item&lt;/code&gt;、&lt;code class="language-plaintext highlighter-rouge"&gt;next&lt;/code&gt; 这三个变量的内存偏移量（相对内存地址），通过这三个偏移量可以拿到实际的内存中的值，这个后面会看到怎么用。&lt;/p&gt;

&lt;p&gt;然后静态初始化块中获取了 Unsafe 实例，接着对三个 offset 变量进行初始化。&lt;/p&gt;

&lt;p&gt;下面再来看看 Node 中其它几个方法：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;itemOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;casItem&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareAndSwapObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;itemOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;lazySetNext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putOrderedObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nextOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;casNext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareAndSwapObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nextOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;lazySetPrev&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putOrderedObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prevOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;casPrev&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;UNSAFE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;compareAndSwapObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prevOffset&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;第一个构造方法意思就是将参数中的对象设置到指定的地址偏移量处。&lt;/p&gt;

&lt;p&gt;下面的几个方法分为两类，一类是 cas 开头的操作一类是 lazySet 操作，先说下 cas 操作，例如&lt;code class="language-plaintext highlighter-rouge"&gt;casItem&lt;/code&gt;方法，其作用是将对应的 item 值替换为参数 val 的值，该方法会先对比内存中的值与 cmp 参数值是否相等，相等则替换，返回值表示操作是否完成，这里调用了&lt;code class="language-plaintext highlighter-rouge"&gt;UNSAFE.compareAndSwapObject&lt;/code&gt;方法来保证并发环境下的安全问题。&lt;/p&gt;

&lt;p&gt;而&lt;code class="language-plaintext highlighter-rouge"&gt;lazySetNext&lt;/code&gt;方法则是直接将参数 val 设置到内存中，调用了&lt;code class="language-plaintext highlighter-rouge"&gt;UNSAFE.putOrderedObject&lt;/code&gt;方法。&lt;/p&gt;

&lt;p&gt;上面我们已经介绍了 Node 类中的代码，其中已经实现了部分多线程同步代码，毕竟对链表的操作本质上都是对节点的操作，虽然其他还有很多方法，但基本都是层层嵌套调用，最终可能都会调用到那几个重点方法上面，下面我们看看这几个重点。&lt;/p&gt;

&lt;h2 id="linkfirst"&gt;linkFirst&lt;/h2&gt;
&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;linkFirst&lt;/code&gt;方法用于将指定的节点添加到链表头位置，例如&lt;code class="language-plaintext highlighter-rouge"&gt;addFirst&lt;/code&gt;、&lt;code class="language-plaintext highlighter-rouge"&gt;offerFirst&lt;/code&gt;最终都是调用了该方法。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;linkFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;checkNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;restartFromHead:&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(;;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;;;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
              &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;// Check for head updates every other hop.&lt;/span&gt;
        &lt;span class="c1"&gt;// If p == q, we are sure to follow head instead.&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// PREV_TERMINATOR&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="n"&gt;restartFromHead&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// p is first node&lt;/span&gt;
        &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lazySetNext&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// CAS piggyback&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;casPrev&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Successful CAS is the linearization point&lt;/span&gt;
          &lt;span class="c1"&gt;// for e to become an element of this deque,&lt;/span&gt;
          &lt;span class="c1"&gt;// and for newNode to become "live".&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// hop two nodes at a time&lt;/span&gt;
            &lt;span class="n"&gt;casHead&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Failure is OK.&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Lost CAS race to another thread; re-read prev&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面代码先开启了一个死循环用于自旋，第二个循环用于在每次自旋时找到&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点，因为多线程环境下&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点或者说链表随时可能被修改，所以每次都需要重新获取。&lt;/p&gt;

&lt;p&gt;找到&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点后，也就是&lt;code class="language-plaintext highlighter-rouge"&gt;p&lt;/code&gt;变量，开始进行替换操作，将&lt;code class="language-plaintext highlighter-rouge"&gt;newNode&lt;/code&gt;设置为&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点。先调用&lt;code class="language-plaintext highlighter-rouge"&gt;newNode.lazySetNext(p)&lt;/code&gt;将原来的&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点设置为&lt;code class="language-plaintext highlighter-rouge"&gt;newNode&lt;/code&gt;的next节点，然后开始 cas 操作，调用&lt;code class="language-plaintext highlighter-rouge"&gt;p.casPrev(null, newNode)&lt;/code&gt;将原本&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;节点的&lt;code class="language-plaintext highlighter-rouge"&gt;prev&lt;/code&gt;节点设置为&lt;code class="language-plaintext highlighter-rouge"&gt;newNode&lt;/code&gt;。&lt;code class="language-plaintext highlighter-rouge"&gt;casPrev&lt;/code&gt;的返回值表示是否操作成功，操作失败则继续下一次自旋重试，直到操作成功为止。&lt;/p&gt;

&lt;p&gt;好了源码就说这么多吧，其他几个方法也都大同小异，大差不差，这个明白了其他的也就明白了。&lt;/p&gt;</description><author>张可的博客</author><pubDate>Thu, 24 Sep 2020 18:16:27 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/09/24/ConcurrentLinkedDeque.html</guid></item><item><title>For non-westerners, it's harder to write in Wikipedia</title><link>https://stop.zona-m.net/2020/09/for-non-westerners-its-harder-to-write-in-wikipedia/</link><description>&lt;p&gt;Did you already know that?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 24 Sep 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/for-non-westerners-its-harder-to-write-in-wikipedia/</guid></item><item><title>Skiing bookmarks</title><link>https://xenodium.com/skiing-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.lonelyplanet.com/articles/remote-ski-resorts-europe"&gt;7 far-flung European ski resorts - Lonely Planet&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Thu, 24 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/skiing-bookmarks</guid></item><item><title>Trigonometry Graphs with Octave</title><link>https://www.tderflinger.com/en/trigonometry-graphs-octave</link><description>Octave is a free and open source scientific computing platform. It is especially suited for mathematical operations and has a simple mechanism to plot the data. Trigonometry visualizations are especially powerful with Octave.</description><author>Thoughts by Thomas Derflinger</author><pubDate>Thu, 24 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.tderflinger.com/en/trigonometry-graphs-octave</guid></item><item><title>Even if tech is addictive, abstinence is no solution</title><link>https://stop.zona-m.net/2020/09/even-if-tech-is-addictive-abstinence-is-no-solution/</link><description>&lt;p&gt;Especially (but not only) for kids?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 23 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/even-if-tech-is-addictive-abstinence-is-no-solution/</guid></item><item><title>A Simple and Flexible Pytorch Video Pipeline</title><link>https://paulbridger.com/posts/video-analytics-pytorch-pipeline/</link><description>Taking machine learning models into production for video analytics doesn&amp;rsquo;t have to be hard. A pipeline with reasonable efficiency can be created very quickly just by plugging together the right libraries. In this post we&amp;rsquo;ll create a video pipeline with a focus on flexibility and simplicity using two main libraries: &lt;a href="https://gstreamer.freedesktop.org/"&gt;Gstreamer&lt;/a&gt; and &lt;a href="https://pytorch.org"&gt;Pytorch&lt;/a&gt;.</description><author>Machine Learning Articles on paulbridger.com</author><pubDate>Wed, 23 Sep 2020 19:21:00 GMT</pubDate><guid isPermaLink="true">https://paulbridger.com/posts/video-analytics-pytorch-pipeline/</guid></item><item><title>REST Endpoint + CRUD with AWS Lambda and DynamoDB in 2 minutes</title><link>https://www.swyx.io/amplify_rest_crud</link><description>A lightning fast overview of everything you need to know to set up a REST endpoint with full CRUD capability with AWS Lambda, DynamoDB and AWS Amplify in 2 minutes.</description><author>swyx's site RSS Feed</author><pubDate>Wed, 23 Sep 2020 17:31:01 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/amplify_rest_crud</guid></item><item><title>ArrayDeque 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/09/23/ArrayDeque.html</link><description>&lt;h1 id="arraydeque"&gt;ArrayDeque&lt;/h1&gt;
&lt;p&gt;ArrayDeque 是 Java 集合中&lt;strong&gt;双端队列&lt;/strong&gt;的&lt;strong&gt;数组实现&lt;/strong&gt;，双端队列的链表实现（&lt;strong&gt;LinkedList&lt;/strong&gt;）我们在前几篇文章中讲过了。&lt;/p&gt;

&lt;p&gt;ArrayDeque 几乎没有容量限制，设计为&lt;strong&gt;线程不安全的&lt;/strong&gt;，&lt;strong&gt;禁止 null 元素&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;ArrayDeque 作为&lt;strong&gt;栈&lt;/strong&gt;使用时&lt;strong&gt;比 Stack 类效率要高&lt;/strong&gt;，作为&lt;strong&gt;队列&lt;/strong&gt;使用时&lt;strong&gt;比 LinkedList 要快&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;ArrayDeque 大多数的额操作都在&lt;strong&gt;固定时间&lt;/strong&gt;内运行，例外情况包括 &lt;code class="language-plaintext highlighter-rouge"&gt;remove&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;removeFirstOccurrence&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;removeLastOccurrence&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;contains&lt;/code&gt;，&lt;code class="language-plaintext highlighter-rouge"&gt;iterator.remove()&lt;/code&gt;，和批量操作，这些将以&lt;strong&gt;线性时间&lt;/strong&gt;运行。&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;iterator&lt;/code&gt;同样也被设计为 &lt;a href="https://en.wikipedia.org/wiki/Fail-fast" title="fail-fast"&gt;fail-fast&lt;/a&gt;。
&lt;!--more--&gt;&lt;/p&gt;
&lt;h1 id="方法"&gt;方法&lt;/h1&gt;
&lt;p&gt;ArrayDeque 作为 &lt;strong&gt;队列（FIFO）&lt;/strong&gt; 使用时的方法：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;队列方法&lt;/th&gt;
      &lt;th&gt;等效的双端队列方法&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;add(e)&lt;/td&gt;
      &lt;td&gt;addLast(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;offer(e)&lt;/td&gt;
      &lt;td&gt;offerLast(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;remove()&lt;/td&gt;
      &lt;td&gt;removeFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;poll()&lt;/td&gt;
      &lt;td&gt;pollFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;element()&lt;/td&gt;
      &lt;td&gt;getFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;peek()&lt;/td&gt;
      &lt;td&gt;peekFirst()&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;ArrayDeque 作为 &lt;strong&gt;堆栈（FILO）&lt;/strong&gt; 使用时的方法：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;堆栈方法&lt;/th&gt;
      &lt;th&gt;等效的双端队列方法&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;push(e)&lt;/td&gt;
      &lt;td&gt;addFirst(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pop(e)&lt;/td&gt;
      &lt;td&gt;removeFirst(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;peek()&lt;/td&gt;
      &lt;td&gt;peekFirst()&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id="源码"&gt;源码&lt;/h1&gt;
&lt;p&gt;我们先看看代码中最重要的三个变量：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们上面也说了 ArrayDeque 是双端队列的数组实现，上面代码可看到确实定义了一个用于存储链表数据数组：&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;，此外还定义了&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;及&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;用于描述链表在数组中的头尾位置。另外说明一下，&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;长度始终未 2 的次方。&lt;/p&gt;

&lt;p&gt;这里需要注意一点，用&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;存储的是双端队列，&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;和&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;参数表示双端队列的头和尾的索引，但并不意味着&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;值永远小于&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;，当&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;移动至数组末尾，但队列长度小于数组时（意味着此时&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;大于0），再向队列末尾添加数据将会使&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;移动至数组的开头。&lt;/p&gt;

&lt;p&gt;假设下图为当前的&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;数组，黄色方块表示其中有数据。&lt;/p&gt;

&lt;p&gt;&lt;img alt="" src="https://img-blog.csdnimg.cn/20200923143615980.png#pic_center" /&gt;
当我们向队列末尾添加一个元素时，数组变成了下面这样：&lt;/p&gt;

&lt;p&gt;&lt;img alt="" src="https://img-blog.csdnimg.cn/20200923143632138.png#pic_center" /&gt;&lt;/p&gt;

&lt;p&gt;目前都是按照我们预期发展的，现在我们来调用&lt;code class="language-plaintext highlighter-rouge"&gt;poll&lt;/code&gt;方法移除队列头部的一个元素，此时&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;变成了下图：&lt;/p&gt;

&lt;p&gt;&lt;img alt="" src="https://img-blog.csdnimg.cn/20200923143645813.png#pic_center" /&gt;
这个时候因为我们移除了队列的头部元素，数组的开头已经空下来了一个位置，这时候再向队列末尾追加一个元素。&lt;/p&gt;

&lt;p&gt;&lt;img alt="" src="https://img-blog.csdnimg.cn/20200923143658734.png#pic_center" /&gt;
可以看到，此时&lt;code class="language-plaintext highlighter-rouge"&gt;head&lt;/code&gt;在&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;的右侧，ArrayDeque为了不浪费数组空间进行了这样的设计，也不难理解，我们继续向下看。&lt;/p&gt;

&lt;p&gt;现在看一下构造器：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ArrayDeque&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ArrayDeque&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;numElements&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;allocateElements&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numElements&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ArrayDeque&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;allocateElements&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;calculateSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;numElements&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MIN_INITIAL_CAPACITY&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numElements&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numElements&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;  &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// Too many elements, must back off&lt;/span&gt;
            &lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="c1"&gt;// Good luck allocating 2 ^ 30 elements&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;allocateElements&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;numElements&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;calculateSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numElements&lt;/span&gt;&lt;span class="o"&gt;)];&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;默认构造器会将&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;初始化为一个长度为 16 的数组，另外两个构造器将根据参数的长度来初始化，最终会调用&lt;code class="language-plaintext highlighter-rouge"&gt;calculateSize&lt;/code&gt;方法计算初始长度。&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;calculateSize&lt;/code&gt;方法就比较有意思了，其中用了很多位运算（虽然我们日常用的很少，但 JDK 中随处可见位运算），最终结果就是控制输出的&lt;code class="language-plaintext highlighter-rouge"&gt;initialCapacity&lt;/code&gt;参数保持在 2 的次方。&lt;/p&gt;

&lt;p&gt;下面我们看看添加元素时的源码，添加元素到双向链表最后都会进入&lt;code class="language-plaintext highlighter-rouge"&gt;addLast&lt;/code&gt;方法中：&lt;/p&gt;

&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addLast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NullPointerException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;doubleCapacity&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面代码的意思就是把元素添加到队列末尾，并移动&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;的值，根据上面的介绍，&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;移动并不会单纯的向后移动，而是会根据当前&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;数组的空余长度进行移动，但这里移动&lt;code class="language-plaintext highlighter-rouge"&gt;tail&lt;/code&gt;的代码写的很巧妙：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们上面说过，因为&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;的长度永远是 2 的次方，所以&lt;code class="language-plaintext highlighter-rouge"&gt;elements.length - 1&lt;/code&gt;的二进制位都是 1，对其进行 &amp;amp; 运算相当于对&lt;code class="language-plaintext highlighter-rouge"&gt;elements.length&lt;/code&gt;进行求余，所以下面两个公式是相等的，不过这种关系必须保证&lt;code class="language-plaintext highlighter-rouge"&gt;elements&lt;/code&gt;长度是 2 的次方才成立：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;由于位运算的效率比算数运算要高很多，所以 JDK 中很多类似的应用。&lt;/p&gt;

&lt;p&gt;好了，回到上面的&lt;code class="language-plaintext highlighter-rouge"&gt;addLast&lt;/code&gt;方法中去，该方法回判断&lt;code class="language-plaintext highlighter-rouge"&gt;tail == head&lt;/code&gt;是否成立，相等则表示数组已满，满了就进行扩容，也就是调用&lt;code class="language-plaintext highlighter-rouge"&gt;doubleCapacity()&lt;/code&gt;方法。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doubleCapacity&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// number of elements to the right of p&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sorry, deque too big"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arraycopy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;arraycopy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;扩容操作会创建一个新的数组，长度为原数组的两倍，然后通过两次复制操作将原数组复制到新的数组中。&lt;/p&gt;

&lt;p&gt;好了，关于 ArrayDeque 就介绍这么多了，其他的方法大体上都是类似的。&lt;/p&gt;</description><author>张可的博客</author><pubDate>Wed, 23 Sep 2020 13:00:03 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/09/23/ArrayDeque.html</guid></item><item><title>Understanding Integration Testing in React</title><link>https://maxrozen.com/understanding-integration-testing-react</link><description>Moving from Enzyme to React Testing Library is rough. You can't do a lot of things you used to, and there are new best practices. Let's learn them!</description><author>Max Rozen</author><pubDate>Wed, 23 Sep 2020 12:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/understanding-integration-testing-react</guid></item><item><title>Lifesaver tools: Rule converter</title><link>https://shadow.sombragris.org/?p=1079</link><description>Hi again! It&amp;#8217;s been a long time. I know&amp;#8230; and there&amp;#8217;s lot of things to share and get to speed. But that can wait for now. Today I would like to talk about a tool which I classify as a lifesaver: something which really takes a lot of meaningless worries and headaches from your daily...</description><author>The Grey Shadow</author><pubDate>Wed, 23 Sep 2020 08:53:59 GMT</pubDate><guid isPermaLink="true">https://shadow.sombragris.org/?p=1079</guid></item><item><title>About Paul Bridger</title><link>https://paulbridger.com/posts/about/</link><description>Hi. I&amp;rsquo;m Paul, and I like to write code, build products and start companies.
I started out in New Zealand, and I&amp;rsquo;ve been lucky enough to work with some very special people in many places around the world. I&amp;rsquo;ve often played a technical co-founder role, leading and growing engineering teams, and taking complex products from conception to production.
Over the last couple of decades I&amp;rsquo;ve built products in a wide range of industries, from publishing, 3D game development, investment banking, to iOS, big data and machine learning.</description><author>Machine Learning Articles on paulbridger.com</author><pubDate>Wed, 23 Sep 2020 02:14:00 GMT</pubDate><guid isPermaLink="true">https://paulbridger.com/posts/about/</guid></item><item><title>Reading algorithms make your world smaller</title><link>https://stop.zona-m.net/2020/09/reading-algorithms-make-your-world-smaller/</link><description>&lt;p&gt;Of course. Why should you care of what happens elsewhere?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 22 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/reading-algorithms-make-your-world-smaller/</guid></item><item><title>Notes on Simple Made Easy</title><link>https://ricardoanderegg.com/posts/notes-simple-made-easy-rich-hickey/</link><description>&lt;p&gt;These are my notes on the talks &lt;a href="https://www.youtube.com/watch?v=kGlVcSMgtV4"&gt;&amp;ldquo;Simple Made Easy&amp;rdquo; by Rich Hickey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Simplicity is a prerequisite for reliability&lt;/em&gt; - Dijkstra&lt;/p&gt;
&lt;p&gt;Simple:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One role.&lt;/li&gt;
&lt;li&gt;One task.&lt;/li&gt;
&lt;li&gt;One concept.&lt;/li&gt;
&lt;li&gt;One dimension.&lt;/li&gt;
&lt;li&gt;Lack of interleaving. (Does not mean there&amp;rsquo;s only one thing)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Easy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Near&amp;rdquo;. To our understanding, skill/set or capabilities.&lt;/li&gt;
&lt;li&gt;Easy is relative.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can only make reliable those things we can understand.&lt;/p&gt;
&lt;p&gt;We can only consider a few things at a time. If a piece is intertwined with another we already have to keep both in mind. It&amp;rsquo;s combinatorial.&lt;/p&gt;</description><author>Posts on rand[om]</author><pubDate>Tue, 22 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ricardoanderegg.com/posts/notes-simple-made-easy-rich-hickey/</guid></item><item><title>Shoe Dog: A Memoir by the Creator of Nike</title><link>https://olshansky.info/book/shoe_dog/</link><description>Olshansky's review of Shoe Dog: A Memoir by the Creator of Nike by Phil Knight</description><author>🦉 olshansky 🦁</author><pubDate>Tue, 22 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/shoe_dog/</guid></item><item><title>On Blogging Versus Social Media</title><link>https://benovermyer.com/blog/2020/09/on-blogging-versus-social-media/</link><description>&lt;p&gt;I read &lt;a href="https://rubenerd.com/why-arent-you-more-serious/" rel="external"&gt;Rubenerd's post about seriousness&lt;/a&gt;, and it got me to thinking. Most people these days are content to post on social media. Very few have their own blogs, let alone a dedicated personal website.&lt;/p&gt;
&lt;p&gt;But that's not the web I grew up with.&lt;/p&gt;
&lt;p&gt;I've had many blogs over the years. They've been powered by different services or software, and had different focuses. But taken as a whole, they've painted a picture remarkably similar to modern social media posts - snapshots of my life at the time. Things that I've been thinking about, things I'm excited about, things I'm angry about.&lt;/p&gt;
&lt;p&gt;There are two key differences, though. Blog posts tend to run a lot longer than social media posts, and I fully control the platform on which they appear.&lt;/p&gt;
&lt;p&gt;Also, people who read blogs tend to be more willing to read longer content. On social media, the vast majority of users seem to only be interested in reacting to short sentences and images. There's nothing &lt;em&gt;wrong&lt;/em&gt; with that, exactly, but it's not the kind of interaction I'm looking for when I write longer content.&lt;/p&gt;
&lt;p&gt;The other thing that Rubenerd made me remember is back when I drew cartoon faces for my earliest websites to reflect my mood for any given update. Maybe I should resurrect that practice and give my site a little more playfulness.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Tue, 22 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/09/on-blogging-versus-social-media/</guid></item><item><title>Debug</title><link>https://ferrucc.io/posts/debug/</link><description>&lt;p&gt;Sometimes I come back home from work, stuck on something, no adults to ask help to and a deadline in the morning.&lt;/p&gt;
&lt;p&gt;I fall asleep thinking: &amp;ldquo;Tomorrow is the day I&amp;rsquo;ll get caught. This will be the one problem I won&amp;rsquo;t be able to solve. The rest of my life is going to be misery and failure&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Every morning though, with more or less pain things get sorted.&lt;/p&gt;
&lt;p&gt;Anyways here&amp;rsquo;s what you should do when you&amp;rsquo;re stuck:&lt;/p&gt;</description><author>ferrucc.io</author><pubDate>Tue, 22 Sep 2020 01:15:44 GMT</pubDate><guid isPermaLink="true">https://ferrucc.io/posts/debug/</guid></item><item><title>Springer Handbook of Robotics (2nd Ed.)</title><link>https://macleodsawyer.com/library/springer-handbook-of-robotics-2nd-ed/</link><description>&lt;blockquote&gt;
&lt;p&gt;The second edition of this handbook provides a state-of-the-art overview on the various aspects in the rapidly developing field of robotics. Reaching for the human frontier, robotics is vigorously engaged in the growing challenges of new emerging domains. Interacting, exploring, and working with humans, the new generation of robots will increasingly touch people and their lives. The credible prospect of practical robots among humans is the result of the scientific endeavour of a half a century of robotic developments that established robotics as a modern scientific discipline. The ongoing vibrant expansion and strong growth of the field during the last decade has fueled this second edition of the &lt;strong&gt;Springer Handbook of Robotics&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Mon, 21 Sep 2020 23:08:23 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/library/springer-handbook-of-robotics-2nd-ed/</guid></item><item><title>Cosmic Calamity (EP)</title><link>https://macleodsawyer.com/music/cosmic-calamity-ep/</link><description/><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Mon, 21 Sep 2020 23:01:49 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/music/cosmic-calamity-ep/</guid></item><item><title>Pegboard Mounts for my Anemometer and Infrared Temperature Gun</title><link>https://zef.studio/projects/pegboard-mounts-anemometer-temp-gun</link><description>Modeling some pegboard mounts for a digital anemometer and infrared temperature gun.</description><author>Zef Houssney</author><pubDate>Mon, 21 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://zef.studio/projects/pegboard-mounts-anemometer-temp-gun</guid></item><item><title>How is FOIA doing in Italy?</title><link>https://stop.zona-m.net/2020/09/how-is-foia-doing-in-italy/</link><description>&lt;p&gt;Freedom of Information Act, you say? It could be more usable if&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 21 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/how-is-foia-doing-in-italy/</guid></item><item><title>Mobile homepage.html</title><link>https://voussoir.net/writing/mobile_homepage_html</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class="tag_link" href="/writing/tags/today_i_did_this"&gt;[today_i_did_this]&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Mobile homepage.html&lt;/h1&gt;
&lt;p&gt;I'm not satisfied with the new tab page on Android Chrome. So, I put together an html file that I can use as my own homepage. Here's a comparison:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/mobile_homepage_html/comparison.png" title="left: new tab page; right: my home page" /&gt;&lt;/p&gt;
&lt;p&gt;I don't like the new tab page because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You only get eight links.&lt;/li&gt;
&lt;li&gt;You can't rename the links.&lt;/li&gt;
&lt;li&gt;You can't rearrange the links.&lt;/li&gt;
&lt;li&gt;I will never ever ever ever click to view the suggested content.&lt;/li&gt;
&lt;li&gt;The web servers I run on my PC are on different ports, but they keep fighting for the same spot on the new tab page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, new tabs still always go to the new tab page and I have to hit the home button. So while it's not as seamless as I'd like, I can live with the one extra tap.&lt;/p&gt;
&lt;p&gt;Here's what I did:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create the html file, which is as follows:&lt;/p&gt;
&lt;div class="highlight html"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html5&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class=""&gt;Homepage&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;pink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;div&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;grid-auto-flow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;grid-gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class=""&gt;Example&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class=""&gt;Example&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class=""&gt;Example&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class=""&gt;Example&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class=""&gt;Example&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class=""&gt;Example&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sync it between PC and phone with the amazing &lt;a href="https://syncthing.net"&gt;Syncthing&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set it as the homepage using either &lt;code&gt;file:///storage/emulated/0/&amp;lt;path&amp;gt;/homepage.html&lt;/code&gt; or &lt;code&gt;file:///mnt/sdcard/&amp;lt;path&amp;gt;/homepage.html&lt;/code&gt;. Despite the name &lt;code&gt;/sdcard/&lt;/code&gt;, this path should correspond to internal storage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; With Android 10's new scoped storage permissions, you may get a permission denied error while opening the page. Your first option is to place the file inside the &lt;code&gt;Android/data/com.android.chrome&lt;/code&gt; folder. E.g., an absolute path of &lt;code&gt;file:///storage/emulated/0/Android/data/com.android.chrome/homepage.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, I was able to bypass the scoped storage system altogether with this &lt;a href="https://developer.android.com/studio/command-line/adb"&gt;ADB&lt;/a&gt; command: &lt;code&gt;adb shell sm set-isolated-storage off&lt;/code&gt; which &lt;strong&gt;rebooted the phone immediately&lt;/strong&gt; and may have other consequences. I am not sure how it fares on Android 11.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Recently, I have been trying to use Android Firefox more, since it has extension support and thus uBlock. Astonishingly, Mozilla has &lt;a href="https://old.reddit.com/r/firefox/comments/i5nom6/how_to_edit_homepage_on_android/"&gt;removed the ability to set a homepage&lt;/a&gt;, which I believe occurred as part of the &lt;a href="/writing/mobile_homepage_html/mozilla_2020_08_25.html"&gt;2020-08-25 update&lt;/a&gt;. And &lt;a href="/writing/mobile_homepage_html/firefox_ntp.png"&gt;their new tab page&lt;/a&gt; has an even bigger thing that I won't ever ever ever click on. I'm not sure what's going on over there.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/mobile_homepage_html/mobile_homepage_html.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/27775a3c4ccf26499d848f34f9985b475a8d9474"&gt;&lt;time datetime="2022-04-07T15:38:05-07:00"&gt;2022-04-07&lt;/time&gt; Archive mozilla link.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/9cce9f9ef055a5e268a9b913871ff8d0473cf3eb"&gt;&lt;time datetime="2021-06-07T19:08:19-07:00"&gt;2021-06-07&lt;/time&gt; Move S3 images to my domain.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/e2e819427c491d6f70c39259634d170371001f20"&gt;&lt;time datetime="2021-03-21T00:19:46-07:00"&gt;2021-03-21&lt;/time&gt; com.android.chrome folder is safe under scoped storage.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/51a3362ddb81d60f2f01886ca269d9c4df8692df"&gt;&lt;time datetime="2021-03-13T08:32:42-08:00"&gt;2021-03-13&lt;/time&gt; Add scoped storage note and bypass.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/4e202b8138b100f29aceabdf717f179427635894"&gt;&lt;time datetime="2020-09-20T21:27:16-07:00"&gt;2020-09-20&lt;/time&gt; Add mobile_homepage_html.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Mon, 21 Sep 2020 07:27:16 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/mobile_homepage_html</guid></item><item><title>Using RDS Snapshots</title><link>/using-rds-snapshots/</link><description>&lt;p&gt;Recently, I had a case where I needed to gain access to an RDS Instance that I had long since deleted. To add insult to injury, the Bastion host to gain access to the Database server had also been deleted and it's VPC, Security Groups and all the other architecture components! Yikes.&lt;/p&gt;
&lt;p&gt;Fortunately, I had taken a final snapshot before it was deleted. Phew!&lt;/p&gt;
&lt;p&gt;I thought it was as simple as downloading the snapshot, which I assumed was just an SQL Dump, import it into a local Database and then bobs your uncle. Not so fast... RDS Snapshots aren't just database dumps, after all that would just be too easy! Instead they are bespoke AWS format that is not able to be parsed and imported with a tool.&lt;/p&gt;
&lt;p&gt;Despite there being documentation, it's fairly lacking so I thought I'd write a guide on how I gained access to the data within an RDS snapshot.&lt;/p&gt;
&lt;h2&gt;1. Create a new VPC&lt;/h2&gt;
&lt;p&gt;The first step is to create a new VPC. Name it what you like and give it any old CIDR Block. Leave everything else standard&lt;/p&gt;
&lt;div class="image"&gt;
  &lt;img alt="Screenshot of creating a VPC" src="../../assets/images/create-vpc.png" /&gt;
&lt;/div&gt;
&lt;h2&gt;2. Create a Security Group for the VPC&lt;/h2&gt;
&lt;p&gt;Next, you need to create a security group for the VPC you just created.
Simple add a name, then select your previously created VPC you created in step 1.&lt;/p&gt;
&lt;p&gt;Next in the Inbound Rules pane, create an new inbound rule to allow traffic on Port 5432 (the PostgreSQL default port). The source should listed as &amp;quot;Your IP&amp;quot;, which will prefill it on the current IP address you are accessing the AWS Console on.&lt;/p&gt;
&lt;div class="image"&gt;
  &lt;img alt="Creating a AWS Security Group" src="../../assets/images/create-sg.png" /&gt;
&lt;/div&gt;
&lt;h2&gt;3. Restore the RDS Instance&lt;/h2&gt;
&lt;p&gt;Now you've done that, go to RDS and then Snapshots.
Find the snapshot you're looking to get data from and click &amp;quot;Restore snapshot&amp;quot;&lt;/p&gt;
&lt;div class="image"&gt;
&lt;img alt="Select to restore the RDS Snapshot" src="../../assets/images/restore-rds.png" /&gt;
&lt;/div&gt;
&lt;p&gt;This will send you to a configuration page for the instance you are about to boot.
First, change the instance type to something cheaper because the default is something more powerful than Deep blue and costs about as much as a mission to the moon.&lt;/p&gt;
&lt;p&gt;Afterwards, change the VPC that the instance is in, to the one created earlier and change the security group to the one created earlier. In my case &amp;quot;snapshot-access-vpc&amp;quot; and &amp;quot;rds-snapshot-sg&amp;quot;. Additionally, select &amp;quot;Public Access&amp;quot;.&lt;/p&gt;
&lt;div class="image"&gt;
  &lt;img alt="Restore RDS Options" src="../../assets/images/restore-rds-options.png" /&gt;
&lt;/div&gt;
&lt;p&gt;Now hit Create and your instance will launch with the snapshot data.&lt;/p&gt;
&lt;h2&gt;Hey Presto!&lt;/h2&gt;
&lt;p&gt;You should not be able now connect to your RDS instance using the details on the Connectivity Pane when clicking on your RDS instance in the list. Hopefully you found this helpful!&lt;/p&gt;
&lt;p&gt;Make sure to tear down this access after you finish using it as it is by no means secure. It should purely be used for grabbing data retrospectively if a client requests it.&lt;/p&gt;</description><author/><pubDate>Mon, 21 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/using-rds-snapshots/</guid></item><item><title>Improving Koru's API Performance</title><link>/api-performance/</link><description>&lt;p&gt;If you don't know already - I love performance. It solves a genuine frustration for users and provides meaty problems to sink your teeth into. Koru's API performance was a little lacking since we had added a lot of features, rewritten large swaths of code and generally not thought about it, since our system is not dependant on returning results quickly. Never the less, we chose to do some performance improvement primarily aimed at reducing database load. This work was in preparation for moving to a multi-tenant architecture. When the move to a central database cluster is complete, reducing database load for each endpoint will be critical to ensure that we continue to have acceptable response times.&lt;/p&gt;
&lt;p&gt;This work is still largely on going but here I'll discuss some of the foundation work we have done.&lt;/p&gt;
&lt;h2&gt;Gathering Data&lt;/h2&gt;
&lt;p&gt;Firstly, we started by collecting data on query performance in our system. We don't use an application performance monitoring, but this is simple enough by attaching onto the &lt;code&gt;receive&lt;/code&gt; &lt;a href="http://vitaly-t.github.io/pg-promise/global.html#event:receive"&gt;event on the PG Promise constructor&lt;/a&gt;. We then want to report queries that take over 500ms into Slack so that we can then focus our attention on them.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;const pg = pgPromise({
  // {... other options }
  receive: async (data, result, e) =&amp;gt; {
    winston.debug(
      `${e.query} received ${result.rowCount} row(s) in ${result.duration}ms`
    );

    if (result.duration &amp;amp;&amp;amp; result.duration &amp;gt;= 500) {
      await Slack.reportSlowQuery(e.query, result.rowCount, result.duration);
    }
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This sends the query, the amount of rows it returned and the duration of the query to a Slack webhook which then produces a message like this:&lt;/p&gt;
&lt;div class="image"&gt;
	&lt;img alt="slow query slack message sample" src="../../assets/images/slackmessage.png" /&gt;
&lt;/div&gt;
&lt;p&gt;Ok, so now we've got a steady stream of slow queries coming into our system! 🎉&lt;/p&gt;
&lt;h2&gt;Optimization&lt;/h2&gt;
&lt;p&gt;Quickly, we began to see a pattern. Most of the queries that were reported as slow contained two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;WHERE&lt;/code&gt; clause on the clients ID - added for prevention of accessing other clients resources&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;ORDER BY&lt;/code&gt; of a property within a &lt;code&gt;JSONB&lt;/code&gt; object&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first was a fairly easy change, simply add an index on the client ID column.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;CREATE UNIQUE INDEX IF NOT EXISTS client_id_key ON clients USING BTREE (client_id);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm still unsure why we hadn't got an index here before, but I put it down to the fact that there was very little in the way of cross-client security. It was as if the system said &amp;quot;well you're authenticated so have what you want!&amp;quot;. Thankfully, we have long since added these protections.&lt;/p&gt;
&lt;p&gt;The second was a little more of a challenge. Initially, I began by looking up if it was possible to create an index on a certain property of a JSON structure or if you instead had to create just an index on the entire column.&lt;/p&gt;
&lt;p&gt;Soon I discovered it was possible! But there was a lot of conflicting advise as to whether it actually improved query performance or not and if the building of the index netted a performance negative.&lt;/p&gt;
&lt;p&gt;Anyway, I decided to create the index like this&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;CREATE INDEX candidate_response_score_indx ON responses((data-&amp;gt;&amp;gt;'score'));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This took down the average query time from around 885ms to 7ms 🚀&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There is still many more queries to improve the performance of but this was a great start. It taught me a lot about the internals of Postgres and experimentation.&lt;/p&gt;
&lt;h2&gt;Takeaways&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Learn but don't be afraid to experiment - there becomes a point with learning that the best way to see if something will be a positive change or not, is to just try it out&lt;/li&gt;
&lt;li&gt;&amp;quot;Reckons&amp;quot; don't always reflect reality - I believed there was lots of performance improvements to be made in a number of common operations but after trying the queries out and collecting data, they were already very performant. Therefore, be more data driven rather than &amp;quot;reckon&amp;quot; driven, even if those assumptions point you in the general direction.&lt;/li&gt;
&lt;/ol&gt;</description><author/><pubDate>Mon, 21 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/api-performance/</guid></item><item><title>[Computing] Serial Attached SCSI (SAS) is a circuit switched computer network</title><link>https://www.devever.net/~hl/sas</link><description>&lt;p&gt;(You may wish to read &lt;a href="scsi"&gt;A brief introduction to SCSI&lt;/a&gt; before reading this article.)&lt;/p&gt;</description><author>devever.net/~hl</author><pubDate>Sun, 20 Sep 2020 22:31:00 GMT</pubDate><guid isPermaLink="true">https://www.devever.net/~hl/sas</guid></item><item><title>A Bazel Persistent Worker for Rust</title><link>https://nikhilism.com/post/2020/bazel-persistent-worker-rust/</link><description>Bazel persistent workers are a cool feature that allow Bazel to start up &amp;ldquo;compiler&amp;rdquo; instances that can accept multiple build requests. This brings benefits like saving startup time, saving the time to parse a standard library or share some cache across compiler invocations. This allows slight speedups in rebuilds, which can be valuable in speeding up the developer iteration cycle.
This is best exemplified in the existing persistent workers:
The Java and Scala rules benefit from paying the cost of process startup only once (warming up the JVM and so on.</description><author>Nikhil's blog</author><pubDate>Sun, 20 Sep 2020 22:09:41 GMT</pubDate><guid isPermaLink="true">https://nikhilism.com/post/2020/bazel-persistent-worker-rust/</guid></item><item><title>Dune</title><link>https://apurva-shukla.me/bookshelf/dune/</link><description>⭐ ⭐ ⭐ ⭐ ⭐ This book is indescribable.

The harsh worlds and realities that Herbert presents intertwined with a inter-galactic feudalism, a…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Sun, 20 Sep 2020 16:51:31 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/bookshelf/dune/</guid></item><item><title>Connecting R53 With External Domains</title><link>https://prashamhtrivedi.in/connecting_r53_external_domains.html</link><description>In this article, we will see how we can use AWS&amp;rsquo; Route 53 to connect with external domains and serve static S3 website.</description><author>Prasham H Trivedi</author><pubDate>Sun, 20 Sep 2020 09:47:31 GMT</pubDate><guid isPermaLink="true">https://prashamhtrivedi.in/connecting_r53_external_domains.html</guid></item><item><title>2020-09-20</title><link>https://ho.dges.online/pictures/2020-09-20/</link><description/><author>ho.dges.online</author><pubDate>Sun, 20 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/pictures/2020-09-20/</guid></item><item><title>Our New Species (Part 1/2)</title><link>http://spirals.blog/articles/our-new-species-pt-1/</link><description>&lt;div class="toc"&gt;
This is part one of this story. &lt;a href="http://spirals.blog/articles/our-new-species-pt-2"&gt;You can read part two here!&lt;/a&gt;
&lt;/div&gt;
&lt;h2&gt;The Age of the Spiritual Machine&lt;/h2&gt;
&lt;h3&gt;Boot Sequence&lt;/h3&gt;
&lt;p&gt;A softly toned, analog alarm pierced the quiet of Harrison’s city apartment. His forgotten dreams slipped through the cracks as his consciousness took over to start the day. Just another day.&lt;/p&gt;
&lt;p&gt;He sighed, rolling out of bed, and switched on his phone. The morning ritual’s feed sprung to life with a firehose of ads, notifications, software updates, and Twitter notifications – all masquerading with self-importance.&lt;/p&gt;
&lt;p&gt;Harrison scrolled through, filtering for anything important, or messages from loved ones. Amid the stupid tweet recommendations and ancient newsletters he really ought to unsubscribe from, a Calendar notification caught his eye.” Meeting reminder: Lunch with Jacob @ 12pm”. He was looking forward to this.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Stepping into the shower, he welcomed the hot water to wash away an average night’s sleep. Showers were his sanctuary, a private oasis to think, generate ideas, and relax without any distractions or Slack messages.&lt;/p&gt;
&lt;p&gt;His mind booted up. He hadn’t seen anything in the mornings feed regarding his application for the Neuralink surgery. He grew anxious; it was just over a week since they said they would get back to him, and there was still radio-silence.&lt;/p&gt;
&lt;p&gt;Feelings of jealousy arose with painful thoughts of his fellow programming colleague who’d recently received a Neuralink. Already, in the two weeks since he’d had the surgery, his co-worker had rebuilt the entire API service for his department, learned sales, marketing, and was now championing technical client relations. All with a new paycheck and high-praise from the CEO, of course.&lt;/p&gt;
&lt;p&gt;Harrison was still stuck as a QA engineer, left to do the manual human testing of the AI’s complicated work. Despite the consistent late-night studying, algorithm practice, and competition submissions, he was only just managing to stay afloat at his job. 5 years ago, he had a high paying role as a senior engineer, but some things had changed in the past few years. It was hard to keep up.&lt;/p&gt;
&lt;p&gt;A temporary blast of cold water shattered his stream of thought. He dried off in the kitchen and put on a brew of Golden Teacher mushroom tea. It had been 3 years since psychedelic psilocybin mushrooms had been approved for legal, personal use. Harrison brewed them daily. It was not enough to feel anything or create any hallucinations. The tea gave Harrison a necessary, though only slight, edge in the competition with the Connies. Others had also embraced the “natural augmentation” that psilocybin offered, eager for anything to expand the mind and stay relevant amongst the chaos. An increasingly common blend of techno-spirituality and psychonaut techniques permeated Harrison’s online social network.&lt;/p&gt;
&lt;p&gt;Since the “Linked Revolution”, a “Connie” was a nick-name for those fortunate enough to afford and receive the Neuralink surgery. They were a different kind. The “Linked Revolution” took the world by storm. An increasing number of professionals, creatives, investors, business-people, and politicians itching to get the implant. They couldn’t build the installation machines fast enough.&lt;/p&gt;
&lt;p&gt;The world underwent vast sweeping changes as the bandwidth between humans and machines exploded by several orders of magnitude. A bridge for humanity and AI to co-exist. Human 2.0.&lt;/p&gt;
&lt;p&gt;Nothing was the same. Harrison sipped his tea.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Harrison’s best friend was his ryukin goldfish, Alice. The pair had a simple relationship, and he liked it that way. Harrison would talk, and she would listen. She was good at that.&lt;/p&gt;
&lt;p&gt;He stood there in his towel, staring into her large bowl, watching her circle aimlessly.&lt;/p&gt;
&lt;p&gt;“Are we still relevant, you and I, Alice?”&lt;/p&gt;
&lt;p&gt;She bubbled in response.&lt;/p&gt;
&lt;p&gt;Harrison wondered if &lt;em&gt;normal&lt;/em&gt; humans and goldfish had grown more alike over the past few years.&lt;/p&gt;
&lt;p&gt;“Are we trapped to the confines of a watery sphere? At the mercy of a greater force, one that can expand beyond the physical constraints of our world? Is our entire existence defined by the chance that they forget to feed us one day?”&lt;/p&gt;
&lt;p&gt;He chewed his lip and concluded the tea was kicking in.&lt;/p&gt;
&lt;p&gt;“Good chat Alice.”&lt;/p&gt;
&lt;p&gt;Harrison cleaned his mug, slipped on his freshly washed jeans, and put on a WWDC 2030 shirt from earlier this year. The years alone at a computer all day and night had not done wonders for his health, and the jeans were a bit too tight. He opened Tesla Fetch on his phone and ordered a ride to his usual cafe spot in the city.&lt;/p&gt;
&lt;p&gt;Running downstairs, he bumped into his neighbor, an old-lady chatting away on FaceTime to her grandchildren in Bali.&lt;/p&gt;
&lt;p&gt;“Oh, Harrison, dear! Say hello to my oldest grandchild, Namibia. She’s in Bali, you know?” the old-lady enthused.&lt;/p&gt;
&lt;p&gt;“Bali? That’s a dangerous place to be,” Harrison squinted at the tiny screen she was thrusting in his face, “How are things down there?”&lt;/p&gt;
&lt;p&gt;“We’re here to enjoy the last of it before it goes under,” Namibia sighed, “Doing what we can to help the locals, you know?” She seemed sad.&lt;/p&gt;
&lt;p&gt;Harrison worked for a startup, Rising Tide, that provided AI relocation assistance for struggling islanders. The thought of being in Bali right now made him queasy.&lt;/p&gt;
&lt;p&gt;“Ah, ok. Well, look after yourself!” and he darted down the remaining stairs into the tiny backstreet of his city. Strangers weren’t his strong suit.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;After a quick glance at Fetch, it told him the ride was still a few minutes away. Instead, he opened HackerNews and leaned against the wall as he consumed his most trusted source.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft VR Office overtakes Oculus sales with new Neuralink integration&lt;/li&gt;
&lt;li&gt;New nuclear fission plants to replace California’s solar farms&lt;/li&gt;
&lt;li&gt;SABER virus gains a second wave in South East Asia&lt;/li&gt;
&lt;li&gt;Ask HN: Best Linux distros for Neuralink/AI development?&lt;/li&gt;
&lt;li&gt;Successful Second Landing of SpaceX Mars Mission&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last one caught his eye. SpaceX had successfully established a Martian base in 2027, officially turning humans into an interplanetary species. Incredible efforts and resources were now being poured into the space industry. Transportation, energy innovation, various offshoots of spacecraft companies, asteroid mining expeditions, pirates fighting with the US Space Force; it was all very science-fiction and exciting.&lt;/p&gt;
&lt;p&gt;Unfortunately for most, the experiences of this brave new world were limited to news articles and immersive video games. Space was reserved only for those who could afford it, or smart enough to work in it. The competition for a job in space was astronomical, and a non-Connie securing a position these days was almost unheard of. Harrison day-dreamed.&lt;/p&gt;
&lt;p&gt;Not long after, the pleasant hum of the driverless, electric, Tesla Fetch zoomed into view, stopping with perfect deceleration right in front of Harrison. The doors swooshed open, and a gust of cool, conditioned air rushed to greet him as he stepped inside to sit on the comfy leather seat.&lt;/p&gt;
&lt;p&gt;In the corner, a purple-haired tween was socializing loudly with her friends on some app.&lt;/p&gt;
&lt;p&gt;“OMG, did you see her new TikTok video? I was like, ummmm, who are you trying to be, you know? Like, don’t pretend to do your own content when you’re just copying me. Be original, bitch. What? Oh yeah, I know. Yep. Mhm. She’s so fake. And it only got like 3 likes, so whatever. Mine got like, 300. Anyway, so what did you tell Ryan last night?”&lt;/p&gt;
&lt;p&gt;There was another passenger, however, that intrigued Harrison much more. The strongly-built, middle-aged man was dressed only in black, sporting heavy boots, tinted sunglasses, and an expensive suit. His short brown hair was contrasted by his clenched, freshly-shaved jawline and tight lips. The air felt colder around him, and he seemed to exude a sense of danger and anger. He didn’t move a muscle as Harrison pulled out his phone, and the doors closed with a click.&lt;/p&gt;
&lt;p&gt;“We’ll be ignoring him,” Harrison thought, uncomfortably resuming the perusal of today’s updates. The Fetch was speeding quickly through the city and took a slight turn, down into one of the city’s tunnel openings. The new underground system was AI-Designed, created by analyzing traffic patterns over the years. AI identified the most common routes and destinations people took, and humans drilled the tunnels. It was extremely efficient. Virtually nobody owned a car anymore, let alone drove – traffic was an issue of the past.&lt;/p&gt;
&lt;p&gt;Harrison lamented on the hours he used to spend driving to the corporate office. All that wasted time, and for what? Since COVID, everything went remote, and the world had never looked back. SABER virus had only deepened the new workflow.&lt;/p&gt;
&lt;p&gt;The Telsa slowed, stopping outside a mysterious, unmarked brick building. The agent (as Harrison supposed he must have been) promptly stepped out, without a sliver of expression, and entered the two reinforced steel doors of the building. Good riddance. Miss Tween was still happily gossiping away.&lt;/p&gt;
&lt;p&gt;Harrion’s phone buzzed, notifying him he would arrive in a few minutes. 2 article headlines later, and they pulled up at The Electric Fig.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;The Electric Fig&lt;/h3&gt;
&lt;p&gt;The tiny, hipster cafe was wedged in an alley between two gigantic skyscrapers, barely seeing the sun. It opened up to the street with a giant floor to ceiling window, inviting busy passerby’s in with scents of fresh, 4th wave coffee and down-tempo jungle beats. Harrison stepped through the open door, waving at some of the staff, and tiptoed his way past potted plants and laptop chargers. His regular seat was at the very back.&lt;/p&gt;
&lt;p&gt;As usual, the energy was palpable, with the tiny room stuffed full of other remoters, designers, devs, and bloggers. He was grateful for his noise-canceling headphones. A few other regulars he knew smiled at him from their conference calls.&lt;/p&gt;
&lt;p&gt;Harrison made his way to the counter and was met with an unfamiliar, pretty face. He felt the butterflies in his stomach as he stumbled over his words.&lt;/p&gt;
&lt;p&gt;“Hey, ugh, you new here?” Great. What a line idiot.&lt;/p&gt;
&lt;p&gt;“Yeah I am,” she smiled, she had a happy voice, “Just started today”&lt;/p&gt;
&lt;p&gt;Harrison glanced at her name tag, “Ugh, Khaleesi? Nice name”&lt;/p&gt;
&lt;p&gt;“Yeah,” she sighed, and seemed annoyed he’d said anything, “My parents are real fun. Most people just call me Kali”&lt;/p&gt;
&lt;p&gt;“Oh, yeah, sorry. I’m a big fan, but yeah. Nice to meet you Kali” Why was talking to girls so hard? “Umm, can I get a cappuccino, please? No sugar”&lt;/p&gt;
&lt;p&gt;“Sure”, she fumbled with the kiosk, “I’ll bring it out to you”&lt;/p&gt;
&lt;p&gt;Harrison’s mind flooded with the million different ways he could have handled that interaction better. Returning to his table, he mumbled to himself. “Maybe I should renew my gym subscription” he thought.&lt;/p&gt;
&lt;p&gt;He opened his laptop, Chrome, and Google meets to join his companies daily standup. He yawned; these meetings were always dull.&lt;/p&gt;
&lt;p&gt;“Hi team!” His manager, Augustine, was annoyingly chipper, but today seemed especially intense, “How was everyone’s weekend?”&lt;/p&gt;
&lt;p&gt;His team gave a half-hearted response, and those game enough turned on their mic to offer a “Good thanks”, or a “Yeah, alright”. Go, team.&lt;/p&gt;
&lt;p&gt;Rising Tide was a relatively new startup, only founded in the last two years. The founder was a Jamaican refugee who was forced to leave his country with his family due to sea levels reducing the island’s capacity. He met the CTO in a holding camp near Toronto, and the pair decided to join forces to tackle the severe issue.&lt;/p&gt;
&lt;p&gt;Harrison zoned out, opening a separate tab to check some of his favorite subreddits, and his mind drifted. He wondered about his lunch with Jacob today. He’d never met him in person, only on Twitch. What intrigued Harrison mostly was that Jacob claimed to be a Connie. What would he think of Harrison?&lt;/p&gt;
&lt;p&gt;“Harrison? You still with us?” Augustine broke his focus.&lt;/p&gt;
&lt;p&gt;“Oh, yeah, sorry, mic problems” he lied. “Uhh today I’m fixing that issue with the invalid tokens being sent to the client”&lt;/p&gt;
&lt;p&gt;Augustine didn’t seem convinced, but Harrison wasn’t sure if it was an internet lag.&lt;/p&gt;
&lt;p&gt;“Ok, thanks, Harrison. Have a great day everyone” The call ended with a patronizing chime.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Harrison couldn’t concentrate. Between the upcoming lunch, the boredom of his Jira tickets, and the frustrations of his interaction with Kali, he was distracted. The code in front of him blurred into colorful blobs, dancing in front of his eyes, taunting Harrison with its declarations, control flows, and loops. An artificially generated soup of complexity.&lt;/p&gt;
&lt;p&gt;The mushrooms weren’t helping today, at least not for this.&lt;/p&gt;
&lt;p&gt;Had coding shifted along with everything else over the last few years? With the Connies and their AI generating most of the code more often, how was a human supposed to keep up?&lt;/p&gt;
&lt;p&gt;“It’s not like I’m dumb” Harrison complained to a small Telegram group of other programmer friends, “I spend so much time studying this shit. Are you guys struggling with this too?”&lt;/p&gt;
&lt;p&gt;His message was seen by several, and gained a couple of thumbs-up emojis. Harrison was encouraged that he wasn’t the only one. Mindlessly, he opened up Gmail to check if there was any Neuralink update. Still nothing.&lt;/p&gt;
&lt;p&gt;A Slack question from a more junior co-worker sucked him back into his work. The unique blend of caffeine and psilocybin was in full effect as he forced himself to zone in and be useful. He disabled his notifications so he could program in peace and spend the next few hours debugging.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;By the time his Calendar reminded him it was time to leave, Harrison was well on his way, packed to go. He paid, waved awkwardly at Kali, and returned to the now empty, cold street. The sunlight valiantly sought for any small break between the skyscrapers, providing patches of illumination before returning to the darkness of steel, cement, and glass. Harrison reached the end of the street and turned left, the sky breaking out to a view of the lake. He enjoyed this walk, and today there was a spring in his step.&lt;/p&gt;
&lt;p&gt;Jacob had suggested they meet at an upmarket lunch bistro that Harrison had never heard of. Google Maps told him it was a 22-minute walk, so he resumed an episode of the Joe Rogan Experience. Joe’s current guest was a Seargent of the Martian Space Core, discussing an ongoing referendum for Martian independence. Recent political tensions over trade agreements between Euro-Chinese leaders and the Martian settlers were a hot topic.&lt;/p&gt;
&lt;p&gt;The Sergeant’s argument was that Earth was demanding too many critical minerals to be shipped on returning voyages – minerals that Mars needed. Mid 2025, a global state of emergency introduced heavy international rations on precious metals running out. There were insufficient physical resources to supplement the titanic consumption of energy produced by non-renewables with solar or wind. Despite the cultural perspective on nuclear fission opening to more research and deployments, we were not moving fast enough. Asteroids, though rich in assets, were an expensive and risky operation. Mars was ripe for the picking to sate Earth’s hunger.&lt;/p&gt;
&lt;p&gt;The breezy bike-path along the lake gave way to chic, elegant architecture, stylish murals, and groomed hedge-trees. The people here dressed differently, and nobody said a word—Connie territory.&lt;/p&gt;
&lt;p&gt;Harrison had arrived.&lt;/p&gt;
&lt;div class="toc" style="text-align: center;"&gt;
  To be continued…
  &lt;br /&gt;
  &lt;a href="http://spirals.blog/articles/our-new-species-pt-2"&gt;👉 You can read part two here! 👈 &lt;/a&gt;
&lt;/div&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 20 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/our-new-species-pt-1/</guid></item><item><title>The Mysterious Keka Slider</title><link>https://xavd.id/blog/post/mysterious-keka-slider/</link><description>A quick dive comparing relative effectiveness different compression speeds and formats.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://xavd.id/blog/post/mysterious-keka-slider/"&gt;Read the whole thing&lt;/a&gt;.</description><author>The David Brownman Blog</author><pubDate>Sun, 20 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xavd.id/blog/post/mysterious-keka-slider/</guid></item><item><title>2020–09–20: Downsizing the multi-boot image</title><link>https://xnux.eu/log/#019</link><author>megi's PinePhone Development Log</author><pubDate>Sun, 20 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#019</guid></item><item><title>2020–09–20: Some ways to improve Pinephone safety</title><link>https://xnux.eu/log/#018</link><author>megi's PinePhone Development Log</author><pubDate>Sun, 20 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#018</guid></item><item><title>About too much work being pointless</title><link>https://stop.zona-m.net/2020/09/about-too-much-work-being-pointless/</link><description>&lt;p&gt;Is it still work, if it damages society?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 19 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/about-too-much-work-being-pointless/</guid></item><item><title>Novelty Makes Novices</title><link>https://peterlyons.com/problog/2020/09/novelty-makes-novices/</link><description>&lt;p&gt;My experience in the last decade have been that software developers are asked to learn new technologies with such frequency that novice level skills have become a semi-permanent norm that is expected and accepted.&lt;/p&gt;
&lt;p&gt;Here's some technologies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;clojure&lt;/li&gt;
&lt;li&gt;edn&lt;/li&gt;
&lt;li&gt;kotlin&lt;/li&gt;
&lt;li&gt;maven&lt;/li&gt;
&lt;li&gt;VS Code&lt;/li&gt;
&lt;li&gt;vim&lt;/li&gt;
&lt;li&gt;elasticsearch&lt;/li&gt;
&lt;li&gt;kafka&lt;/li&gt;
&lt;li&gt;kafka connect&lt;/li&gt;
&lt;li&gt;kafka streams&lt;/li&gt;
&lt;li&gt;mongodb replication&lt;/li&gt;
&lt;li&gt;event sourcing, change data capture architecture, CQRS&lt;/li&gt;
&lt;li&gt;avro&lt;/li&gt;
&lt;li&gt;graphql&lt;/li&gt;
&lt;li&gt;graphql schema delegation&lt;/li&gt;
&lt;li&gt;apollojs&lt;/li&gt;
&lt;li&gt;nextjs&lt;/li&gt;
&lt;li&gt;postgresql ltree plugin&lt;/li&gt;
&lt;li&gt;yarn&lt;/li&gt;
&lt;li&gt;advanced circleci configuration&lt;/li&gt;
&lt;li&gt;advanced docker&lt;/li&gt;
&lt;li&gt;mozilla sops&lt;/li&gt;
&lt;li&gt;kustomize&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Is that list everything I've used in my 20 years in the industry? No! That's just tech I had to learn and use in my 18 months at Reaction Commerce! That's more than one each month. Alomst every one of these represents "probably should read at least 1 whole book on this" depth.&lt;/p&gt;
&lt;p&gt;Then of course we go through an acquisition and our tech stack changes pretty much completely. 2 new programming languages, 2 new databases, a new public cloud, a new RPC system, in-house frameworks and libraries, and so on.&lt;/p&gt;
&lt;p&gt;In terms of my personal job satisfaction, I'm hoping that now that the acquisition transition is pretty much complete, I'll start to have at least a few stable bits of my tech stack: mostly the same DBs, programming languages, and cloud managed services. I enjoy doing work with intermediate or advanced skills a lot more than I enjoy learning new things and fumbling around as a novice. Of course others will crave and flourish with a series of new stuff to learn in a cursory way.&lt;/p&gt;
&lt;p&gt;Thinking more broadly, I have some vague concerns about this might have an indirect causal relationship with the generally terrible state of technology at large, but I have no way to really test this, and the even second level more cynical side of me suspects maybe even if expert implementations were the norm, tech would still be mostly terrible because we don't really care about making it good.&lt;/p&gt;</description><author>Pete's Points</author><pubDate>Sat, 19 Sep 2020 19:07:15 GMT</pubDate><guid isPermaLink="true">https://peterlyons.com/problog/2020/09/novelty-makes-novices/</guid></item><item><title>Martin Schlachter and Justina Tschosick</title><link>https://www.davidschlachter.com/misc/martin-schlachter-justina-tschosick</link><description>Everything I know about my great-great-great grandparents Martin Schlachter and Justina Tschosick.</description><author>David Schlachter</author><pubDate>Sat, 19 Sep 2020 15:30:00 GMT</pubDate><guid isPermaLink="true">https://www.davidschlachter.com/misc/martin-schlachter-justina-tschosick</guid></item><item><title>Emacs: search/play Music (macOS)</title><link>https://xenodium.com/emacs-searchplay-music-macos</link><description>&lt;p&gt;While trying out macOS's Music app to manage offline media, I wondered if I could easily search and control playback from Emacs. Spoiler alert: yes it can be done and fuzzy searching music is rather gratifying.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-searchplay-music-macos/music_search.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Luckily, the hard work's already handled by &lt;a href="https://github.com/hile/pytunes"&gt;pytunes&lt;/a&gt;, a command line interface to macOS's iTunes/Music app. We add &lt;a href="https://ffmpeg.org/ffprobe.html"&gt;ffprobe&lt;/a&gt; and some elisp glue to the mix, and we can generate an Emacs media index.&lt;/p&gt;
&lt;p&gt;Indexing takes roughly a minute per 1000 files. Prolly suboptimal, but I don't intend to re-index frequently. For now, we can use a separate process to prevent Emacs from blocking, so we can get back to playing tetris from our beloved editor:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun musica-index ()
  &amp;quot;Indexes Music's tracks in two stages:
1. Generates \&amp;quot;Tracks.sqlite\&amp;quot; using pytunes (needs https://github.com/hile/pytunes installed).
2. Caches an index at ~/.emacs.d/.musica.el.&amp;quot;
  (interactive)
  (message &amp;quot;Indexing music... started&amp;quot;)
  (let* ((now (current-time))
         (name &amp;quot;Music indexing&amp;quot;)
         (buffer (get-buffer-create (format &amp;quot;*%s*&amp;quot; name))))
    (with-current-buffer buffer
      (delete-region (point-min)
                     (point-max)))
    (set-process-sentinel
     (start-process name
                    buffer
                    (file-truename (expand-file-name invocation-name
                                                     invocation-directory))
                    &amp;quot;--quick&amp;quot; &amp;quot;--batch&amp;quot; &amp;quot;--eval&amp;quot;
                    (prin1-to-string
                     `(progn
                        (interactive)
                        (require 'cl-lib)
                        (require 'seq)
                        (require 'map)

                        (message &amp;quot;Generating Tracks.sqlite...&amp;quot;)
                        (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;update-index&amp;quot;) ;; Generates Tracks.sqlite
                        (message &amp;quot;Generating Tracks.sqlite... done&amp;quot;)

                        (defun parse-tags (path)
                          (with-temp-buffer
                            (if (eq 0 (call-process &amp;quot;ffprobe&amp;quot; nil t nil &amp;quot;-v&amp;quot; &amp;quot;quiet&amp;quot;
                                                    &amp;quot;-print_format&amp;quot; &amp;quot;json&amp;quot; &amp;quot;-show_format&amp;quot; path))
                                (map-elt (json-parse-string (buffer-string)
                                                            :object-type 'alist)
                                         'format)
                              (message &amp;quot;Warning: Couldn't read track metadata for %s&amp;quot; path)
                              (message &amp;quot;%s&amp;quot; (buffer-string))
                              (list (cons 'filename path)))))

                        (let* ((paths (process-lines &amp;quot;sqlite3&amp;quot;
                                                     (concat (expand-file-name &amp;quot;~/&amp;quot;)
                                                             &amp;quot;Music/Music/Music Library.musiclibrary/Tracks.sqlite&amp;quot;)
                                                     &amp;quot;select path from tracks&amp;quot;))
                               (total (length paths))
                               (n 0)
                               (records (seq-map (lambda (path)
                                                   (let ((tags (parse-tags path)))
                                                     (message &amp;quot;%d/%d %s&amp;quot; (setq n (1+ n))
                                                              total (or (map-elt (map-elt tags 'tags) 'title) &amp;quot;No title&amp;quot;))
                                                     tags))
                                                 paths)))
                          (with-temp-buffer
                            (prin1 records (current-buffer))
                            (write-file &amp;quot;~/.emacs.d/.musica.el&amp;quot; nil))))))
     (lambda (process state)
       (if (= (process-exit-status process) 0)
           (message &amp;quot;Indexing music... finished (%.3fs)&amp;quot;
                    (float-time (time-subtract (current-time) now)))
         (message &amp;quot;Indexing music... failed, see %s&amp;quot; buffer))))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once media is indexed, we can feed it to &lt;a href="https://github.com/abo-abo/swiper"&gt;ivy&lt;/a&gt; for that narrowing-down fuzzy-searching goodness! It's worth mentioning the &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Size-of-Displayed-Text.html"&gt;truncate-string-to-width&lt;/a&gt; function. Super handy for truncating strings to a fixed width and visually organizing search results in columns.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun musica-search ()
  (interactive)
  (cl-assert (executable-find &amp;quot;pytunes&amp;quot;) nil &amp;quot;pytunes not installed&amp;quot;)
  (let* ((c1-width (round (* (- (window-width) 9) 0.4)))
         (c2-width (round (* (- (window-width) 9) 0.3)))
         (c3-width (- (window-width) 9 c1-width c2-width)))
    (ivy-read &amp;quot;Play: &amp;quot; (mapcar
                        (lambda (track)
                          (let-alist track
                            (cons (format &amp;quot;%s   %s   %s&amp;quot;
                                          (truncate-string-to-width
                                           (or .tags.title
                                               (file-name-base .filename)
                                               &amp;quot;No title&amp;quot;) c1-width nil ?\s &amp;quot;…&amp;quot;)
                                          (truncate-string-to-width (propertize (or .tags.artist &amp;quot;&amp;quot;)
                                                                                'face '(:foreground &amp;quot;yellow&amp;quot;)) c2-width nil ?\s &amp;quot;…&amp;quot;)
                                          (truncate-string-to-width
                                           (propertize (or .tags.album &amp;quot;&amp;quot;)
                                                       'face '(:foreground &amp;quot;cyan1&amp;quot;)) c3-width nil ?\s &amp;quot;…&amp;quot;))
                                  track)))
                        (musica--index))
              :action (lambda (selection)
                        (let-alist (cdr selection)
                          (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;play&amp;quot; .filename)
                          (message &amp;quot;Playing: %s [%s] %s&amp;quot;
                                   (or .tags.title
                                       (file-name-base .filename)
                                       &amp;quot;No title&amp;quot;)
                                   (or .tags.artist
                                       &amp;quot;No artist&amp;quot;)
                                   (or .tags.album
                                       &amp;quot;No album&amp;quot;)))))))

(defun musica--index ()
  (with-temp-buffer
    (insert-file-contents &amp;quot;~/.emacs.d/.musica.el&amp;quot;)
    (read (current-buffer))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The remaining bits are straigtforward. We add a few interactive functions to control playback:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun musica-info ()
  (interactive)
  (let ((raw (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;info&amp;quot;)))
    (message &amp;quot;%s [%s] %s&amp;quot;
             (string-trim (string-remove-prefix &amp;quot;Title&amp;quot; (nth 3 raw)))
             (string-trim (string-remove-prefix &amp;quot;Artist&amp;quot; (nth 1 raw)))
             (string-trim (string-remove-prefix &amp;quot;Album&amp;quot; (nth 2 raw))))))

(defun musica-play-pause ()
  (interactive)
  (cl-assert (executable-find &amp;quot;pytunes&amp;quot;) nil &amp;quot;pytunes not installed&amp;quot;)
  (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;play&amp;quot;)
  (musica-info))

(defun musica-play-next ()
  (interactive)
  (cl-assert (executable-find &amp;quot;pytunes&amp;quot;) nil &amp;quot;pytunes not installed&amp;quot;)
  (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;next&amp;quot;))

(defun musica-play-next-random ()
  (interactive)
  (cl-assert (executable-find &amp;quot;pytunes&amp;quot;) nil &amp;quot;pytunes not installed&amp;quot;)
  (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;shuffle&amp;quot; &amp;quot;enable&amp;quot;)
  (let-alist (seq-random-elt (musica--index))
    (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;play&amp;quot; .filename))
  (musica-info))

(defun musica-play-previous ()
  (interactive)
  (cl-assert (executable-find &amp;quot;pytunes&amp;quot;) nil &amp;quot;pytunes not installed&amp;quot;)
  (process-lines &amp;quot;pytunes&amp;quot; &amp;quot;previous&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, if we want some convenient keybindings, we can add something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(global-set-key (kbd &amp;quot;C-c m SPC&amp;quot;) #'musica-play-pause)
(global-set-key (kbd &amp;quot;C-c m i&amp;quot;) #'musica-info)
(global-set-key (kbd &amp;quot;C-c m n&amp;quot;) #'musica-play-next)
(global-set-key (kbd &amp;quot;C-c m p&amp;quot;) #'musica-play-previous)
(global-set-key (kbd &amp;quot;C-c m r&amp;quot;) #'musica-play-next-random)
(global-set-key (kbd &amp;quot;C-c m s&amp;quot;) #'musica-search)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hooray! Controlling music is now an Emacs keybinding away: ø/&lt;/p&gt;
&lt;p&gt;comments on &lt;a href="https://twitter.com/xenodium/status/1307294369326731264"&gt;twitter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UPDATE1: Installing pytunes with &lt;em&gt;pip3 install pytunes&lt;/em&gt; didn't just work for me. Instead, I cloned and installed as:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;git clone https://github.com/hile/pytunes
pip3 install file:///path/to/pytunes
pip3 install pytz
brew install libmagic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UPDATE2: Checked in to &lt;a href="https://github.com/xenodium/dotsies/blob/master/emacs/ar/musica.el"&gt;dot files&lt;/a&gt;.&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sat, 19 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-searchplay-music-macos</guid></item><item><title>On school improvement</title><link>https://nutcroft.mataroa.blog/blog/on-school-improvement/</link><description>&lt;p&gt;Few would disagree that the educational system of the —so-called— Western world &lt;a href="/blog/whats-wrong-with-school/"&gt;could be improved&lt;/a&gt;. Eight partially concrete concepts on a potential improvement follow.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Less information. Slash the amount of information included in the courses. Aim to keep the essence, the fundamentals, the knowledge that a student is expected to either remember 10 years later or to have been &lt;a href="http://www.paulgraham.com/know.html"&gt;influenced by it&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More humanities and art. There are many forms of art, and even the simplest change of dedicating a couple of hours per week on those would be beneficial (yet admittedly crude).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;More bodily knowledge. The importance of physical activity both for physical health but also for psychological health cannot be overstated. More classes of exercising and sports is an easy first step.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Teacher quality assessment by students. Students are the essence and purpose of the whole operation. How could we not deeply value their impressions?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Teacher freedom. Teaching and learning are creative processes in their very core. If a teacher is micromanaged by laws on how to teach, then learning will probably not happen; only a knowledge auditory event will.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;De-professionalise teaching. Accomplished educationalists &lt;a href="https://www.ted.com/talks/sir_ken_robinson_how_to_escape_education_s_death_valley/transcript"&gt;talk about&lt;/a&gt; this idea for quite some time. If only, it's worth a serious attempt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;School as a more integrated part of society. Let's incorporate school as part of every society member's life. Non-parent professionals can teach. Others can learn. Is there an argument for not being inclusive?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Student freedom and abolishment of mandated studying. Every time a student is graded with a failure mark in an exam it is proof that people cannot force people to learn. Let's entrust students with the responsibility to decide what to learn, when, where, and how.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;Also on this series: &lt;a href="/blog/whats-wrong-with-school/"&gt;What’s wrong with school?&lt;/a&gt;&lt;/p&gt;</description><author>nutcroft</author><pubDate>Sat, 19 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/on-school-improvement/</guid></item><item><title>How to batch resize and compress images in linux</title><link>https://shyamjos.com/batch-resize-compress-photos-linux/</link><description>&lt;p&gt;






 
 
&lt;figure&gt;&lt;img alt="retro cmaer" class="mx-auto my-0 rounded-md" src="https://shyamjos.com/assets/img/ImageMagick/retro-camera-black.jpg" /&gt;
&lt;/figure&gt;

In this tutorial I will show you how to batch resize and compress images in Ubuntu or in any other Linux distros(debian,arch and fedora).&lt;/p&gt;
&lt;p&gt;&amp;lsquo;Convert&amp;rsquo; command is a very powerful image manipulation utility which comes preinstalled in almost all Linux distributions (ubuntu,debian,arch and fedora) and it is a part of ImageMagick software suite.&lt;/p&gt;
&lt;h2 class="relative group" id="check-if-convert-command-is-available-on-your-linux-distro"&gt;Check if convert command is available on your Linux distro &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#check-if-convert-command-is-available-on-your-linux-distro"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; convert -version
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;output:&lt;/p&gt;
&lt;p&gt;Version: ImageMagick 6.9.7-4 Q16 x86_64 20170114 &lt;a href="http://www.imagemagick.org" rel="noreferrer" target="_blank"&gt;http://www.imagemagick.org&lt;/a&gt;
Copyright: © 1999-2017 ImageMagick Studio LLC&lt;/p&gt;
&lt;p&gt;If the above command is not found on your Linux distro you can install it by typing the below command.&lt;/p&gt;
&lt;h2 class="relative group" id="install-convert-tool-on-ubuntu--debian"&gt;Install convert tool on Ubuntu / Debian &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#install-convert-tool-on-ubuntu--debian"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; sudo apt-get install imagemagick
&lt;/code&gt;&lt;/pre&gt;&lt;h2 class="relative group" id="install-convert-tool-on-fedora"&gt;Install convert tool on fedora &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#install-convert-tool-on-fedora"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; sudo dnf install imagemagick
&lt;/code&gt;&lt;/pre&gt;&lt;h2 class="relative group" id="install-convert-tool-on-arch"&gt;Install convert tool on arch &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#install-convert-tool-on-arch"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;pre tabindex="0"&gt;&lt;code&gt; sudo pacman -S imagemagick
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note: &lt;em&gt;It&amp;rsquo;s always good idea take backup of your images before running convert command.&lt;/em&gt;&lt;/p&gt;
&lt;h2 class="relative group" id="batch-resize-and-compress-images-with-convert-command"&gt;Batch resize and compress images with convert command &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#batch-resize-and-compress-images-with-convert-command"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h2&gt;&lt;p&gt;Below command will resize and compress all images ending with .jpg extension in a &amp;lsquo;for loop&amp;rsquo; and save the compressed/resized image as &amp;lsquo;filename-Optimized.jpg&amp;rsquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ndash;quality :&lt;/strong&gt; this option is used to set the image compression level in percentage&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;-resize :&lt;/strong&gt; this option is used to resize the image to a given resolution , You can use -resize option with width ( -resize 1600x ) only or both width and height ( -resize 1600×900), In both cases convert command will automatically adjust the given resolution to get optimum aspect ratio so you don&amp;rsquo;t have to worry about stretched images.&lt;/p&gt;
&lt;p&gt;Note: some jpeg image extensions may end with .JPG (in capital letters) ,Since Linux is case-sensitive you may need to adjust the bash script accordingly.&lt;/p&gt;
&lt;p&gt;Open terminal and cd into the directory containing your photos and execute below command&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; mkdir photos-Optimized;for photos in *.JPG;do convert -verbose "$photos" -quality 85% -resize 1600x900 ./photos-Optimized/"$photos-Optimized.jpg"; done
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Voilà! Now you have successfully resized/compressed images, You can see the optimized images in the photos-Optimized directory.&lt;/p&gt;</description><author>Shyam Jos</author><pubDate>Sat, 19 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://shyamjos.com/batch-resize-compress-photos-linux/</guid></item><item><title>Cybersecurity in the early 1990's</title><link>https://jasoneckert.github.io/myblog/cybersecurity-in-the-90s/</link><description>&lt;p&gt;Back in the late 1980&amp;rsquo;s and early 1990&amp;rsquo;s, I remember collecting MS-DOS computer viruses. I’d download them from an online Bulletin Board System (BBS) and store them on floppy disks in compressed format to prevent them from executing. For fun, some friends and I would occasionally release them on one of our systems to see what they did, and then reinstall MS-DOS  afterwards. Most viruses didn’t do very much, but some others (e.g. BBkiller) would remove or modify the contents of files.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Sat, 19 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/cybersecurity-in-the-90s/</guid></item><item><title>Farewell Estes Park</title><link>https://adriano.fyi/posts/2020-09-19-farewell-estes-park/</link><description>&lt;p&gt;This is less about saying farewell to Estes Park than it is about a ride I&amp;rsquo;ve been eyeing for over five years. Not only did I have the wrong bike when I was here in September, 2015, but I learned that this route existed the day after I finished an out-and-back run of Trail Ridge Road on my old Giant roady. TRR is the downhill paved segment of today&amp;rsquo;s route.&lt;/p&gt;
&lt;p&gt;There are a multitude of reasons to visit this beautiful town nestled at the base of Rocky Mountain National Park. There are endless hiking trails both in and out of the park, mountain biking, tons of sport climbing routes (in fact, 18 routes literally in the downtown area), great trail running, and views for days. But at  the back of my mind, pulling into Estes Park five years after the last time, was the &lt;a href="https://gravelbikeadventures.com/2020/07/12/old-fall-river-road-groad-in-estes-park/"&gt;fall river road to trail ridge road loop&lt;/a&gt;, beginning in Estes. It&amp;rsquo;s a mixed gravel and paved route that&amp;rsquo;s known in the area as one of the greats. And indeed it is!&lt;/p&gt;
&lt;p&gt;On September 9th winter came early in Colorado, following record-setting temperatures the previous three days over Labor Day weekend. About 8 inches of snow fell down in the valley, with up to 12-16 inches falling at the top of the of the Rockies. Initially the storm sent me into an immediate panic, because both Trail Ridge Road and Fall River Road were closed &amp;ndash; possibly for the rest of the season. Neither of these are normal roads: they&amp;rsquo;re high, traverse the continental divide, and TRR holds the designation as the &amp;ldquo;highest continuously paved road in the United States&amp;rdquo;. So they&amp;rsquo;re kind of special.&lt;/p&gt;
&lt;p&gt;Immediate panic transformed into eventual delight. TRR would probably reopen, but Fall River Road would probably not. That doesn&amp;rsquo;t bode well for a ride involving Fall River Road, but It all turned out to be great news. Why? First of all the entirety of RMNP is timed-entry restricted, meaning you have to have reservation in advance to enter with a car. Bikes are open game. This means the park is more empty and with fewer cars than it &lt;em&gt;ever&lt;/em&gt; is. Secondly, gate security on a road like Fall River Road doesn&amp;rsquo;t exits, which meant I&amp;rsquo;d probably have the entire north section of the park to myself if I was willing to duck a gate and turn a blind eye to some pesky rules.&lt;/p&gt;
&lt;p&gt;
&lt;input hidden="hidden" id="zoomCheck-6d743" type="checkbox" /&gt;
&lt;label for="zoomCheck-6d743"&gt;
  &lt;img alt="The top of TT" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/sbs4yxPrdoJCabT/preview" title="The top of TRR" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;p&gt;Indeed, I&amp;rsquo;ve never been more alone in RMNP. The ride was fantastic and without a soul in sight until I peaked out at the alpine visitor&amp;rsquo;s center. I have to admit that leading into this ride I was questioning whether I still had it because I&amp;rsquo;m far from peak personal fitness. I&amp;rsquo;ve been active recently, but not 1 mile of elevation gain active. So it was a bit of a surprise to finish this climb and decent in 3.5 hours. I was harboring fears of getting turned around by the elevation and steep grade, and no longer being in my 20s. I don&amp;rsquo;t know how long my first ride of TRR took back in 2015, but it was embarrassingly longer. Helluva way to end my 5 weeks in Estes Park!&lt;/p&gt;





&lt;p&gt;Up next! I&amp;rsquo;m excited to be headed to Crested Butte bright and early tomorrow morning.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;</description><author>Adriano Caloiaro's personal blog</author><pubDate>Sat, 19 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://adriano.fyi/posts/2020-09-19-farewell-estes-park/</guid></item><item><title>An optimistic description of the Network Economy...</title><link>https://stop.zona-m.net/2020/09/an-optimistic-description-of-the-network-economy.../</link><description>&lt;p&gt;&amp;hellip;with just a few weak spots.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 18 Sep 2020 08:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/an-optimistic-description-of-the-network-economy.../</guid></item><item><title>Specify Bundler Version</title><link>https://thomascountz.com/2020/09/18/specify-bundler-version</link><description>&lt;p&gt;If you’re like me, you may have versions of both Bundler 1 and Bundler 2 installed on your system. This can make it difficult to manage different codebases.&lt;/p&gt;

&lt;p&gt;Say one requires an older version, like &lt;code class="language-plaintext highlighter-rouge"&gt;1.13.6&lt;/code&gt;. You can run the following command to install it,&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;gem install bundler -v 1.13.6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;but when you install gems,&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;bundle install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;you might end up seeing something like&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;BUNDLED WITH
   2.1.4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;in your &lt;code class="language-plaintext highlighter-rouge"&gt;Gemfile.lock&lt;/code&gt; file… which is &lt;em&gt;not&lt;/em&gt; the same as bundling with &lt;code class="language-plaintext highlighter-rouge"&gt;1.13.6&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can tell Bundler that you’d like to use a specific version of Bundler by specifying the exact version number before the command you wish to run. Like so:&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;bundle _x.x.x_ install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To install gems for your project using Bundler &lt;code class="language-plaintext highlighter-rouge"&gt;1.13.6&lt;/code&gt;, you can use this command to force Bundler to use the correct version:&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;bundle _1.13.6_ install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And you should see&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;BUNDLED WITH
   1.13.6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;at the end of your &lt;code class="language-plaintext highlighter-rouge"&gt;Gemfile.lock&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Hooray!&lt;/p&gt;</description><author>Thomas Countz</author><pubDate>Fri, 18 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thomascountz.com/2020/09/18/specify-bundler-version</guid></item><item><title>2020–09–18: Let's talk about safety of Pinephone</title><link>https://xnux.eu/log/#017</link><author>megi's PinePhone Development Log</author><pubDate>Fri, 18 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#017</guid></item><item><title>And Another Thing Wrong with Social Media...</title><link>https://one.mikro2nd.net/pages/and-another-thing-wrong-with-social-media/</link><description>One of the sources of ill we experience with social media is this constant pressure to be exellent. To be sparkly and witty and clever. To be a Special Snowflake.
Among the myriad flora and fauna inhabiting social networks, there&amp;rsquo;s that Long Tail of us who have little to say beyond chatter to our friends and acquaintances. That&amp;rsquo;s fine. It&amp;rsquo;s what we came for in the first place. And then there&amp;rsquo;s the other 5%: Those who are there to promote their businesses, their books and music, their causes and politics.</description><author>one mikro2nd</author><pubDate>Thu, 17 Sep 2020 17:57:30 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/and-another-thing-wrong-with-social-media/</guid></item><item><title>Original ErgoDox is Better than Infinity</title><link>https://peterlyons.com/problog/2020/09/original-ergodox-is-better-than-infinity/</link><description>&lt;p&gt;I own both an original ErgoDox (full hand acrylic case, from I think the 2nd massdrop) and a newer ErgoDox Infitity. The original works better for me and I wanted to share my experience and reasoning. There's a few things that are just simpler/nicer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;flashing the original just requires a paperclip button press on the top of the keyboard and 1 command in the OS&lt;/li&gt;
&lt;li&gt;Flashing the infinity is a dance of a paperclip press on the underside of one half, an OS command that requires sudo, changing a USB cable around, a second paperclip on the bottom of the other half, a second OS command, and finally putting the USB cable back.&lt;/li&gt;
&lt;li&gt;2 of the infinity USB cables have the wiggly USB 3.0 micro shape which is a pain to connect&lt;/li&gt;
&lt;li&gt;the cable connecting the 2 halves of the infinity is thicker than the ergodox's TRRS so its more of an intrusion into my desktop&lt;/li&gt;
&lt;li&gt;The infinity full-hand case has outer bottom shape isn't a straight line. There's a tiny angle and curve that makes trying to tent it near impossible vs the original where you jam a piece of all-thread into one of the bolt holes and you're done.&lt;/li&gt;
&lt;/ul&gt;</description><author>Pete's Points</author><pubDate>Thu, 17 Sep 2020 16:37:26 GMT</pubDate><guid isPermaLink="true">https://peterlyons.com/problog/2020/09/original-ergodox-is-better-than-infinity/</guid></item><item><title>Dear Computer, We Need to Talk</title><link>https://bastibe.de/2020-09-17-dear-computer-we-need-to-talk.html</link><description>&lt;p&gt;After years of using Linux on my desktop, I decided to install Windows on my computer, to get access to a few commercial photo editing applications. I'll go into my grievances with Linux later, but for now:&lt;/p&gt;
&lt;h2&gt;I tried to install Windows, you won't believe what happened next&lt;/h2&gt;
&lt;p&gt;Like I have done many times with Linux, I download a Windows image from my university, and write it to a USB drive, then reboot into the USB drive. The USB drive can't be booted. A quick internet search leads me to a Microsoft Support page on how to &lt;a href="https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/install-windows-from-a-usb-flash-drive"&gt;Install Windows from a USB Flash Drive&lt;/a&gt;, which says that&lt;/p&gt;
&lt;img src="/static/2020-09/one does not simply.jpg" style="width: 50%; padding-left: 25%;" /&gt;

&lt;p&gt;Instead, one has to format the stick as FAT32, make it &lt;em&gt;active&lt;/em&gt;, then copy the files from the image to it. So I follow the instructions and open the Disk Management program. It does not offer an option of FAT32, nor for making the partition &lt;em&gt;active&lt;/em&gt;. I settle on (inactive) exFAT instead. It doesn't boot.&lt;/p&gt;
&lt;p&gt;I switch over to Linux, where I can indeed make a FAT32 partition, and I can mark it as &lt;em&gt;bootable&lt;/em&gt;, which I take as the equivalent of &lt;em&gt;active&lt;/em&gt;. But Linux can not open the Windows image to copy the files onto the USB stick. So back to Windows, for copying the files. Except they can't be copied, because some of them are larger than 4Gb, which can't be written to a FAT32 partition. What now?&lt;/p&gt;
&lt;p&gt;While researching how to download a different version of Windows 10, I stumble upon the &lt;a href="https://www.microsoft.com/de-de/software-download/windows10"&gt;Media Creation Tool&lt;/a&gt;, which automatically downloads Windows 10 and writes it to the USB stick correctly. Why was this not pointed out in the article above? Who knows. At any rate, it works. I can finally install Windows.&lt;/p&gt;
&lt;p&gt;The installation process requires the usual dozen-or-so refusals of tracking, ads, privacy intrusions, and voice assistants. I wish I could simply reject them all at once. And then the install hangs, while &amp;quot;polishing up a few things&amp;quot;. Pressing the helpful back button, and then immediately the forward button unhangs it, and the installation completes.&lt;/p&gt;
&lt;p&gt;Next up are drivers. It feels anachronistic to have to install drivers manually in this day and age, but oh well. The new GPU driver to make screen tearing go away, a driver for my trackball to recognize the third mouse button, a wacom driver, ten or so Intel drivers of unknown utility. The trackball driver is not signed. I install it anyway. The GPU driver does not recognize my GPU and can't be installed. A quick Internet search reveals that my particular AMD/Intel GPU/CPU was discontinued from support by both AMD and Intel, and does not have a current driver. But fora suggest that up to version 20.2.1 of the AMD driver work fine. They don't, the driver crashes when I open images in my photo editor. An even older version published by Intel does work correctly. So now I am running an AMD GPU with an Intel driver from 2018.&lt;/p&gt;
&lt;img src="/static/2020-09/this is fine.png" style="width: 50%; padding-left: 25%;" /&gt;

&lt;p&gt;Installing and setting up Firefox and my photo editors works without issue, thank goodness. Emacs has a Windows installer now, which is greatly appreciated. OpenCL and network shares just work. This is why I'm installing Windows next to my Linux.&lt;/p&gt;
&lt;p&gt;But Windows is still not activated. I copy my university's product key in the appropriate text box, but hesitate: That's for Windows Enterprise, and I'd be just fine with Home. So I cancel the activation without activating. A helpful link in the activation systems sends me to the Microsoft Store to get my very own version of Windows Home for €145, which normally retails for around €95, so that's a no-go. Whatever, I'll go with my university's Enterprise edition. Except the activation box now says my product key is invalid. And the Store now literally says &amp;quot;We don't know how you got here but you shouldn't be here&amp;quot; instead of selling me Windows. After a restart it installs and activates Windows Enterprise, even though I never actually completed the activation.&lt;/p&gt;
&lt;img src="/static/2020-09/this is fine 2.jpg" style="width: 70%; padding-left: 15%;" /&gt;

&lt;p&gt;I install Git, but in order to access my Github I need to copy over my SSH key from the Linux install. Which I can't boot at the moment, because installing Windows overwrites the boot loader. This is normal. So I download Ubuntu, write it to the USB stick, boot into it, recover the bootloader, boot into my old install, reformat the stick, copy the files to the stick, boot back into Windows, and the files aren't on the stick. Tough. Boot back into Linux, copy the files onto the stick, &lt;em&gt;eject the stick&lt;/em&gt;, boot back into Windows, copy the files to the computer. Great user experience.&lt;/p&gt;
&lt;p&gt;Now that I have my SSH key, I open a Git Bash to download a project. It says my credentials are incorrect. I execute the same commands in a regular CMD instead of Git Bash, and now my credentials are correct. Obviously.&lt;/p&gt;
&lt;p&gt;There are several programs that claim to be able to read Linux file systems from Windows. They do not work. But Microsoft has just announced that you will be able to mount Linux file systems from WSL in a few weeks or months. So maybe that will work!&lt;/p&gt;
&lt;p&gt;I set my lock screen to a slideshow of my pictures. Except my pictures do not show up, and I get to see Window's default pictures instead. An internet search reveals that this is a wide-spread problem. Many &amp;quot;solutions&amp;quot; are offered &lt;a href="https://answers.microsoft.com/en-us/windows/forum/windows_10-start/windows-10-lock-screen-slideshow-not-showing/01975f7f-11e8-457e-a8ef-5b494af135f1"&gt;in the support fora&lt;/a&gt;. What works for me is to first set the lock screen to &amp;quot;Windows Spotlight&amp;quot;, then to &amp;quot;Slideshow&amp;quot;. Only in that order will my pictures be shown.&lt;/p&gt;
&lt;p&gt;I will stop here. I could probably go on ad infinitum if I wanted to. This was my experience of using Windows for one day. I consider these problems relatively benign, in that all of them had solutions, if non-obvious ones.&lt;/p&gt;
&lt;h2&gt;Why install Windows in the first place?&lt;/h2&gt;
&lt;p&gt;Part of the reason for installing Windows was my growing frustration with Linux. I have been a happy user of KDE of various flavors for about seven years now. But ever since I got into photo editing, things began to become problematic:&lt;/p&gt;
&lt;p&gt;My photo editor requires OpenCL, but the graphics driver situation on Linux is problematic, to say the least. I generally managed to get RocM running most of the time, but kernel updates frequently broke it, or required down- or upgrading RocM. It was a constant struggle.&lt;/p&gt;
&lt;p&gt;I wanted to work with some of my data on a network share, but KDE's implementation of network shares does not simply mount them for applications to use, but instead requires each application to be able to open network locations on their own. Needless to say, this worked almost never, requiring many unnecessary file copies. Perhaps Gnome handles network shares better, but let's not open that can of worms.&lt;/p&gt;
&lt;p&gt;Printing photos simply never worked right for me. The colors were off, photo papers were not supported, the networked printer was rarely recognized. Both for a Samsung printer and an Epson and a Canon. One time a &lt;a href="https://turboprint.info/"&gt;commercial printer driver for Linux&lt;/a&gt; printed with so much ink it dripped off the paper afterwards. Neither Darktable nor Gimp nor Digikam have a robust printing mode. I generally resorted to Windows for printing.&lt;/p&gt;
&lt;p&gt;I ran that Windows in a virtual machine. With Virtualbox, the virtual machine would be extremely slow, to the point where it had a delay of several seconds between typing and seeing letters on the screen. VMWare did better, but would suddenly freeze and hang for minutes at a time. Disabling hugepages helped sometimes, for a short while. The virtual machine network was extremely unreliable. Some of these issues were probably related to my using a 4K screen.&lt;/p&gt;
&lt;p&gt;Speaking of screens, I have two screens, one HighDPI 4k and one normal 1440p. Using X, the system can be either in HighDPI mode, or in normal mode. But it can't drive the two displays in different modes. Thus the second monitor was almost useless and I generally worked only on the 4k screen. With Wayland I would have been able to use both screens in different modes, but not be able to color-calibrate them or record screen casts. Which is completely unacceptable. So I stuck with one screen and X. In Windows, I can use both screens and calibrate them.&lt;/p&gt;
&lt;img src="/static/2020-09/wtf.jpg" style="width: 50%; padding-left: 25%;" /&gt;

&lt;p&gt;Additionally, Linux hardware support is still a bit spotty. My SD card reader couldn't read some SD cards because of driver issues. It would sometimes corrupt the SD card's file systems. USB-connected cameras were generally not accessible. The web cam did not work reliably. The CPU fan ran too hot most of the time.&lt;/p&gt;
&lt;p&gt;So there had been numerous grievances in Linux that had no solutions. Still I stuck with it because so many more smaller issues were actually fixable if I put in the work. In fact I had accumulated quite a number of small hacks and scripts for various issues. I feared that Windows would leave me without recourse in these situations. And it doesn't. But at least the bigger features generally work as advertised.&lt;/p&gt;
&lt;h2&gt;Where do we go from here?&lt;/h2&gt;
&lt;p&gt;Just for completion's sake, I should really find an Apple computer and run it through its paces. From my experience of occasionally using a Macbook for teaching over the last few years, I am confident that it fares no better than Linux or Windows.&lt;/p&gt;
&lt;p&gt;Were things always this broken? How are normal people expected to deal with these things? No wonder every sane person now prefers a smartphone or tablet to their computers. Limited as they may be, at least they generally &lt;em&gt;work&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There is no joy in technology any more.&lt;/p&gt;</description><author>bastibe.de</author><pubDate>Thu, 17 Sep 2020 13:25:00 GMT</pubDate><guid isPermaLink="true">https://bastibe.de/2020-09-17-dear-computer-we-need-to-talk.html</guid></item><item><title>The future of farming looks more and more like Star Wars</title><link>https://stop.zona-m.net/2020/09/the-future-of-farming-looks-more-and-more-like-star-wars/</link><description>&lt;p&gt;May the Force of the Right Hardware be with you.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 17 Sep 2020 08:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/the-future-of-farming-looks-more-and-more-like-star-wars/</guid></item><item><title>True Heroism</title><link>https://ho.dges.online/words/commonplace/true-heroism-by-david-foster-wallace/</link><description>&lt;p&gt;True heroism is minutes, hours, weeks, year upon year of the quiet, precise, judicious exercise of probity and care - with no one there to see or cheer. This is the world&amp;quot;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;David Foster Wallace, The Pale King&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>ho.dges.online</author><pubDate>Thu, 17 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/words/commonplace/true-heroism-by-david-foster-wallace/</guid></item><item><title>Rust 2021: Lower the barriers</title><link>https://nindalf.com/posts/rust-2021/</link><description>Rust's success is guaranteed on a long enough timescale, but lowering the barrier to entry by making it easier to learn is crucial for its adoption rate.</description><author>Krishna's blog</author><pubDate>Thu, 17 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/rust-2021/</guid></item><item><title>2020–09–17: Video acceleration experiments with PinePhone</title><link>https://xnux.eu/log/#016</link><author>megi's PinePhone Development Log</author><pubDate>Thu, 17 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#016</guid></item><item><title>Notes from Amir Shevat on Measuring &amp;amp; Managing Developer Relations</title><link>https://www.swyx.io/a16z_devrel_amir_shevat</link><description>Notes from an a16z podcast about developer relations that I thought was valuable</description><author>swyx's site RSS Feed</author><pubDate>Wed, 16 Sep 2020 21:40:08 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/a16z_devrel_amir_shevat</guid></item><item><title>Focused headings</title><link>https://www.pinecoder.dev/blog/2020-09-16/focused-headings/</link><description>I finished another feature on Chronicles: &amp;ldquo;Focused headings&amp;rdquo; (demo). Focusing a heading finds all content under that heading, filters everything else out, then pins the heading to the top of the journal.
A journal might typically have a range of topics across many days:
After &amp;ldquo;Focusing&amp;rdquo; a heading, the heading element is fixed to the top, and the view filters any content not under that heading:
The primary inspiration was wanting a way to take running notes on similar topics, then have a way to surface them all in one stream — as though the entire journal was about just that topic.</description><author>Home on Pinecoder blog</author><pubDate>Wed, 16 Sep 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://www.pinecoder.dev/blog/2020-09-16/focused-headings/</guid></item><item><title>Building the USB audio passthrough board</title><link>https://blog.kaetemi.be/2020/09/16/building-the-usb-audio-passthrough-board/</link><description>After trying out a USB isolator to fix the audio noise that was caused by a ground loop, I continued my search for a high quality plug-and-play solution to forward...</description><author>Kaetemi</author><pubDate>Wed, 16 Sep 2020 11:39:42 GMT</pubDate><guid isPermaLink="true">https://blog.kaetemi.be/2020/09/16/building-the-usb-audio-passthrough-board/</guid></item><item><title>Why writing is important</title><link>https://andrew.gr/stories/writing/</link><description>I have no idea how to run RSS feeds, so please read this story on my website &lt;a href="https://andrew.gr/stories/writing/"&gt;here&lt;/a&gt;!</description><author>Andrew's Stories</author><pubDate>Wed, 16 Sep 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://andrew.gr/stories/writing/</guid></item><item><title>Verbal mathematics sequence</title><link>https://zrkrlc.com/notes/verbal-mathematics/1600237453/</link><description>— a sequence introducing mathematical thinking to VerbalsThesis: (verbally loaded) mathematics is just philosophy, but where everything is precisely what we mean</description><author>Junk Heap Homotopy</author><pubDate>Wed, 16 Sep 2020 09:24:13 GMT</pubDate><guid isPermaLink="true">https://zrkrlc.com/notes/verbal-mathematics/1600237453/</guid></item><item><title>Poisson on startups</title><link>https://zrkrlc.com/notes/poisson-on-startups/1600237384/</link><description>Let’s start with some sage advice.A lot of curmudgeonly commenters on HN treat viable side-projects as a lottery. If we take that idea seriously, well, your chances of winning a PowerBall per ticket is 1 in 13 983 816. There are around 42620 programmers in Silicon Valley + the other US tech hubs (Seattle, Dallas/Fort Worth, DC, NYC)1. So if every single one of those Y programmers tries to found a startup, the expected number of startups we’ll get is:</description><author>Junk Heap Homotopy</author><pubDate>Wed, 16 Sep 2020 09:23:04 GMT</pubDate><guid isPermaLink="true">https://zrkrlc.com/notes/poisson-on-startups/1600237384/</guid></item><item><title>Bicycle delivery, or SLOW delivery?</title><link>https://stop.zona-m.net/2020/09/bicycle-delivery-or-slow-delivery/</link><description>&lt;p&gt;Where are the bigger gains?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 16 Sep 2020 08:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/bicycle-delivery-or-slow-delivery/</guid></item><item><title>What is Stealth Address technology and Why Does Monero Use It?</title><link>https://serhack.me/articles/what-is-stealth-address-technology-monero/</link><description>&lt;a href="https://getmonero.org"&gt;Monero&lt;/a&gt; is based on the CryptoNote protocol and utilizes the most powerful cryptographic techniques in an effort to protect the privacy of the sender, recipient, and obfuscate the amount transacted. -&lt;a href="https://serhack.me/articles/what-is-stealth-address-technology-monero/"&gt;Continue to read the article on SerHack.me&lt;/a&gt;</description><author>SerHack - Security Researcher</author><pubDate>Wed, 16 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://serhack.me/articles/what-is-stealth-address-technology-monero/</guid></item><item><title>Deprecating Marvin</title><link>https://muffinman.io/blog/deprecating-marvin/</link><description>&lt;article class="article"&gt;&lt;p&gt;It is funny, I would never say I would be sad to deprecate a software project. Especially a project boilerplate. But I just merged the deprecation notice, and I do feel down a little.&lt;/p&gt;
&lt;p&gt;I created &lt;a href="https://github.com/stanko/marvin"&gt;Marvin&lt;/a&gt; about &lt;a href="/blog/webpack-2-react-redux/"&gt;four years ago&lt;/a&gt; for my own needs. Since then it grew, became internal project at
&lt;span class="sidenote__text" tabindex="0"&gt;Work&amp;amp;Co&lt;/span&gt;&lt;span class="sidenote__note"&gt;&lt;span class="sidenote__note-inner"&gt;&lt;span class="sidenote__note-text"&gt;Fun fact, &lt;a href="https://work.co"&gt;our website&lt;/a&gt; is made on top of Marvin.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and was used by thousands of people.&lt;/p&gt;
&lt;h2 id="why"&gt;Why? &lt;a class="anchor-link" href="#why"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When Marvin was created React landscape was looking a lot different than today. The ecosystem continues to relentlessly evolve and maintaining a single boilerplate to capture all these possibilities has become unproductive.&lt;/p&gt;
&lt;p&gt;The repo will stay available, but we are stopping further improvements and maintenance.&lt;/p&gt;
&lt;h2 id="thank-you"&gt;Thank you! &lt;a class="anchor-link" href="#thank-you"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/So_Long,_and_Thanks_for_All_the_Fish"&gt;big thank you&lt;/a&gt; to everyone who used and supported Marvin!&lt;/p&gt;&lt;/article&gt;</description><author>Muffin Man</author><pubDate>Wed, 16 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/blog/deprecating-marvin/</guid></item><item><title>Analysing the Indian government cyberspace</title><link>https://captnemo.in/blog/2020/09/16/goi-cyberspace/</link><description>&lt;p&gt;I recently did some work on analysing the Indian government cyberspace, thought I should document them somewhere outside of my Twitter&lt;sup id="fnref:9"&gt;&lt;a class="footnote" href="#fn:9" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2 id="list-of-goi-websites"&gt;List of GoI websites&lt;/h2&gt;

&lt;p&gt;I’d made a list of Indian government websites in Jan 2019:&lt;/p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I ran &lt;a href="https://twitter.com/18F?ref_src=twsrc%5Etfw"&gt;@18F&lt;/a&gt; /pulse on Indian Government websites to see how many of them support HTTPS. A quick summary:&lt;br /&gt;&lt;br /&gt;Total Websites: 14183&lt;br /&gt;Total Live Websites: 11710 (82%)&lt;br /&gt;Websites with Valid HTTPS: 4753 (40% of all live websites)&lt;br /&gt;&lt;br /&gt;Raw Dataset for now: &lt;a href="https://docs.google.com/spreadsheets/d/16LWWplbSAu-EkWk4R7OVsk8JM6guyZ3yiKdXIzBDT_Q/edit?usp=sharing"&gt;docs.google.com/spreadsheets&lt;/a&gt;&lt;/p&gt;&amp;mdash; Nemo (@captn3m0) &lt;a href="https://twitter.com/captn3m0/status/1085050749011161089?ref_src=twsrc%5Etfw"&gt;January 15, 2019&lt;/a&gt;&lt;/blockquote&gt;


&lt;p&gt;The dataset was from 2 sources:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="http://goidirectory.nic.in/"&gt;GoI Directory&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://crt.sh"&gt;crt.sh&lt;/a&gt; (All certificates ending in &lt;code class="language-plaintext highlighter-rouge"&gt;.gov.in&lt;/code&gt; were used)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I re-ran the scripts to get an updated list (12842 domains), then tabulated them against the public-suffix&lt;sup id="fnref:1"&gt;&lt;a class="footnote" href="#fn:1" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt; for each. There is a long-tail, and I’ve published results &lt;a href="https://gist.github.com/captn3m0/4f3da8f07fe884e62bfab3ac85616936"&gt;here&lt;/a&gt;. Here are the top public suffixes for Indian government sites:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Public Suffix&lt;/th&gt;
      &lt;th&gt;Domains&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;nic.in&lt;/td&gt;
      &lt;td&gt;2454&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;gov.in&lt;/td&gt;
      &lt;td&gt;7259&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;in&lt;/td&gt;
      &lt;td&gt;528&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ac.in&lt;/td&gt;
      &lt;td&gt;490&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;com&lt;/td&gt;
      &lt;td&gt;568&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;co.in&lt;/td&gt;
      &lt;td&gt;171&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;org.in&lt;/td&gt;
      &lt;td&gt;168&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;edu.in&lt;/td&gt;
      &lt;td&gt;117&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;org&lt;/td&gt;
      &lt;td&gt;844&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;res.in&lt;/td&gt;
      &lt;td&gt;134&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;net.in&lt;/td&gt;
      &lt;td&gt;12&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;net&lt;/td&gt;
      &lt;td&gt;38&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id="sanskari-proxy"&gt;Sanskari Proxy&lt;/h2&gt;

&lt;p&gt;This was a long standing idea on my &lt;a href="https://github.com/captn3m0/ideas"&gt;ideas repo&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A lot of Indian Government websites are inaccessible on the public internet, because
they geo-fence it to within Indian Boundaries. The idea
is to make a Indian Proxy service that specifically works only for the Geo-fenced Indian government
websites.&lt;/p&gt;

  &lt;p&gt;For eg, if &lt;code class="language-plaintext highlighter-rouge"&gt;uidai.gov.in&lt;/code&gt; is inaccessible, hitting &lt;code class="language-plaintext highlighter-rouge"&gt;uidai.gov.sanskariproxy.in&lt;/code&gt; will get you
the same result, proxied via our servers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since I’d made an updated list of GoI websites, this seemed easy enough. I realized that setting up &lt;code class="language-plaintext highlighter-rouge"&gt;uidai.gov.sanskariproxy.in&lt;/code&gt; would likely count as impersonation under the Indian law,
so I did the next best thing: run an actual proxy. Here’s the announcement tweet:&lt;/p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Are you a security researcher outside India? Do you hate getting geoblocked to Indian government websites?&lt;br /&gt;&lt;br /&gt;Well, I made a proxy for security researchers outside India to access Indian government websites without resorting to shady VPNs.&lt;br /&gt;&lt;a href="https://github.com/captn3m0/sanskari-proxy"&gt;captn3m0/sanskari-proxy&lt;/a&gt;&lt;/p&gt;&amp;mdash; Nemo (@captn3m0) &lt;a href="https://twitter.com/captn3m0/status/1302191390508552192?ref_src=twsrc%5Etfw"&gt;September 5, 2020&lt;/a&gt;&lt;/blockquote&gt;


&lt;p&gt;Project page is &lt;a href="https://github.com/captn3m0/sanskari-proxy"&gt;https://github.com/captn3m0/sanskari-proxy&lt;/a&gt;, and if you’d like to get access - please reach out.&lt;/p&gt;

&lt;h2 id="cyberspace-ownership"&gt;Cyberspace Ownership&lt;/h2&gt;

&lt;p&gt;I’d planned to get a complete list of geoblocked websites next. While I’m progressing on this front, the results have been inconsistent/inaccurate so far. As an intermediate step, I’d made a list of IPs against every domain&lt;sup id="fnref:2"&gt;&lt;a class="footnote" href="#fn:2" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;, which looked like this:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Domain&lt;/th&gt;
      &lt;th&gt;IP Address&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;aavin.tn.gov.in&lt;/td&gt;
      &lt;td&gt;164.100.134.148&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;abnhpm.gov.in&lt;/td&gt;
      &lt;td&gt;14.143.233.34&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;agnii.gov.in&lt;/td&gt;
      &lt;td&gt;13.232.216.65&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;ap.gov.in&lt;/td&gt;
      &lt;td&gt;117.254.92.53&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;aponline.gov.in&lt;/td&gt;
      &lt;td&gt;125.16.9.130&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;appolice.gov.in&lt;/td&gt;
      &lt;td&gt;118.185.110.147&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;attendance.gov.in&lt;/td&gt;
      &lt;td&gt;164.100.166.114&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;cgg.gov.in&lt;/td&gt;
      &lt;td&gt;112.133.222.115&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;While running numerous nmap scans (and failing), I start checking the &lt;abbr title="Autonomous System Number"&gt;&lt;a href="https://en.wikipedia.org/wiki/Autonomous_system_(Internet)"&gt;ASN&lt;/a&gt;&lt;/abbr&gt;&lt;sup id="fnref:asn"&gt;&lt;a class="footnote" href="#fn:asn" rel="footnote"&gt;4&lt;/a&gt;&lt;/sup&gt; for some of these IPs to see who was hosting each website - especially the ones I was finding were blocked.&lt;/p&gt;

&lt;p&gt;I stumbled upon a bulk &lt;a href="https://team-cymru.com/community-services/ip-asn-mapping/"&gt;IP to ASN service&lt;/a&gt; by Cymru, ran all the IPs against it and published the results. Here’s the important graph:&lt;/p&gt;

&lt;p&gt;&lt;img alt="% of Indian Government domains hosted by each ASN. The image is a pie-chart representation showing share of each ASN. 45% of the chart is taken up by " src="/img/domain-by-asn.png" /&gt;&lt;/p&gt;

&lt;p&gt;As you can expect, &lt;abbr title="National Informatics Centre"&gt;NIC&lt;/abbr&gt;&lt;sup id="fnref:nic"&gt;&lt;a class="footnote" href="#fn:nic" rel="footnote"&gt;5&lt;/a&gt;&lt;/sup&gt; has the highest share, with &lt;abbr title="National Knowledge Network"&gt;NKN&lt;/abbr&gt;&lt;sup id="fnref:nkn"&gt;&lt;a class="footnote" href="#fn:nkn" rel="footnote"&gt;6&lt;/a&gt;&lt;/sup&gt;, BSNL, and &lt;a href="https://www.ctrls.in/"&gt;CtrlS&lt;/a&gt; following at roughly 5% each. There are a few other chart on &lt;a href="https://twitter.com/captn3m0/status/1303683006276620288"&gt;the twitter thread&lt;/a&gt;, and the raw data is available &lt;a href="https://docs.google.com/spreadsheets/d/e/2PACX-1vRFcjIsqE13A7FaRID_z_ETFtGNdpznx4VcFfmEzJGjHBx-oT-urp60C9BZZK7Umc9f5QX0Z4Yd3Vja/pubhtml#"&gt;here&lt;/a&gt; with interactive versions of each visualization.&lt;/p&gt;

&lt;h2 id="what-next"&gt;What next?&lt;/h2&gt;

&lt;p&gt;I’m working on running and comparing connectivity scans to these IPs to get a better understanding of the geoblocking situation. There’s also some issues with the domain list, as it seems to be missing lots of domains - so more corrections are needed.&lt;/p&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:9"&gt;
      &lt;p&gt;Twitter decided to suspend 12 different accounts I had access to recently - I’m starting to get wary of using Twitter for archival now. &lt;a class="reversefootnote" href="#fnref:9"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;A “public suffix” is one under which Internet users can (or historically could) directly register names. For eg - &lt;code class="language-plaintext highlighter-rouge"&gt;nic.in&lt;/code&gt; or &lt;code class="language-plaintext highlighter-rouge"&gt;github.io&lt;/code&gt;. Mozilla manages the list at &lt;a href="https://publicsuffix.org/"&gt;https://publicsuffix.org/&lt;/a&gt;. &lt;a class="reversefootnote" href="#fnref:1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:2"&gt;
      &lt;p&gt;There are issues with this approach, since domains do resolve to multiple IPs. But this is okay for the rudimentary analysis I’ve been doing so far. &lt;a class="reversefootnote" href="#fnref:2"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:asn"&gt;
      &lt;p&gt;Autonomous Systems (AS) is how the internet is sliced up and managed by different entities. Each AS (usually an ISP) is responsible for routing within its network, while announcing network routes on how it can be reached. &lt;a class="reversefootnote" href="#fnref:asn"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:nic"&gt;
      &lt;p&gt;The primary government office (under &lt;abbr title="Ministry of Electronics and Information Technology"&gt;MeitY&lt;/abbr&gt;) that provides infrastructure and support for government IT services. &lt;a class="reversefootnote" href="#fnref:nic"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:nkn"&gt;
      &lt;p&gt;National Knowledge Network is a multi-gigabit research and education network that provides a high speed network backbone for educational institutions in India. &lt;a class="reversefootnote" href="#fnref:nkn"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>Nemo's Home</author><pubDate>Wed, 16 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://captnemo.in/blog/2020/09/16/goi-cyberspace/</guid></item><item><title>2020–09–16: PineBook Pro and Levinboot again</title><link>https://xnux.eu/log/#015</link><author>megi's PinePhone Development Log</author><pubDate>Wed, 16 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#015</guid></item><item><title>Typesafe, Fullstack React &amp;amp; GraphQL with AWS Amplify</title><link>https://www.swyx.io/aws_typesafe_fullstack_react</link><description>This is the blog version of a talk I am giving at React Summit 2020</description><author>swyx's site RSS Feed</author><pubDate>Wed, 16 Sep 2020 00:23:42 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/aws_typesafe_fullstack_react</guid></item><item><title>Guidelines to improve your React folder structure</title><link>https://maxrozen.com/guidelines-improve-react-app-folder-structure</link><description>People often say to 'move files around until it feels right', but what does 'right' even mean? Let's learn in this article.</description><author>Max Rozen</author><pubDate>Tue, 15 Sep 2020 12:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/guidelines-improve-react-app-folder-structure</guid></item><item><title>Pointers are Easy, Optimization is Complicated</title><link>https://blog.metaobject.com/2020/09/pointers-are-easy-optimization-is.html</link><description>Just recently came across Ralf Jung's 2018 post titled &lt;a href="https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html"&gt;Pointers are Complicated&lt;/a&gt;.  The central thesis is that the model that most C (and 
assembly language) programmers have that a pointer is just an integer that happens to be a machine
address is wrong, in fact the author flat out states:  "Pointers are definitely not integers."&lt;p&gt;

That's a strong statement.  I like strong statements, because they make a discussion possible.  So 
let's respond in kind:  the claim that pointers are &lt;em&gt;definitely&lt;/em&gt; not integers is wrong.&lt;p&gt;

&lt;h3&gt;The example&lt;/h3&gt;

The example the author uses to show that pointers are definitely not integers is the following:

&lt;hr /&gt;

&lt;figure class="highlight"&gt;&lt;pre&gt;&lt;code class="language-c--"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="cm"&gt;/* some side-effect-free computation */&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;x_ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x_ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;


&lt;hr /&gt;
And this is the crux of the reasoning:

&lt;blockquote&gt;
It would be beneficial to be able to optimize the final read of y[0] to just return 42. The justification for this optimization is that writing to x_ptr, which points into x, cannot change y.
&lt;/blockquote&gt;

So pointers are "hard" and "not integers" because they conflict with this optimization that "would be
beneficial".&lt;p&gt;

I find this fascinating: a "nice to have" optimzation is so obviously more important than a simple
and obvious pointer model that it doesn't even need to be explained as a possible tradeoff, never
mind justified as to why the tradeoff is resolved in favor of the nice-to-have optimization.&lt;p&gt;

I prefer the simple and obvious pointer model.  Vastly.&lt;p&gt;

This way of placing the optimizer's concerns far ahead of the programmer's is not unique, if
you check out Chris Lattner's  &lt;a href="https://blog.llvm.org/posts/2011-05-13-what-every-c-programmer-should-know/"&gt;What Every C Programmer Should Know About Undefined Behavior&lt;/a&gt;, you will note
the frequent occurrence of the phrase "enables ... optimizations".  It's pretty much the only
justification ever given.&lt;p&gt;

I call this now industry-dominating style of programming &lt;em&gt;Compiler Optimizer Creator Oriented 
Programming&lt;/em&gt; (COCOP).  It was thoroughly critiqued in &lt;a href="http://www.complang.tuwien.ac.at/kps2015/proceedings/KPS_2015_submission_29.pdf"&gt;What every compiler writer should know about programmers or “Optimization” based on undefined behaviour hurts performance (pdf)&lt;/a&gt;.&lt;p&gt;


&lt;h3&gt;Pointers as Integers&lt;/h3&gt;

There are certainly machines where pointers are not integers, the most prominent being 8086/80286 16 bit
segmented mode, where a (far) pointer consists of a segment and an offset.  On 8086, the segment
is simply shifted left 4 bits and added to the offset, on 80286 the segment can be located anywhere
in memory or not be resident, implementing a segmented virtual memory.  AFAIK, these modes are
simplified variants of the iAPX 432 object memory model.&lt;p&gt;

What's important to note in this context is that the iAPX 432 and its memory model failed horribly,
and industry actively and happily moved away from the x86 segmented model to what is called a
"flat address space", common on other architectures and finally also adopted by Intel with the
386.&lt;p&gt;

The salient feature of a "flat address space" is that a pointer is an integer, and in fact this
eqivalence is also rather influential on CPU architecture, with address-space almost universally
tied to the CPU's integer size.  So although the 68K was billed as a 16 bit CPU (or 16/32), its
registers were actually 32 bits, and IIRC its address ALUs were fully 32 bit, so if you wanted
to do some kinds of 32 bit aritmetic, the LEA (Load Effective Address) instruction was your
friend.  The reason for the segmented architecturee on the 8086 was that it was a true 16 bit
machine, with 16 bit registers, but Intel wanted to have a 20 bit address space.&lt;p&gt; 

So not only was and is there an equivalence of pointers and integers, this state of affairs
was one that was actively sought and joyously received once we achieved it again.  Giving
it up for nice-to-have optimizations seems at &lt;em&gt;best&lt;/em&gt; debatable, but at the very
least it is something that should be discussed/debated, rather than simply assumed away.&lt;p&gt;</description><author>metablog</author><pubDate>Tue, 15 Sep 2020 12:01:17 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2020/09/pointers-are-easy-optimization-is.html</guid></item><item><title>Building UI without AutoLayout</title><link>https://whackylabs.com/objc/ui/2020/09/15/simple-manual-layout/</link><description>&lt;p&gt;I love &lt;a href="https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html"&gt;Auto Layout&lt;/a&gt;. It helps a lot when designing complex UI. But there are times when the UI is very simple and Auto Layout might feel a bit overkill, while other times the UI might be a bit too complex and Auto Layout actually starts affecting the app performance. Before auto layout there was another technique to creating UI, it’s called &lt;em&gt;Springs and Struts&lt;/em&gt; (also known as &lt;em&gt;Manual Layout&lt;/em&gt; to be in contrast with Auto Layout). I like Manual Layout a lot as well for its simplicity. Like with every other tool, there are trade-offs when selecting the best tool for the job, and it also applies when selecting Auto Layout vs Manual Layout.&lt;/p&gt;

&lt;p&gt;The good thing is that, the Auto Layout has not been designed as an alternative to Manual Layout, rather more like an complement. Where instead of us having to calculate the &lt;code class="language-plaintext highlighter-rouge"&gt;frame&lt;/code&gt;, we start with a &lt;code class="language-plaintext highlighter-rouge"&gt;CGRectZero&lt;/code&gt; and let the Auto Layout fill in the &lt;code class="language-plaintext highlighter-rouge"&gt;frame&lt;/code&gt; value later. Most of the time it’s wonderful and doesn’t impact our flow. Other times we might have to wait for the layout pass run to read back the calculated &lt;code class="language-plaintext highlighter-rouge"&gt;frame&lt;/code&gt; values&lt;/p&gt;

&lt;div class="language-c highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// let Auto layout calculate the frame values&lt;/span&gt;
  &lt;span class="n"&gt;dispatch_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dispatch_get_main_queue&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// start using the frame values for something else.&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I often wish if the Auto Layout were not that tightly coupled with &lt;code class="language-plaintext highlighter-rouge"&gt;UIKit&lt;/code&gt;. In a sense, if I could just run Auto Layout without a layout pass. This inspired me to take another take of building UIs without Auto Layout with something I’d like to call as &lt;em&gt;Simple Manual Layout&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id="inspiration"&gt;Inspiration&lt;/h2&gt;

&lt;p&gt;The inspiration is from how &lt;code class="language-plaintext highlighter-rouge"&gt;UIBarButtonItem&lt;/code&gt; works with &lt;code class="language-plaintext highlighter-rouge"&gt;UIToolbar&lt;/code&gt; or &lt;code class="language-plaintext highlighter-rouge"&gt;UINavigationBar&lt;/code&gt;. If we wanted to build a UI like&lt;/p&gt;

&lt;p&gt;&lt;img alt="img" src="https://whackylabs.com/assets/simple-manual-layout/toolbar.png" /&gt;&lt;/p&gt;

&lt;p&gt;We would create a &lt;code class="language-plaintext highlighter-rouge"&gt;UIToolBar&lt;/code&gt; and add a bunch of &lt;code class="language-plaintext highlighter-rouge"&gt;UIBarButtonItem&lt;/code&gt;&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;UIToolbar&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;toolbar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;UIToolbar&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;initWithFrame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toolbarFrame&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;playButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                               &lt;span class="nl"&gt;initWithBarButtonSystemItem:&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonSystemItemPlay&lt;/span&gt;
                               &lt;span class="nl"&gt;target:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;
                               &lt;span class="nl"&gt;action:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playVideo&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pauseButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                &lt;span class="nl"&gt;initWithBarButtonSystemItem:&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonSystemItemPause&lt;/span&gt;
                                &lt;span class="nl"&gt;target:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;
                                &lt;span class="nl"&gt;action:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pauseVideo&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rewindButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                 &lt;span class="nl"&gt;initWithBarButtonSystemItem:&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonSystemItemRewind&lt;/span&gt;
                                 &lt;span class="nl"&gt;target:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;
                                 &lt;span class="nl"&gt;action:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rewindVideo&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;forwardButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                  &lt;span class="nl"&gt;initWithBarButtonSystemItem:&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonSystemItemFastForward&lt;/span&gt;
                                  &lt;span class="nl"&gt;target:&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;
                                  &lt;span class="nl"&gt;action:&lt;/span&gt;&lt;span class="k"&gt;@selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forwardVideo&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;spaceButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonItem&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                                &lt;span class="nl"&gt;initWithBarButtonSystemItem:&lt;/span&gt;&lt;span class="n"&gt;UIBarButtonSystemItemFlexibleSpace&lt;/span&gt;
                                &lt;span class="nl"&gt;target:&lt;/span&gt;&lt;span class="nb"&gt;nil&lt;/span&gt;
                                &lt;span class="nl"&gt;action:&lt;/span&gt;&lt;span class="nf"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;toolbar&lt;/span&gt; &lt;span class="nf"&gt;setItems&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;NSArray&lt;/span&gt; &lt;span class="nf"&gt;arrayWithObjects&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                   &lt;span class="n"&gt;spaceButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;rewindButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;spaceButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;playButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;spaceButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;pauseButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;spaceButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;forwardButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;spaceButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nb"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The interesting element here is &lt;code class="language-plaintext highlighter-rouge"&gt;UIBarButtonSystemItemFlexibleSpace&lt;/code&gt;. Which is &lt;a href="https://developer.apple.com/documentation/uikit/uibarbuttonsystemitem/uibarbuttonsystemitemflexiblespace"&gt;documented as&lt;/a&gt; &lt;em&gt;“Blank space to add between other items. The space is distributed equally between the other items.”&lt;/em&gt;. Similarly, there’s another one called &lt;code class="language-plaintext highlighter-rouge"&gt;UIBarButtonSystemItemFixedSpace&lt;/code&gt; which is &lt;a href="https://developer.apple.com/documentation/uikit/uibarbuttonsystemitem/uibarbuttonsystemitemfixedspace"&gt;documented as&lt;/a&gt; &lt;em&gt;“Blank space to add between other items. Only the width property is used when this value is set.”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I think this approach could be used to build a layout engine which is very simple in terms of mental model but can be used to build as sophisticated layouts as we’d want.&lt;/p&gt;

&lt;h2 id="simple-manual-layout"&gt;Simple Manual Layout&lt;/h2&gt;

&lt;p&gt;With that design in mind we can build out layout engine. If there is a class &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayoutItem&lt;/code&gt; which is a placeholder for a &lt;code class="language-plaintext highlighter-rouge"&gt;UIView&lt;/code&gt; and another class &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayout&lt;/code&gt; that takes in one or more of these &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayoutItem&lt;/code&gt; and immediately calculates the &lt;code class="language-plaintext highlighter-rouge"&gt;frame&lt;/code&gt; of the every &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayoutItem&lt;/code&gt;. Then we can use the calculated &lt;code class="language-plaintext highlighter-rouge"&gt;frame&lt;/code&gt; value when constructing our &lt;code class="language-plaintext highlighter-rouge"&gt;UIView&lt;/code&gt; objects.&lt;/p&gt;

&lt;p&gt;So to create a full screen subview we should be able to create as:&lt;/p&gt;

&lt;p&gt;&lt;img alt="img" src="https://whackylabs.com/assets/simple-manual-layout/testFullScreenLayout.png" /&gt;&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="nf"&gt;layoutWithParentBounds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_rootFrame&lt;/span&gt;
                                            &lt;span class="nl"&gt;direction:&lt;/span&gt;&lt;span class="n"&gt;SLELayoutDirectionColumn&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mainItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;flexItem&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;mainItem&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;redView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mainItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;redColor&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_rootView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;redView&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;initWithFrame&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="nf"&gt;autorelease&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And a 2 subview layout, where the top is flexible and bottom is fixed&lt;/p&gt;

&lt;p&gt;&lt;img alt="img" src="https://whackylabs.com/assets/simple-manual-layout/testBottomFixLayout.png" /&gt;&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;  &lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="nf"&gt;layoutWithParentBounds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_rootFrame&lt;/span&gt;
                                              &lt;span class="nl"&gt;direction:&lt;/span&gt;&lt;span class="n"&gt;SLELayoutDirectionColumn&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;flexItem&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;itemWithHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;

  &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;topFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="nf"&gt;frameAtIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;bottomFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="nf"&gt;frameAtIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_rootView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;redColor&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_rootView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bottomFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;blueColor&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A more interesting layout would be where we have a column that contains a row.&lt;/p&gt;

&lt;p&gt;&lt;img alt="img" src="https://whackylabs.com/assets/simple-manual-layout/testInnerViewLayout.png" /&gt;&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;  &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="n"&gt;contentHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mainLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="nf"&gt;layoutWithParentBounds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;_rootFrame&lt;/span&gt;
                                                  &lt;span class="nl"&gt;direction:&lt;/span&gt;&lt;span class="n"&gt;SLELayoutDirectionColumn&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mainLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;flexItem&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mainLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;itemWithHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mainLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;itemWithHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;contentHeight&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;

  &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;headerFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mainLayout&lt;/span&gt; &lt;span class="nf"&gt;frameAtIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;toolbarFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mainLayout&lt;/span&gt; &lt;span class="nf"&gt;frameAtIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;contentFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mainLayout&lt;/span&gt; &lt;span class="nf"&gt;frameAtIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;SLELayout&lt;/span&gt; &lt;span class="nf"&gt;layoutWithParentBounds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;contentFrame&lt;/span&gt;
                                                   &lt;span class="nl"&gt;direction:&lt;/span&gt;&lt;span class="n"&gt;SLELayoutDirectionRow&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;flexItem&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;itemWithWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;contentHeight&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;flexItem&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;itemWithWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;contentHeight&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="nf"&gt;flexItem&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;

  &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;content1Frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="nf"&gt;frameAtIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;content2Frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentLayout&lt;/span&gt; &lt;span class="nf"&gt;frameAtIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_rootView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headerFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;redColor&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_rootView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toolbarFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;blueColor&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt;
  &lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;contentView&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contentFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;yellowColor&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_rootView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;contentView&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content1Frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;cyanColor&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;contentView&lt;/span&gt; &lt;span class="nf"&gt;addSubview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;SLECreateView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content2Frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UIColor&lt;/span&gt; &lt;span class="nf"&gt;magentaColor&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id="implementation-details"&gt;Implementation details&lt;/h1&gt;

&lt;p&gt;The implementation of this layout engine turns out to be not as sophisticated. If we provide a &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayoutItem&lt;/code&gt; which can have some properties fixed and others flexible.&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;
&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;NSObject&lt;/span&gt;

&lt;span class="c1"&gt;// no values fixed&lt;/span&gt;
&lt;span class="k"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;flexItem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// partially fixed&lt;/span&gt;
&lt;span class="k"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;itemWithWidth&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;itemWithHeight&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// total fixed&lt;/span&gt;
&lt;span class="k"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;itemWithSize&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// would be filled by the layout engine&lt;/span&gt;
&lt;span class="k"&gt;@property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonatomic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;readonly&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So we can mark any flexible value as &lt;code class="language-plaintext highlighter-rouge"&gt;kSLELayoutValueUndefined&lt;/code&gt; which is &lt;code class="language-plaintext highlighter-rouge"&gt;-1&lt;/code&gt; in our case.&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SLELayoutItem.m&lt;/span&gt;
&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;SLELayoutItem&lt;/span&gt;
&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;initWithSize&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;size&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// requested frame&lt;/span&gt;
    &lt;span class="n"&gt;_originalFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGRect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kSLELayoutValueUndefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kSLELayoutValueUndefined&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="c1"&gt;// will be updated later&lt;/span&gt;
    &lt;span class="n"&gt;_finalFrame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CGRectZero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// called by layout engine&lt;/span&gt;
&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setOrigin&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;origin&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;_finalFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setSize&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;size&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;_finalFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And we can have an internal &lt;em&gt;setter&lt;/em&gt; interface only visible to &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayout&lt;/code&gt;&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SLELayoutItem+Internal.h&lt;/span&gt;
&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setOrigin&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;setSize&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@property&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonatomic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;readonly&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;CGRect&lt;/span&gt; &lt;span class="n"&gt;originalFrame&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, within &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayout&lt;/code&gt; we have an mutable array that contains &lt;code class="language-plaintext highlighter-rouge"&gt;SLELayoutItem&lt;/code&gt;. And whenever a new item is added we recalculate the frames per item.&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SLELayout.m&lt;/span&gt;
&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;SLELayout&lt;/span&gt;

&lt;span class="c1"&gt;// ... &lt;/span&gt;

&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;addItem&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_items&lt;/span&gt; &lt;span class="nf"&gt;addObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt; &lt;span class="nf"&gt;updateFrames&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we calculate only for one direction, say vertical. The &lt;code class="language-plaintext highlighter-rouge"&gt;updateFrames&lt;/code&gt; might look something like:&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SLELayout.m&lt;/span&gt;
&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;SLELayout&lt;/span&gt;

&lt;span class="c1"&gt;// ... &lt;/span&gt;

&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;updateFrames&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// calculate total fixed height&lt;/span&gt;
  &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="n"&gt;fixHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;NSInteger&lt;/span&gt; &lt;span class="n"&gt;flexItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="n"&gt;itemHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;originalFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;itemHeight&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;kSLELayoutValueUndefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;flexItems&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;fixHeight&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;itemHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// calculate height per flex item&lt;/span&gt;
  &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="n"&gt;flexHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_parentSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;fixHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="n"&gt;flexItemHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flexHeight&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;flexItems&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// update final frames per item&lt;/span&gt;
  &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="n"&gt;offsetY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLELayoutItem&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;CGSize&lt;/span&gt; &lt;span class="n"&gt;itemSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;originalFrame&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;CGFloat&lt;/span&gt; &lt;span class="n"&gt;itemHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;itemSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;kSLELayoutValueUndefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;flexItemHeight&lt;/span&gt;
      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;itemSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;itemSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_parentSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;itemHeight&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="nf"&gt;setOrigin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;CGPointMake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offsetY&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="nf"&gt;setSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;itemSize&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="n"&gt;offsetY&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;itemSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And similar calculations for width.&lt;/p&gt;

&lt;p&gt;And now it doesn’t seem hard to imagine to support alignment for sub views (currently they are all set &lt;code class="language-plaintext highlighter-rouge"&gt;0.0f&lt;/code&gt; or all aligned to start) with something like:&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="nf"&gt;NS_ENUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NSUInteger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SLELayoutAlignment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;SLELayoutAlignmentStart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SLELayoutAlignmentCenter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SLELayoutAlignmentEnd&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If I actually start using this code in real life, I might start supporting it. The code for the &lt;code class="language-plaintext highlighter-rouge"&gt;Simple Layout Engine&lt;/code&gt; is available at &lt;a href="https://github.com/chunkyguy/SimpleLayoutEngine"&gt;github.com/chunkyguy/SimpleLayoutEngine&lt;/a&gt;&lt;/p&gt;</description><author>Whacky Labs</author><pubDate>Tue, 15 Sep 2020 09:00:00 GMT</pubDate><guid isPermaLink="true">https://whackylabs.com/objc/ui/2020/09/15/simple-manual-layout/</guid></item><item><title>The unbearable US-ness of online discourse</title><link>https://stop.zona-m.net/2020/09/the-unbearable-us-ness-of-online-discourse/</link><description>&lt;p&gt;My apologies in advance to all my US friends. But&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 15 Sep 2020 08:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/the-unbearable-us-ness-of-online-discourse/</guid></item><item><title>Hard Travel Case for Corne LP</title><link>http://evantravers.com/articles/2020/09/14/hard-travel-case-for-corne-lp/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/09/case-open.JPG" /&gt;&lt;/p&gt;&lt;p&gt;When I am bored I get on Amazon and look for hard cases that might work for my favorite keyboards. This week… the new Corne LP. While there are people making soft sleeves for keyboards, there's not much in the way of a protective travel case for most keyboards, especially the weird hobbyist ones that I've been using recently.&lt;/p&gt;
&lt;p&gt;&lt;img alt="case closed" src="https://images.evantravers.com/articles/2020/09/case-closed.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;This &lt;a href="https://www.amazon.com/gp/product/B004I5BUSO/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&amp;amp;psc=1"&gt;5&amp;quot; hard case for a GPS is $11 on Amazon&lt;/a&gt;, and from the internal dimensions it looked like it'd fit the corne LP and some cables… and it does!&lt;/p&gt;
&lt;p&gt;Included in the package is a very short usb-c -&amp;gt; usb-a cable, a short TRRS cable to connect the halves, and the Apple Camera Connection kit so that I can plug this into my phone.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; Since soldering up the Corne, I've learned there are bluetooth chips I could put on it… but I'll just work with this for a while.&lt;/p&gt;
&lt;p&gt;&lt;img alt="phone plugged into split keyboard" src="https://images.evantravers.com/articles/2020/09/case-cyberdeck.JPG" /&gt;&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;You have to reduce the power draw of your keyboard for this to work. You can see my commit &lt;a href="https://github.com/evantravers/qmk_firmware/commit/98aec4b55923b110f8f600222c25e2de900fe791"&gt;here&lt;/a&gt;. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Mon, 14 Sep 2020 18:17:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/09/14/hard-travel-case-for-corne-lp/</guid></item><item><title>Go-style coroutines in the FN language</title><link>https://blog.gnoack.org/post/coroutines-in-fn</link><description>&lt;p&gt;My toy Lisp &lt;a href="https://github.com/gnoack/fn"&gt;fn&lt;/a&gt; is an inherently
single-threaded language, but with its built-in stack-inspection
capabilities, it&amp;rsquo;s easy to build coroutines on top.&lt;/p&gt;
&lt;p&gt;The
&lt;a href="https://github.com/gnoack/fn/blob/master/examples/threads.fn#L29"&gt;implementation&lt;/a&gt;
only has about 20 lines of code, including comments. This article
contains a simplified implementation in-line. In only rewrote some
comments to make more sense in context, and removed confusing
technicalities like &lt;code&gt;fn&lt;/code&gt;&amp;rsquo;s custom method call syntax, the use of
&lt;code&gt;dynamic-wind&lt;/code&gt; and remarks about tail calls.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;In most programming languages, the call stack is a chain of stack
frames which ends in the program&amp;rsquo;s entry point.&lt;/p&gt;
&lt;figure&gt;
&lt;div class="pikchr" id="pikchr-0"&gt;
&lt;div class="pikchr-svg"&gt;
&lt;svg viewBox="0 0 335.463 180.386" xmlns="http://www.w3.org/2000/svg"&gt;
&lt;path d="M129.719,178.226L328.144,178.226L328.144,22.32L129.719,22.32Z"&gt;
&lt;path d="M2.16,178.226L58.8529,178.226L58.8529,149.879L2.16,149.879Z"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="30.5065" y="164.052"&gt;bar&lt;/text&gt;
&lt;polygon points="30.5065,110.194 34.8265,121.714 26.1865,121.714"&gt;
&lt;path d="M30.5065,149.879L30.5065,115.954"&gt;
&lt;text fill="rgb(0,0,0)" font-size="80%" text-anchor="middle" transform="rotate(-90 30.5065,130.037)" x="30.5065" y="120.353"&gt;caller&lt;/text&gt;
&lt;path d="M2.16,110.194L58.8529,110.194L58.8529,81.8476L2.16,81.8476Z"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="30.5065" y="96.0208"&gt;foo&lt;/text&gt;
&lt;polygon points="30.5065,42.1625 34.8265,53.6825 26.1865,53.6825"&gt;
&lt;path d="M30.5065,81.8476L30.5065,47.9225"&gt;
&lt;text fill="rgb(0,0,0)" font-size="80%" text-anchor="middle" transform="rotate(-90 30.5065,62.005)" x="30.5065" y="52.321"&gt;caller&lt;/text&gt;
&lt;path d="M2.16,42.1625L58.8529,42.1625L58.8529,13.8161L2.16,13.8161Z"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="30.5065" y="27.9893"&gt;main&lt;/text&gt;
&lt;path d="M143.892,107.359L313.971,107.359L313.971,36.4932L143.892,36.4932Z"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="228.932" y="51.7663"&gt;information to&lt;/text&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="228.932" y="71.9263"&gt;resume execution of&lt;/text&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="228.932" y="92.0863"&gt;the calling function&lt;/text&gt;
&lt;path d="M143.892,164.052L313.971,164.052L313.971,107.359L143.892,107.359Z"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="228.932" y="125.626"&gt;values of local&lt;/text&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="228.932" y="145.786"&gt;variables and arguments&lt;/text&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="228.932" y="12.24"&gt;stack frame (simplified)&lt;/text&gt;
&lt;path d="M58.8529,178.226L129.719,178.226"&gt;
&lt;path d="M58.8529,149.879L129.719,22.32"&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figcaption&gt;A conventional call stack&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class="sidenote"&gt;
Stack frames are on the heap in fn.
&lt;/div&gt;
&lt;p&gt;In the case of C, this call stack is a contiguous memory area, but in
&lt;em&gt;fn&lt;/em&gt;, the stack frames are actually allocated objects on the heap
which have pointers to each other. Each stack frame also stores the
information required to &lt;a href="https://github.com/gnoack/fn/blob/def2f2164f708df2980364f8f1495e94d0df8690/runtime/interpreter.c#L154"&gt;resume
it&lt;/a&gt;.&lt;/p&gt;
&lt;div class="sidenote"&gt;
Functions can get a handle on their own stack frame
&lt;/div&gt;
&lt;p&gt;Additionally, &lt;em&gt;fn&lt;/em&gt; has a natively implemented helper called
&lt;a href="https://github.com/gnoack/fn/blob/def2f2164f708df2980364f8f1495e94d0df8690/runtime/primitives.c#L311"&gt;&lt;code&gt;$get-frame&lt;/code&gt;&lt;/a&gt;.
When called, &lt;code&gt;$get-frame&lt;/code&gt; returns the caller&amp;rsquo;s own stack frame as Lisp
object which can be manipulated. You can access it from an interactive
&lt;code&gt;fn&lt;/code&gt; session as well:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-scheme"&gt;fn&amp;gt; ($get-frame)
#&amp;lt;Frame () @1ff4437b5780&amp;gt;
fn&amp;gt; (frame-caller ($get-frame))
#&amp;lt;Frame () @1ff4437b97c4&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="implementation"&gt;Implementation&lt;/h2&gt;
&lt;h3 id="a-queue-of-suspended-coroutines"&gt;A queue of suspended coroutines&lt;/h3&gt;
&lt;p&gt;For Go-style coroutine behaviour, we keep track of a queue of call
stacks of currently suspended coroutines. A coroutine which yields
execution queues itself last, and returns into the first call stack
from that queue.&lt;/p&gt;
&lt;figure&gt;
&lt;div class="pikchr" id="pikchr-1"&gt;
&lt;div class="pikchr-svg"&gt;
&lt;svg viewBox="0 0 422.422 210.29" xmlns="http://www.w3.org/2000/svg"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="39.6576" y="177.89"&gt;pop out&lt;/text&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="39.6576" y="198.05"&gt;(resume)&lt;/text&gt;
&lt;polygon points="82.9152,187.97 94.4352,183.65 94.4352,192.29"&gt;
&lt;path d="M88.6752,187.97L116.931,187.97"&gt;
&lt;path d="M116.931,202.143L162.285,202.143L162.285,173.797L116.931,173.797Z"&gt;
&lt;polygon points="139.608,145.45 143.928,156.97 135.288,156.97"&gt;
&lt;path d="M139.608,173.797L139.608,151.21"&gt;
&lt;path d="M122.6,145.45L156.616,145.45L156.616,122.773L122.6,122.773Z"&gt;
&lt;polygon points="139.608,94.4266 143.928,105.947 135.288,105.947"&gt;
&lt;path d="M139.608,122.773L139.608,100.187"&gt;
&lt;path d="M122.6,94.4266L156.616,94.4266L156.616,71.7494L122.6,71.7494Z"&gt;
&lt;polygon points="139.608,43.403 143.928,54.923 135.288,54.923"&gt;
&lt;path d="M139.608,71.7494L139.608,49.163"&gt;
&lt;path d="M122.6,43.403L156.616,43.403L156.616,20.7258L122.6,20.7258Z"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" transform="rotate(-90 122.6,83.088)" x="122.6" y="73.008"&gt;next to be resumed&lt;/text&gt;
&lt;path d="M162.285,202.143L207.64,202.143L207.64,173.797L162.285,173.797Z"&gt;
&lt;polygon points="184.962,145.45 189.282,156.97 180.642,156.97"&gt;
&lt;path d="M184.962,173.797L184.962,151.21"&gt;
&lt;path d="M167.955,145.45L201.97,145.45L201.97,122.773L167.955,122.773Z"&gt;
&lt;polygon points="184.962,94.4266 189.282,105.947 180.642,105.947"&gt;
&lt;path d="M184.962,122.773L184.962,100.187"&gt;
&lt;path d="M167.955,94.4266L201.97,94.4266L201.97,71.7494L167.955,71.7494Z"&gt;
&lt;path d="M207.64,202.143L252.994,202.143L252.994,173.797L207.64,173.797Z"&gt;
&lt;polygon points="230.317,145.45 234.637,156.97 225.997,156.97"&gt;
&lt;path d="M230.317,173.797L230.317,151.21"&gt;
&lt;path d="M213.309,145.45L247.325,145.45L247.325,122.773L213.309,122.773Z"&gt;
&lt;polygon points="230.317,94.4266 234.637,105.947 225.997,105.947"&gt;
&lt;path d="M230.317,122.773L230.317,100.187"&gt;
&lt;path d="M213.309,94.4266L247.325,94.4266L247.325,71.7494L213.309,71.7494Z"&gt;
&lt;polygon points="230.317,43.403 234.637,54.923 225.997,54.923"&gt;
&lt;path d="M230.317,71.7494L230.317,49.163"&gt;
&lt;path d="M213.309,43.403L247.325,43.403L247.325,20.7258L213.309,20.7258Z"&gt;
&lt;path d="M252.994,202.143L298.348,202.143L298.348,173.797L252.994,173.797Z"&gt;
&lt;polygon points="275.671,145.45 279.991,156.97 271.351,156.97"&gt;
&lt;path d="M275.671,173.797L275.671,151.21"&gt;
&lt;path d="M258.663,145.45L292.679,145.45L292.679,122.773L258.663,122.773Z"&gt;
&lt;polygon points="275.671,94.4266 279.991,105.947 271.351,105.947"&gt;
&lt;path d="M275.671,122.773L275.671,100.187"&gt;
&lt;path d="M258.663,94.4266L292.679,94.4266L292.679,71.7494L258.663,71.7494Z"&gt;
&lt;polygon points="298.348,187.97 309.868,183.65 309.868,192.29"&gt;
&lt;path d="M304.108,187.97L332.364,187.97"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="379.193" y="177.89"&gt;push in&lt;/text&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="379.193" y="198.05"&gt;(suspend)&lt;/text&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figcaption&gt;A queue of suspended call stacks&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;div class="sidenote"&gt;
Starting new coroutines
&lt;/div&gt;
&lt;p&gt;A new coroutine is started with &lt;code&gt;thread-new!&lt;/code&gt;. &lt;code&gt;thread-new!&lt;/code&gt; suspends
its caller and itself becomes the entry point for the new coroutine
which immediately executes. The helper function &lt;code&gt;thread-die!&lt;/code&gt;
unschedules the current thread from execution by scheduling another
coroutine without adding itself back to the queue.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-scheme"&gt;(defn thread-new! (thunk)
  ;; Suspend current call stack.
  (queue-push! *thread-queue* (frame-caller ($get-frame)))
  ;; Make sure we don't accidentally
  (set-frame-caller! ($get-frame) '*should-never-be-used*)
  ;; Call thunk, then call thread-die!.
  (thunk)
  (thread-die!))

(defn thread-die! ()
  (set-frame-caller! ($get-frame)
                     (queue-pop! *thread-queue*))
  nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="switching-between-coroutines"&gt;Switching between coroutines&lt;/h3&gt;
&lt;div class="sidenote"&gt;
In some languages, &lt;tt&gt;next-thread!&lt;/tt&gt; would be called &lt;tt&gt;yield&lt;/tt&gt;
&lt;/div&gt;
&lt;p&gt;To switch between coroutines, all you need to do is to have &lt;em&gt;multiple
call stacks&lt;/em&gt; and switch between them. In &lt;em&gt;fn&lt;/em&gt;, this is done in the
&lt;code&gt;next-thread!&lt;/code&gt; function. &lt;code&gt;next-thread!&lt;/code&gt;, when called, will swizzle out
the calling stack frame stored in its own stack frame. That way, the
function can return into a different call stack than the one it was
invoked from.&lt;/p&gt;
&lt;figure&gt;
&lt;div class="pikchr" id="pikchr-2"&gt;
&lt;div class="pikchr-svg"&gt;
&lt;svg viewBox="0 0 185.737 219.753" xmlns="http://www.w3.org/2000/svg"&gt;
&lt;path d="M24.8372,217.593L115.546,217.593L115.546,189.247L24.8372,189.247Z"&gt;
&lt;text fill="rgb(0,0,0)" text-anchor="middle" x="70.1915" y="203.42"&gt;next-thread!&lt;/text&gt;
&lt;polygon points="30.5065,143.892 34.8265,155.412 26.1865,155.412"&gt;
&lt;path d="M58.8529,189.247 L 44.6797,180.743 Q 30.5065,172.239 30.5065,160.946 L 30.5065,149.652"&gt;
&lt;path d="M2.16,143.892L58.8529,143.892L58.8529,115.546L2.16,115.546Z"&gt;
&lt;polygon points="30.5065,87.1994 34.8265,98.7194 26.1865,98.7194"&gt;
&lt;path d="M30.5065,115.546L30.5065,92.9594"&gt;
&lt;path d="M2.16,87.1994L58.8529,87.1994L58.8529,58.8529L2.16,58.8529Z"&gt;
&lt;polygon points="30.5065,30.5065 34.8265,42.0265 26.1865,42.0265"&gt;
&lt;path d="M30.5065,58.8529L30.5065,36.2665"&gt;
&lt;path d="M2.16,30.5065L58.8529,30.5065L58.8529,2.16L2.16,2.16Z"&gt;
&lt;path d="M16.3332,166.569L56.0183,166.569"&gt;
&lt;path d="M16.3332,177.908L56.0183,155.231"&gt;
&lt;text fill="rgb(255,0,0)" text-anchor="start" x="56.0183" y="155.231"&gt; 1.&lt;/text&gt;
&lt;polygon points="155.231,143.892 159.551,155.412 150.911,155.412"&gt;
&lt;path d="M92.8687,189.247 L 124.05,177.908 Q 155.231,166.569 155.231,158.111 L 155.231,149.652"&gt;
&lt;text fill="rgb(60,179,113)" text-anchor="middle" x="124.05" y="154.869"&gt;2.&lt;/text&gt;
&lt;path d="M126.884,143.892L183.577,143.892L183.577,115.546L126.884,115.546Z"&gt;
&lt;polygon points="155.231,87.1994 159.551,98.7194 150.911,98.7194"&gt;
&lt;path d="M155.231,115.546L155.231,92.9594"&gt;
&lt;path d="M126.884,87.1994L183.577,87.1994L183.577,58.8529L126.884,58.8529Z"&gt;
&lt;polygon points="155.231,30.5065 159.551,42.0265 150.911,42.0265"&gt;
&lt;path d="M155.231,58.8529L155.231,36.2665"&gt;
&lt;path d="M126.884,30.5065L183.577,30.5065L183.577,2.16L126.884,2.16Z"&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figcaption&gt;next-thread! returns into a different call stack than it was called from&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;code&gt;next-thread!&lt;/code&gt; is implemented as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-scheme"&gt;(defn next-thread! ()
  ;; Push our own frame's caller onto the queue.
  (queue-push! *thread-queue* (frame-caller ($get-frame)))
  ;; Remove a suspended stack frame from the queue,
  ;; and set it as our own caller, so we'll return to it.
  (set-frame-caller! ($get-frame)
                     (queue-pop! *thread-queue*))
  nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="caveats-about-tail-calls"&gt;Caveats about tail calls&lt;/h3&gt;
&lt;p&gt;Manipulating your own stack frame leads to a simple and short
implementation, but the devil is in the details.&lt;/p&gt;
&lt;p&gt;In particular, in languages with implicit and automatic tail calls, an
invocation such as &lt;code&gt;(set-frame-caller! ($get-frame) ...)&lt;/code&gt; cannot be
put at the end of a function, of you would manipulate the caller of a
function that won&amp;rsquo;t ever return again. To work around this problem,
functions like &lt;code&gt;next-thread!&lt;/code&gt; and &lt;code&gt;thread-die!&lt;/code&gt; return &lt;code&gt;nil&lt;/code&gt;
explicitly at the end, so that &lt;code&gt;set-frame-caller!&lt;/code&gt; does not get
invoked with a tail call.&lt;/p&gt;
&lt;p&gt;The full coroutine implementation is in the &lt;code&gt;fn&lt;/code&gt; repository in
&lt;a href="https://github.com/gnoack/fn/blob/master/examples/threads.fn"&gt;&lt;code&gt;examples/threads.fn&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;</description><author>Blog on blog.gnoack.org</author><pubDate>Mon, 14 Sep 2020 13:15:00 GMT</pubDate><guid isPermaLink="true">https://blog.gnoack.org/post/coroutines-in-fn</guid></item><item><title>Coronavirus, Italian schizophrenia</title><link>https://stop.zona-m.net/2020/09/coronavirus-italian-schizophrenia/</link><description>&lt;p&gt;Unsurprising, yes. But very weird to live in.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 14 Sep 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/coronavirus-italian-schizophrenia/</guid></item><item><title>Real Deal Bridge</title><link>https://apurva-shukla.me/blog/real-deal-bridge/</link><description>Over a period of four months our game studio team at No Moss Co, led the development of Real Deal Bridge - a realtime multiplayer, cross…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Mon, 14 Sep 2020 08:30:23 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/blog/real-deal-bridge/</guid></item><item><title>Book Review - Shoe Dog by Phil Knight</title><link>https://www.swyx.io/shoe-dog</link><description>One of the greatest autobiographies by a business icon and great writer</description><author>swyx's site RSS Feed</author><pubDate>Mon, 14 Sep 2020 06:30:30 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/shoe-dog</guid></item><item><title>Voting Roll Call</title><link>https://xavd.id/blog/post/voting-roll-call/</link><description>Voting won't solve everything, but it certainly won't make anything worse. These are instructions to help you make sure all your Facebook friends are registered to vote!&lt;br /&gt;&lt;br /&gt;&lt;a href="https://xavd.id/blog/post/voting-roll-call/"&gt;Read the whole thing&lt;/a&gt;.</description><author>The David Brownman Blog</author><pubDate>Mon, 14 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xavd.id/blog/post/voting-roll-call/</guid></item><item><title>Notes on Adversarial Interoperability</title><link>https://www.swyx.io/adversarial_interoperability</link><description>Summarizing thoughts from Seth Godin and Cory Doctorow on Interoperability</description><author>swyx's site RSS Feed</author><pubDate>Mon, 14 Sep 2020 02:37:49 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/adversarial_interoperability</guid></item><item><title>2020–09–14: Putting 13 PinePhone distributions on a 8GiB uSD card</title><link>https://xnux.eu/log/#014</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 14 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#014</guid></item><item><title>Did You Know Fonts Could Do All This?</title><link>https://venam.net/blog/unix/2020/09/14/playing_with_fonts.html</link><description>Freetype, included in the font stack on Unix, is quite complex. There are so many layers to get it to do what it does that it's easy to get lost. From finding the font, to actually rendering it, and everything in between. Like most of the world, I use a rather low screens definition (1366x768 with 96 dpi) and rather old-ish laptop, unlike some font designers that live in a filter bubble where everyone has the latest macbook. Thus, good and legible font rendering is important. Let's play with lesser known toggles available to us when it comes to font rendering and see what they do, let's have fun and explore possibilities.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Mon, 14 Sep 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/unix/2020/09/14/playing_with_fonts.html</guid></item><item><title>Assassin 33 A.D.</title><link>https://olshansky.info/movie/assassin_33_a.d./</link><description>Olshansky's review of Assassin 33 A.D.</description><author>🦉 olshansky 🦁</author><pubDate>Sun, 13 Sep 2020 16:04:38 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/assassin_33_a.d./</guid></item><item><title>Be careful with your Docker logs</title><link>https://heitorpb.github.io/bla/careful-with-docker-logs/</link><description>Logs are important. But they might fill your disk. Here I show how to configure Docker daemon to rotate logs.</description><author>Heitor's log</author><pubDate>Sun, 13 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://heitorpb.github.io/bla/careful-with-docker-logs/</guid></item><item><title>Start With No</title><link>https://dylanpaulus.com/posts/2020/start-with-no/</link><description>&lt;blockquote&gt;
&lt;p&gt;Our default response to any idea that comes up should be: “Interesting. Maybe some day.” In other words, a very soft “no” that leaves all our options open. We don’t put it in a backlog. We give it space so we can learn whether it’s really important and what it might entail.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
    &lt;sub&gt;
        &lt;a href="https://basecamp.com/shapeup/1.2-chapter-03#responding-to-raw-ideas"&gt;"Shape Up" - Ryan Singer (Basecamp)&lt;/a&gt;
    &lt;/sub&gt;
&lt;/div&gt;
&lt;p&gt;Here's a story: At a previous employer, I had a boss who I thought was pretty tough. Not to me, but to our users. No matter the request, his response was always the same: "No." Eventually, we implemented around 40% of the requests, but the constant rejection of these requests stuck with me. Now that I lead a team, I notice myself using the same mindset. "No" isn't negative, and it's not dismissive. "No" is a way of protecting the team, the project, and the users.&lt;/p&gt;
&lt;h3&gt;No?&lt;/h3&gt;
&lt;p&gt;There is a natural progression to projects that looks something like this: first, the honeymoon phase. The pastures are green; the project has no technical debt, and every feature is a great idea. As we add functionality, our user base grows. If we're lucky enough to get traction, we move to phase two: the monolith. Our application now handles a bunch of use-cases. It does your taxes, picks up your dog's poop, and reminds you to call your mom. Only power users can fully grasp the purpose of the application. The technical debt is increasing with every new feature added. Finally, we get to the last phase. The application has become so bloated that it's hard to develop new features. New users aren't willing to learn the ins-and-outs of the product. A new startup comes around with a trimmed-down version of your application. It's so easy to use! Around this time, users are jumping ship.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Diagram showing a product's lifecycle" src="./feature-graph.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Saying "no" is a buffer in our development process. It gives us, the developer, time to think of an optimal solution. Could a feature being asked for be solved in a way that satisfies multiple feature requests? Is there some domain logic we have yet to understand? Does the feature really make sense in &lt;em&gt;this&lt;/em&gt; application? All these questions help reduce the lifecycle described above. It reduces feature churn by keeping the application simple and by solving issues the users actually have.&lt;/p&gt;
&lt;p&gt;Be mindful of how features interact within your application. Nothing comes without a cost—especially in software development.&lt;/p&gt;
&lt;h3&gt;No.&lt;/h3&gt;
&lt;p&gt;"No" is a way of protecting people—the users and the development team. There is a gradient of experience when it comes to using your application. Users will be complete beginners, and others will be power users. As a product owner, we need to balance these two extremes. If the application is too power-user-centric, then it's harder for new users to grasp. When the application is too hand-holding, power users become frustrated. Saying "no" to one extreme is a way of keeping the scales balanced. But be mindful of what you say "no" to. Some features may be vital to the application's success. This is part of the art.&lt;/p&gt;
&lt;p&gt;"No" gives time to find the optimal solution to a problem. Users ask for a solution to X and suggest implementing Y, but what they really need is K. Feature requests give us an opportunity to improve processes and workflows. Our users are domain experts but are prone to doing things the way they've "always done them." We can come in and find ways to simplify. Ask the user, "do we really need this step?" or "Could the system handle that instead of a person?" Once code is written and users get accustomed to the feature, it's really hard to change. Do this step upfront.&lt;/p&gt;
&lt;p&gt;"No" keeps the development team doing meaningful work. Spending a sprint or two implementing a feature nobody uses or finds frustrating is demoralizing. Think about the workflow before writing any code. Question the feature and the users. Does the application need this? Could we implement it in a simple way? Reduce code churn; reduce developer churn.&lt;/p&gt;
&lt;h3&gt;No!&lt;/h3&gt;
&lt;p&gt;Work needs to get done. At some point, you need to say "yes," but instead of taking on every task, you get to be mindful of what to prioritize. You get to take on the tasks that add the most business value and delight users. Use "no" as a tool.&lt;/p&gt;</description><author>Dylan Paulus' Blog</author><pubDate>Sun, 13 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dylanpaulus.com/posts/2020/start-with-no/</guid></item><item><title>Don't Go Far Off by Pablo Neruda</title><link>https://ho.dges.online/words/commonplace/dont-go-far-off-by-pablo-neruda/</link><description>&lt;p&gt;Don&amp;rsquo;t go far off, not even for a day, because &amp;ndash;&lt;br /&gt;
because &amp;ndash; I don&amp;rsquo;t know how to say it: a day is long&lt;br /&gt;
and I will be waiting for you, as in an empty station&lt;br /&gt;
when the trains are parked off somewhere else, asleep.&lt;br /&gt;
Don&amp;rsquo;t leave me, even for an hour, because&lt;br /&gt;
then the little drops of anguish will all run together,&lt;br /&gt;
the smoke that roams looking for a home will drift&lt;br /&gt;
into me, choking my lost heart.&lt;br /&gt;
Oh, may your silhouette never dissolve on the beach;&lt;br /&gt;
may your eyelids never flutter into the empty distance.&lt;br /&gt;
Don&amp;rsquo;t leave me for a second, my dearest,&lt;br /&gt;
because in that moment you&amp;rsquo;ll have gone so far&lt;br /&gt;
I&amp;rsquo;ll wander mazily over all the earth, asking,&lt;br /&gt;
Will you come back? Will you leave me here, dying?&lt;/p&gt;</description><author>ho.dges.online</author><pubDate>Sun, 13 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/words/commonplace/dont-go-far-off-by-pablo-neruda/</guid></item><item><title>The Guilt Line - Red &amp;amp; Blue's Frontier</title><link>http://spirals.blog/articles/the-guilt-line/</link><description>&lt;p&gt;&lt;strong&gt;“STOP!”&lt;/strong&gt; The police officer yelled, “This raucous is over!”&lt;/p&gt;
&lt;p&gt;The music ceased immediately, and the end-of-year forest party came to an abrupt end. It was good while it lasted. Some of the teenagers ran for the darkness and safety of the trees, while others, horrified of what their parents would say, stood Blue–struck, red beer cups in hand.&lt;/p&gt;
&lt;p&gt;What seemed like a fun, secluded, annual ritual – a chance to dance away the boredom of another school year of tests and assignments – was not looked upon so favorably by the strict, local law enforcement. After all, it was only last year that Johnny was seen handing out weed. The town was on edge.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Blue Vs. Red&lt;/h2&gt;
&lt;p&gt;Along the frontier of the Blue/Red boundary lies many a conflict:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Terrorists and trained armies.&lt;/li&gt;
&lt;li&gt;“Surfer-dudes” and their frustrated bosses, from the cafes they &lt;em&gt;sometimes&lt;/em&gt; show up to work for.&lt;/li&gt;
&lt;li&gt;An eager youth and a strict school principal.&lt;/li&gt;
&lt;li&gt;Criminals and the law.&lt;/li&gt;
&lt;li&gt;A rowdy teenager and a concerned parent.&lt;/li&gt;
&lt;li&gt;Etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The hard line between expressive Red and a responsibility-driven Blue underpins many of societies’ interactions and much of our individual lives.&lt;/p&gt;
&lt;p&gt;As we’ve learned from our previous forays into these complex perspectives, &lt;em&gt;&lt;strong&gt;both are needed&lt;/strong&gt;&lt;/em&gt;. &lt;em&gt;&lt;strong&gt;Neither is “right” or “wrong”&lt;/strong&gt;&lt;/em&gt;. And yet, when one is fueled by a righteous and ordered Blue drive or a carefree and in-the-moment Red fuel, we don’t always see the other side. They’re often the enemy: the misbehaving hooligans, or the stuck-up, prissy suits.&lt;/p&gt;
&lt;p&gt;Sound familiar?&lt;/p&gt;
&lt;h2&gt;The Guilt Line&lt;/h2&gt;
&lt;p&gt;&lt;img alt="The Guilt Line" src="http://spirals.blog/articles/the-guilt-line/guilt-line.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;In the Spiral’s evolution, Blue clamps down on an overactive Red that was taking things too far. We learned that one of Blue’s powerful assets in controlling Red is guilt. A firm, disciplined, fear of doing something wrong in the eye of the law/god/ism/Truth/company policy.&lt;/p&gt;
&lt;p&gt;In the diagram above, Red rises until, usually, something catastrophic happens, and society steps in. A concrete line is drawn, and anybody who crosse this line will be severely punished. You’ve been warned.&lt;/p&gt;
&lt;p&gt;Here’s the thing, however. &lt;strong&gt;This line is dependent on how healthy your Blue is, AND your acceptance of Red.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;A Low Guilt Line = No fun&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Low Guilt Line" src="http://spirals.blog/articles/the-guilt-line/low-line.jpg" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As the guilt line drops, so too does healthy expression and self-acceptance of ones desires (culturally or individual)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example, let’s take a party-going highschool-dropout, who after a dance with alcoholism and a brief intervention from the local church, get’s his shit together and becomes church’s accountant.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Accountant" src="http://spirals.blog/articles/the-guilt-line/accountant.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;How do you suppose this “structure” (Red -&amp;gt; Blue) would respond to &lt;em&gt;his&lt;/em&gt; children going out to party? I think it’s fair to say he would not be offering to pick them up at 1 am from the beach celebrations.&lt;/p&gt;
&lt;p&gt;Likewise, the same applies to countries. After the bloodshed, chaos, and warring disputes, the “peace” that Blue brings is a breath of fresh air. Countries like Japan enforce incredibly strict social norms and rules to limit Red’s expression - often resulting in very unhealthy behavior.&lt;/p&gt;
&lt;p&gt;“You can be Red, but only on a Friday or Saturday night, between the hours of 7 pm and 11:59 pm, and it but be contained to this small district we’ve set aside for you.”&lt;/p&gt;
&lt;p&gt;This sentiment is exceptionally damaging (as is any over-suppression of the natural Spiral). It creates friction (internal and externally), crippling guilt, sexual frustration, “working one’s self to the bone”, stress, “uptight” ness, boredom, lack of creativity and joy, and many other issues.&lt;/p&gt;
&lt;p&gt;In some cases, for those whose “guilt line” has been too low for too long, they’ll snap one day. They’ve sacrificed themselves for society/others, allowing nothing for themselves. Suddenly, the long-term, high-valued employee quits their job, gets a divorce, moves to Hawaii, and buys a Ferrari. &lt;em&gt;A typical midlife crisis – Red violently bursts through Blue.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Too high a Guilt Line = Chaos&lt;/h2&gt;
&lt;p&gt;&lt;img alt="High Guilt Line" src="http://spirals.blog/articles/the-guilt-line/high-line.jpg" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As the guilt line rises, order, discipline, and tempered rationality gives way to extreme behavior, ego, and power struggles.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course, the converse of everything above is also true. If Blue laxes too much, allowing Red to walk over it as it pleases, other problems arise.&lt;/p&gt;
&lt;p&gt;For example, when crime becomes prevalent (sometimes organized by small amounts of Orange) and the police are too weak, corrupt, or under-funded to control it, Red can claim entire nations. Despite potential external meddling from the CIA, Pablo Escobar is an unfortunate illustration of Red dominating a still developing Blue Colombia.&lt;/p&gt;
&lt;p&gt;At one point, an extreme Red was controlling Colombia’s entire country
from a “prison” that HE designed for himself. It crippled Colombia’s people (who thankfully have recovered) and much of South America’s reputation.&lt;/p&gt;
&lt;p&gt;Red must be kept in check. Not so much that it limits the self to the point of a puristic chastise, but enough to protect and preserve the safety of all. Lowering the guilt line when Red has reigned for a time is a bloody business.&lt;/p&gt;
&lt;h2&gt;Finding the balance&lt;/h2&gt;
&lt;p&gt;I wonder if you can recognize your own guilt line. Indeed, it often fluctuates depending on the area of our lives. How far do you go before the sense that you’re doing something wrong kicks in? Do you end up hurting people (intentionally OR Unintentionally)? Or are you too strict on yourself and others, not giving space to “take the day off” or “dance the night away”.&lt;/p&gt;
&lt;p&gt;If you’re fueled by Red, living in a dominant Blue (which is most of the world), is the line too low for you? Too high?&lt;/p&gt;
&lt;p&gt;If Blue fuels you, how much Red can you tolerate? Do you put your foot down at the slightest sight of “unruly behavior” or “bad manners”? Or do you recognize that we all possess a bit of everything, and join in on the fun?&lt;/p&gt;
&lt;p&gt;Indeed, different situations call for the raising and lowering of our Guilt Lines.&lt;/p&gt;
&lt;p&gt;As always, there are no definitive answers to any of the above. There are only the tools we develop and discover – using and practicing them in the game of life. Like an archeologist, we brush away our own bias and dig a little deeper into the world around us – driven curiously to uncover the mysteries of others world-views.&lt;/p&gt;
&lt;p&gt;And now we have another tool.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 13 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/the-guilt-line/</guid></item><item><title>Modelling a Wealth Tax Correctly</title><link>https://nindalf.com/posts/wealth-tax/</link><description>This article examines the accuracy of modelling a wealth tax and critiques Paul Graham's argument against it.</description><author>Krishna's blog</author><pubDate>Sun, 13 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/wealth-tax/</guid></item><item><title>You do not have a Right To KEEP Buying (*)</title><link>https://stop.zona-m.net/2020/09/you-do-not-have-a-right-to-keep-buying/</link><description>&lt;p&gt;And that is BAD.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 12 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/you-do-not-have-a-right-to-keep-buying/</guid></item><item><title>Cheese cake recipe (no crust)</title><link>https://xenodium.com/cheese-cake-recipe-no-crust</link><description>&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/cheese-cake-recipe-no-crust/berried.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/cheese-cake-recipe-no-crust/inoven.jpg" /&gt;&lt;/p&gt;
&lt;h2&gt;Preheat oven&lt;/h2&gt;
&lt;p&gt;Preheat oven at 175°C.&lt;/p&gt;
&lt;h2&gt;Ingredients at room temperature&lt;/h2&gt;
&lt;p&gt;Ensure the cream cheese, sour cream, and eggs are at room temperature before starting.&lt;/p&gt;
&lt;h2&gt;Mix cream cheese&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;900g of cream cheese&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mix the cream cheese thoroughly.&lt;/p&gt;
&lt;h2&gt;Mix sugar&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;240g of sugar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add half the sugar. Mix in thoroughly. Add second half and mix.&lt;/p&gt;
&lt;h2&gt;Mix sour cream, corn flour, and vanilla.&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;100g sour cream&lt;/li&gt;
&lt;li&gt;40g corn flour&lt;/li&gt;
&lt;li&gt;1tbsp vanilla bean paste&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add the three ingredients and mix well.&lt;/p&gt;
&lt;h2&gt;Mix eggs&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;3 eggs&lt;/li&gt;
&lt;li&gt;1 egg yolk&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add the eggs and mix for 30 seconds.&lt;/p&gt;
&lt;h2&gt;Mix by hand&lt;/h2&gt;
&lt;p&gt;Finish mixing thoroughly by hand, using a wooden spoon.&lt;/p&gt;
&lt;h2&gt;Prepare pan&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Springform pan&lt;/li&gt;
&lt;li&gt;Parchment paper&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A springform pan works best here. Wrap its plate with parchment paper and lock it in place.&lt;/p&gt;
&lt;h2&gt;Pour mix&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Strainer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour the mix through a strainer and into the prepared pan.&lt;/p&gt;
&lt;h2&gt;Rest mix&lt;/h2&gt;
&lt;p&gt;Let the mix rest in the pan for 10 minutes to let air bubbles out.&lt;/p&gt;
&lt;h2&gt;Bake&lt;/h2&gt;
&lt;p&gt;Bake for an 1 hour 10 minutes. Maybe add another 10 minutes (or more) if surface is still pale. Turn the oven off, leave door half open, and let it sit for 20 minutes.&lt;/p&gt;
&lt;h2&gt;Cool off&lt;/h2&gt;
&lt;p&gt;Take out and let it cool off to room temperature.&lt;/p&gt;
&lt;h2&gt;Refrigerate&lt;/h2&gt;
&lt;p&gt;Refrigerate for 4 hours (or overnight) before removing the sides of the pan.&lt;/p&gt;
&lt;h2&gt;Eat!&lt;/h2&gt;
&lt;p&gt;Nom nom. Yum yum.&lt;/p&gt;
&lt;h2&gt;Bonus (topping)&lt;/h2&gt;
&lt;p&gt;I winged this one and it worked out well. Heated up frozen berries with some honey and used it as topping. The whole combo was pretty tasty.&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sat, 12 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/cheese-cake-recipe-no-crust</guid></item><item><title>I Want to Fix Goodreads</title><link>/culture/2020/09/fixing_goodreads.html</link><description>&lt;p&gt;I use &lt;a href="https://goodreads.com"&gt;goodreads&lt;/a&gt; a lot because I like to read books and want to find more books to read. This morning I was reading a &lt;a href="https://news.ycombinator.com/item?id=24451428"&gt;thread on hackernews&lt;/a&gt; on &lt;a href="https://www.newstatesman.com/science-tech/social-media/2020/08/better-goodreads-possible-bad-for-books-storygraph-amazon"&gt;Sarah Manavis’s NewStatesman article&lt;/a&gt; and it reminds me of how much I want, I yearn, for useful book recommendations. I think about this pretty much every time I open the goodreads page or app and hope that maybe this is the day they finally fix recommendations, so I figure I would capture some ideas I have for fixing their recommendations.&lt;/p&gt;

&lt;h2 id="i-love-goodreads"&gt;I Love Goodreads&lt;/h2&gt;

&lt;p&gt;First, I love Goodreads. My &lt;a href="https://www.goodreads.com/user/show/9499790-brian"&gt;profile&lt;/a&gt; says I joined May 2012. But I think that’s just whenever I started this profile and I have multiple, old profiles that I can’t find. My memory says I started using them soon after launch, but maybe I’m misremembering. But I’ve used them for a long time because I like to read books. I love browsing bookstores and libraries looking for new books. I experience joy finding a 50 or 100 year old book that I didn’t know about. One of my favorite things is reading a book so good that I can’t go to bed, or want to walk an extra mile. But that’s pretty rare for me, I’m lucky if I get one of those a year.&lt;/p&gt;

&lt;p&gt;I have goodreads on my &lt;a href="http://prepend.com/stack.xml"&gt;link stack&lt;/a&gt; with the tag &lt;a href="https://www.prepend.com/future/technology/2020/01/purdah.html"&gt;“purdah”&lt;/a&gt; that I think means it is part of the stuff I do that uniquely identifies me.&lt;/p&gt;

&lt;p&gt;Any time I get a recommendation from a friend or article or wherever, I add it to my “to read” shelf on goodreads. That helps me when I’m trying to buy a new book. So at least I can read through the 245 books that at least a past me wanted to read. This works well and is better than a vanilla list.&lt;/p&gt;

&lt;p&gt;I also like seeing what my friends read and especially what they like or dislike. My friends have different tastes so it’s not as simple as just reading everything they read, but it helps a little. It’s one of the few places that I think facebook helps because at least I get to find out facebook friends who also are on goodreads. Every once in a while I find a new book through this feed, maybe once every 2 years. This might be because I don’t have many friends on goodreads (only 42), but I think it’s also because different people have different tastes in books.&lt;/p&gt;

&lt;p&gt;I also like that goodreads will tell me when an author I’ve read releases a new book, or is having a book chat or something. Although I wish they would tell me when they come to a local book signing.&lt;/p&gt;

&lt;h2 id="the-problem-as-i-see-it"&gt;The Problem As I See It&lt;/h2&gt;

&lt;p&gt;This gets me to what I think is wrong and want to fix. I have read and rated 802 books with my average rating of 3.97. This makes sense as I’m probably only going to read books I think I’ll like, but I think this is the average goodreads rating, not the average of my ratings. Looking at what I rated, I’ve only given out 3 one stars, 42 two stars and tons of five stars. I keep scrolling on and on.&lt;/p&gt;

&lt;p&gt;The user interface for goodreads is pretty bad- information is hard to find, layout is wasted, search doesn’t work well, hard to tell ads from user content- but that’s not what I’m talking about here. The main problem is in finding books that I will like. Maybe a UX overhaul from a great designer would help, but not that much. A craigslist interface would be great if they could just solve this one problem…&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;What is the single book that I will love most in all the world?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I want to find the next amazing experience. Books are great because they are cheap and portable. It’s not like wine where the best is more than I’ll ever pay. Or travel where a first class flight can cost $20k. If I can find a book, I can read it. And maybe someone I know can read it too.&lt;/p&gt;

&lt;p&gt;If I can mix in more wonderful books, my life will be better. My family’s life will be better. Etc etc. Maybe this is the answer to world enlightenment. Probably not, but it will be great, I think.&lt;/p&gt;

&lt;p&gt;When I click on &lt;a href="https://www.goodreads.com/recommendations"&gt;recommendations&lt;/a&gt;, goodreads shows me five books that I don’t want to read. And it’s weirdly bad. Some of it makes since why it’s bad. They recommend different versions of books I’ve read. They recommend two different versions of &lt;em&gt;Lord of the Rings&lt;/em&gt; (one of my favorite books), but I guess they don’t know these are the same book. That’s just a waste of time and it’s weird that amazon isn’t smart enough to avoid duplicative books.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot of goodreads recommendations page" src="/assets/images/goodreads_recommendations.png" /&gt;&lt;/p&gt;

&lt;p&gt;But then they recommend stuff like Stephen King’s &lt;em&gt;The Long Walk&lt;/em&gt;. This is perplexing because I only have one book that goodreads knows I’ve read from King and I rated it two stars. I don’t have any of his books in my “to read” list. Why would they recommend this book? Two of my friends rated it four stars and one even wrote a recommendation. So maybe that’s why. I’m aware of this book and don’t want to read it. But other books like &lt;em&gt;Shoe Dog&lt;/em&gt; by Phil Knight has no relationship to me. Why would they recommend this? I also know about this book and don’t want to read it. I wish there was some way to note books that I don’t want to read. Then at least they would stop showing me the same book over and over.&lt;/p&gt;

&lt;p&gt;So it seems like goodreads is making pretty basic, rules-based recommendations. And they don’t help me pick new books.&lt;/p&gt;

&lt;h2 id="my-perfect-wish"&gt;My Perfect Wish&lt;/h2&gt;

&lt;p&gt;My idea for an 11-star experience &lt;sup id="fnref:brian_chesky"&gt;&lt;a class="footnote" href="#fn:brian_chesky" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; in finding new books is that Goodreads knows me even better than I know myself and constantly recommends the perfect book. They recommend books that teach me, that spark enlightenment, that I hate but teach me to appreciate other books, books for when I want to be happy, and books for when I need to be sad. I want something like Jane from Ender’s Game who experiences everything I know but is fixated on finding me a good book. So the output of a book sommelier whose passion is seeing me sit there and love a book.&lt;/p&gt;

&lt;p&gt;That’s what I would like.&lt;/p&gt;

&lt;h2 id="a-little-story-about-jeff-bezos"&gt;A Little Story About Jeff Bezos&lt;/h2&gt;

&lt;p&gt;Once I was lucky enough to go to TED. It was great on so many levels, I highly recommend it and 2/3 of the cost was tax deductible. It was full of great stuff. I got to wait in the registration line in front of Neil Gaiman and Amanda Palmer, that was neat.&lt;/p&gt;

&lt;p&gt;Anyway, one night Neil Gaiman was doing in a midnight ghost story reading in some neat four story townhouse type building &lt;sup id="fnref:vancouver_club"&gt;&lt;a class="footnote" href="#fn:vancouver_club" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt; that was totally empty and spooky and a great place for the event. The reading was on the top floor and there was a huge crowd waiting for the single elevator in this place. The lights were off and there weren’t any staff around so it was maybe 100 people waiting to go up three at a time. So I looked around the corner and took the stairs. About 2 or 3 other people had the same idea so we started racing up the stairs to get to the top and avoid the crowds.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Vancouver Club street view" src="/assets/images/vancouver_club.jpg" /&gt;
&lt;em&gt;photo by &lt;a href="https://fineartamerica.com/profiles/2-joe-fox"&gt;Joe Fox&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This building was awesome. It seemed 100 years old, rare in Vancouver, and as we went up the stairs we saw each floor. The stairwell opened up to a big room that could probably seat a 50 person wedding dinner. The lights were off, and someone had opened a few windows and the white, wispy curtains were blowing with a little breeze. Even though it didn’t feel like a breeze. I said “cool, haunted house” and stopped climbing the stairs to look around. The person next to me said “yeah, cool” and we started quickly running around checking out the empty room. We did this on the third floor too and me and this random person did quick 60 second explorations of this spooky house.&lt;/p&gt;

&lt;p&gt;It all happened quickly. Maybe 3 minutes to go up the stairs, run around each floor, and get to the top. About halfway through I realized this random dude was Jeff Bezos. I thought that was neat. I’ve bought books from Amazon since 1995 and I’m pretty sure I telnetted into it to order some books (although maybe that was cdnow before they bought them), so it was cool to think that Jeff Bezos likes haunted houses and still likes exploring empty buildings.&lt;/p&gt;

&lt;p&gt;We got to the top and went into the venue and were maybe the first 10 people. Comically got there maybe after two or three elevators full of people. We went to the front where Gaiman was setting up at the podium. I got a comfy chair right in the front about five feet in front of Gaiman. Jeff Bezos sat in the chair to my left. The chair on my right had Neil’s wife, Amanda Palmer, who was carrying a ukelele case. I didn’t know it was a ukulele case until she told me. She also said she might play, but she didn’t.&lt;/p&gt;

&lt;p&gt;Gaiman finished setting up and came up to talk to Bezos. Bezos asked if Gaiman got the books he sent. Gaiman said he did and they were really great and he enjoyed reading them. It seemed like this was the most recent in a series of book shipments.&lt;/p&gt;

&lt;p&gt;Aside from nerd joy from getting to witness this small talk of people who interest me, I thought, at the time and many times since,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;How cool is it that Neil-freaking Gaiman is still finding new books that are great, and how cool would it be to get book recommendations from Jeff Bezos. I bet he has access to the best book recommendations in the world.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Also, TED has something called the “TED book club” where they mail you this box of books a month before the conference. This was the closest I’ve come to my dream. They maybe sent 10 and 5 are still on my bookshelf. But not the shelf behind me, so I don’t remember them specifically. I’ll look them up one day.&lt;/p&gt;

&lt;p&gt;That’s probably better than Jane making recommendations. Amazon had just bought goodreads a year earlier and I was hopeful that any day, goodreads would roll out a wonderful recommendation engine any day now.&lt;/p&gt;

&lt;h2 id="what-i-want-to-do-to-fix"&gt;What I Want to Do to Fix&lt;/h2&gt;

&lt;p&gt;What I would like to do is to just get a data dump of mine and everyone on goodreads recommendations. I don’t need to know the identities, just to know what recommendations go with what individual. It would be neat to protect privacy and find individuals to potentially follow them on goodreads, but I think for the analysis I want to do, I don’t need to know the actual identities.&lt;/p&gt;

&lt;p&gt;I think if I have this data, I could try to find people who rate a few hundred books like I have, then look at what books they’ve read the most, or books that they’ve rated highest. I think that would be a good signal that I might like it.&lt;/p&gt;

&lt;p&gt;It would also be cool to see books they hated. Just to see uniqueness amongst the millions of readers.&lt;/p&gt;

&lt;p&gt;It would also be cool to find my exact opposite. People who rate the absolute opposite from me, my antipode. &lt;sup id="fnref:antipode"&gt;&lt;a class="footnote" href="#fn:antipode" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;If I just had this data, I would do what goodreads isn’t doing for me. Maybe they’ve already tried and it’s impossible to achieve. Maybe it’s just one of those things where we have to increase opportunities and leverage serendipity.&lt;/p&gt;

&lt;p&gt;They do have an &lt;a href="https://www.goodreads.com/api"&gt;api&lt;/a&gt; but it seems meant for integrators to do goodreads functions from an app or something. I can get my own recommendations, but there’s no way to get other people’s ratings, and unless I know the name of the book I can’t look up ratings. And that’s sort of the problem since I don’t know the name of books I don’t know. They do allow me to view a &lt;a href="https://www.goodreads.com/api/index#user.show"&gt;specific user’s info&lt;/a&gt; and even lets us &lt;a href="https://www.goodreads.com/api/index#user.compare"&gt;compare shelves&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wish they had a data dump somewhere. It’s strange to me that lots of users allow their ratings to be public (eg, &lt;a href="https://www.goodreads.com/user/show/18134272-susan-beaumont"&gt;this random friend user&lt;/a&gt;), so I can theoretically scrape all the reviews from just public users, but that’s a lot of work. I share my ratings because I want to help others. I assume that other users do so for the same reason so I wish Goodreads/Amazon would help facilitate this. Since userids are just 8 digits, I supposed I can use their API to read one user a second (their requested rate limit) and it would just take me and it would just take me 3.17 years, or maybe less since they may not have 99,999,999 users, but Statistica claims they had 90 million registered users on July 2019. &lt;sup id="fnref:statistica"&gt;&lt;a class="footnote" href="#fn:statistica" rel="footnote"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h2 id="housekeeping"&gt;Housekeeping&lt;/h2&gt;

&lt;h3 id="unanswered-questions"&gt;Unanswered Questions&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Low quality of reading random people’s reviews and comments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="related-blog-posts"&gt;Related Blog Posts&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.prepend.com/future/technology/2020/01/purdah.html"&gt;How to identify yourself, when yourself changes? Neal Stephenson’s PURDAH.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="future-blog-ideas"&gt;Future Blog Ideas&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Describe the &lt;a href="http://prepend.com/stack.xml"&gt;link stack&lt;/a&gt; idea.&lt;/li&gt;
  &lt;li&gt;Emergent awesomeness. When you can’t explicitly do something, you just have to increase the rate of random awesome things and appreciate them when they happen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="stuff-i-read-while-working-on-this-post-that-you-might-want-to-read-too"&gt;Stuff I Read While Working on This Post (That You Might Want to Read Too)&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.newstatesman.com/science-tech/social-media/2020/08/better-goodreads-possible-bad-for-books-storygraph-amazon"&gt;Why Goodreads is bad for books&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Amazon_(company)"&gt;https://en.wikipedia.org/wiki/Amazon_(company)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Goodreads"&gt;https://en.wikipedia.org/wiki/Goodreads&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/book/show/375802.Ender_s_Game"&gt;Ender’s Game by Orson Scott Card&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/There_are_known_knowns"&gt;Known knowns&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.ted.com/attend/conferences"&gt;https://www.ted.com/attend/conferences&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.neilgaiman.com/"&gt;https://www.neilgaiman.com/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://amandapalmer.net/"&gt;https://amandapalmer.net/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.goodreads.com/api"&gt;https://www.goodreads.com/api&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Gentlemen%27s_club"&gt;https://en.wikipedia.org/wiki/Gentlemen%27s_club&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="footnotes"&gt;Footnotes&lt;/h3&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:brian_chesky"&gt;
      &lt;p&gt;&lt;a href="https://mastersofscale.com/brian-chesky-handcrafted/"&gt;https://mastersofscale.com/brian-chesky-handcrafted/&lt;/a&gt; Masters of Scale podcast with Brian Chesky where he describes AirBNB process of trying to design experiences where users rate something 11 stars (out of 5). I find it funny that AirBNB has never given me an 11 star experience, but lots of 5 stars. And I think that’s the message here. &lt;a class="reversefootnote" href="#fnref:brian_chesky"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:vancouver_club"&gt;
      &lt;p&gt;&lt;a href="https://vancouverclub.ca/"&gt;https://vancouverclub.ca/&lt;/a&gt; I think it was The Vancouver Club, so imagine this place but at midnight, empty and abandoned. &lt;a href="https://en.wikipedia.org/wiki/Gentlemen%27s_club"&gt;Wikipedia&lt;/a&gt; says it was founded in 1889. &lt;a class="reversefootnote" href="#fnref:vancouver_club"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:antipode"&gt;
      &lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Antipodes"&gt;https://en.wikipedia.org/wiki/Antipodes&lt;/a&gt; I would also like to see this antipode functionality for twitter. Who is the person with the exact opposite of me on Twitter. Would be neat to read their ideas. &lt;a class="reversefootnote" href="#fnref:antipode"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:statistica"&gt;
      &lt;p&gt;&lt;a href="https://www.statista.com/statistics/252986/number-of-registered-members-on-goodreadscom"&gt;https://www.statista.com/statistics/252986/number-of-registered-members-on-goodreadscom&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:statistica"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>PREPEND</author><pubDate>Sat, 12 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/culture/2020/09/fixing_goodreads.html</guid></item><item><title>Ergo update: standing desk + treadmill</title><link>https://mgsloan.com/posts/ergo-update-standing-desk-treadmill/</link><description>Active sitting stool, suspended drinks, tidying cables.</description><author>mgsloan's blog</author><pubDate>Sat, 12 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://mgsloan.com/posts/ergo-update-standing-desk-treadmill/</guid></item><item><title>Is Open Data for everybody, or not?</title><link>https://stop.zona-m.net/2020/09/is-open-data-for-everybody-or-not/</link><description>&lt;p&gt;It is a challenging and urgent task to innovate democracy&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 11 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/is-open-data-for-everybody-or-not/</guid></item><item><title>Postfix on a NixOS null client with external catch-all</title><link>https://alanpearce.eu/post/postfix-as-null-client-with-external-catchall/</link><description>&lt;p&gt;I wanted to set up a server so that any local email (e.g. generated by cron jobs/systemd timers) would be forwarded to an external address, regardless of the user.  I also wanted the from address to keep the system hostname whilst not allowing any external use of the mailserver.&lt;/p&gt;
&lt;p&gt;It took me a while to figure out how to this, so I thought I&amp;rsquo;d share my method.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the config that can be used to do this on any NixOS host, after redefining the first two variables.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-txt,linenos,hl_lines=2-3"&gt;services.postfix = let
  localUser = &amp;quot;example-user&amp;quot;;
  forwardingAddress = &amp;quot;user@external.domain&amp;quot;;
in
{
  enable = true;
  destination = [];
  domain = config.networking.domain;
  virtual = ''
    @${config.networking.hostName}.${config.networking.domain} ${localUser}
    ${localUser} ${forwardingAddress}
  '';
  config = {
    inet_interfaces = &amp;quot;loopback-only&amp;quot;;
  };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Emails to any user without a domain part are all sent to the forwarding address with a clear &lt;em&gt;from&lt;/em&gt; address (e.g. &lt;code&gt;System administrator &amp;lt;root@host.example.com&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;p&gt;First, the basic setup for a null client can be found in the &lt;a href="http://www.postfix.org/STANDARD_CONFIGURATION_README.html#null_client"&gt;postfix documentation&lt;/a&gt;. The example config would be translated into NixOS like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-txt"&gt;services.postfix = {
  enable = true;
  destination = [];
  domain = config.networking.domain;
  origin = config.networking.domain;
  relayHost = config.networking.domain;
  lookupMX = true;
  config = {
    inet_interfaces = &amp;quot;loopback-only&amp;quot;;
  };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this rewrites user@hostname.example.com to user@example.com (due to &lt;code&gt;origin&lt;/code&gt; on line 5).  I wanted to be able to see which host a mail concerns.&lt;/p&gt;</description><author>Alan Pearce</author><pubDate>Fri, 11 Sep 2020 19:49:00 GMT</pubDate><guid isPermaLink="true">https://alanpearce.eu/post/postfix-as-null-client-with-external-catchall/</guid></item><item><title>[Computing] USB Mass Storage and USB-Attached SCSI... are both SCSI</title><link>https://www.devever.net/~hl/usbuas</link><description>&lt;p&gt;(You may wish to read &lt;a href="scsi"&gt;A brief introduction to SCSI&lt;/a&gt; before reading this article.)&lt;/p&gt;</description><author>devever.net/~hl</author><pubDate>Fri, 11 Sep 2020 15:06:00 GMT</pubDate><guid isPermaLink="true">https://www.devever.net/~hl/usbuas</guid></item><item><title>KotSF is now Tilting at Windmills</title><link>https://tiltingatwindmills.dev/kotsf-is-now-tilting-at-windmills/</link><description>According to WHOIS, I first registered the domain
kotsf.com, a little over 12 years ago on August 18, 2008. Since then it's been my catch…</description><author>Tilting at Windmills</author><pubDate>Fri, 11 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://tiltingatwindmills.dev/kotsf-is-now-tilting-at-windmills/</guid></item><item><title>Black Holes • Art</title><link>https://muffinman.io/art/black-holes-color/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;A friend of mine asked for a color version of &lt;a href="/art/black-holes/"&gt;Black Holes&lt;/a&gt;. Again, it is so hard to take a good photo of these colors. They are nicer and more vivid in person.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;September 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;42x30cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Fabriano Black Black 300gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Gelly Roll Moonlight&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery art-gallery--wide"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1972" src="./0.jpg" width="2800" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1800" src="./w_500-h_500--1.jpg" width="2400" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./plot_1080x1080.mp4"&gt;&lt;video class="gallery__video" src="./plot_1080x1080.mp4#t=0.001"&gt;&lt;/video&gt;&lt;svg class="gallery__play-icon" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20 c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z"&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Fri, 11 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/black-holes-color/</guid></item><item><title>In My Craft Or Sullen Art by Dylan Thomas</title><link>https://ho.dges.online/words/commonplace/in-my-craft-or-sullen-art-by-dylan-thomas/</link><description>&lt;p&gt;In my craft or sullen art&lt;br /&gt;
Exercised in the still night&lt;br /&gt;
When only the moon rages&lt;br /&gt;
And the lovers lie abed&lt;br /&gt;
With all their griefs in their arms,&lt;br /&gt;
I labour by singing light&lt;br /&gt;
Not for ambition or bread&lt;br /&gt;
Or the strut and trade of charms&lt;br /&gt;
On the ivory stages&lt;br /&gt;
But for the common wages&lt;br /&gt;
Of their most secret heart.&lt;/p&gt;
&lt;p&gt;Not for the proud man apart&lt;br /&gt;
From the raging moon I write&lt;br /&gt;
On these spindrift pages&lt;br /&gt;
Nor for the towering dead&lt;br /&gt;
With their nightingales and psalms&lt;br /&gt;
But for the lovers, their arms&lt;br /&gt;
Round the griefs of the ages,&lt;br /&gt;
Who pay no praise or wages&lt;br /&gt;
Nor heed my craft or art.&lt;/p&gt;</description><author>ho.dges.online</author><pubDate>Fri, 11 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/words/commonplace/in-my-craft-or-sullen-art-by-dylan-thomas/</guid></item><item><title>The 11th</title><link>https://lambdaland.org/posts/2020-09-11-september-11th/</link><description>&lt;p&gt;Today is September 11th. I remember waking up 19 years ago, coming into the living room, and my dad getting down on one knee so he was closer to my level. He told me that earlier that morning two airplanes had crashed into some tall buildings in New York City. I didn’t know what that meant at the time, but I soon found out.&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Fri, 11 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-09-11-september-11th/</guid></item><item><title>2020–09–11: Adding postmarket OS to multi-distro image</title><link>https://xnux.eu/log/#013</link><author>megi's PinePhone Development Log</author><pubDate>Fri, 11 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#013</guid></item><item><title>2020–09–11: Ways to help improve Pinephone kernel</title><link>https://xnux.eu/log/#012</link><author>megi's PinePhone Development Log</author><pubDate>Fri, 11 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#012</guid></item><item><title>2020–09–11: PinePhone multi-boot image deduplication tool complete</title><link>https://xnux.eu/log/#011</link><author>megi's PinePhone Development Log</author><pubDate>Fri, 11 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#011</guid></item><item><title>AT&amp;amp;amp;T Archives: The UNIX Operating System</title><link>https://tbolt.space/2020/9/10/att-archives-unix-operating-system</link><description>From the video AT&amp;amp;T Archives: The UNIX Operating System (1982):</description><author>tbolt.space</author><pubDate>Thu, 10 Sep 2020 23:00:09 GMT</pubDate><guid isPermaLink="true">https://tbolt.space/2020/9/10/att-archives-unix-operating-system</guid></item><item><title>Automatic Wildness Creators?</title><link>https://stop.zona-m.net/2020/09/automatic-wildness-creators/</link><description>&lt;p&gt;What problem do we want to solve here?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 10 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/automatic-wildness-creators/</guid></item><item><title>James is available for hire!</title><link>https://purpleidea.com/blog/2020/09/10/james-is-available-for-hire/</link><description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I&amp;rsquo;m available for hire. Experienced at Linux/Golang/Mentoring/etc.
More information below!&lt;/p&gt;
&lt;br /&gt;
&lt;table&gt;&lt;tr&gt;&lt;td&gt;
&lt;table style="text-align: center; width: 80%; margin: 0 auto;"&gt;&lt;tr&gt;&lt;td&gt;
&lt;a href="https://purpleidea.com/blog/2020/09/10/james-is-available-for-hire/james-working.png"&gt;&lt;img class="alignnone size-full" src="https://purpleidea.com/blog/2020/09/10/james-is-available-for-hire/james-working.png" width="100%" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A drawing of me coding away.&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;/td&gt;&lt;td&gt;
&lt;table style="text-align: center; width: 80%; margin: 0 auto;"&gt;&lt;tr&gt;&lt;td&gt;
&lt;a href="https://purpleidea.com/blog/2020/09/10/james-is-available-for-hire/james-speaking.png"&gt;&lt;img class="alignnone size-full" src="https://purpleidea.com/blog/2020/09/10/james-is-available-for-hire/james-speaking.png" width="100%" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A photo of me giving a talk to a sold-out crowd.&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;

&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;


&lt;br /&gt;&lt;span style="text-decoration: underline; font-weight: bold;"&gt;Background&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;

&lt;p&gt;Two years ago, &lt;a href="https://purpleidea.com/blog/2018/04/04/leaving-redhat/"&gt;I left my job at Red Hat&lt;/a&gt; to
work on &lt;a href="https://github.com/purpleidea/mgmt/"&gt;mgmt config&lt;/a&gt; full-time. I&amp;rsquo;m still
passionate about this project, and I&amp;rsquo;m proud of the progress that has been made
in the last two years, but it&amp;rsquo;s time for me to explore new opportunities as
well. My years of experience building mgmt has taught me a lot about open
source, golang and mentoring others, and I hope this makes me a valuable
addition to your team.&lt;/p&gt;</description><author>The Technical Blog of James on purpleidea.com</author><pubDate>Thu, 10 Sep 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://purpleidea.com/blog/2020/09/10/james-is-available-for-hire/</guid></item><item><title>Go Modules have a v2+ Problem</title><link>https://donatstudios.com/Go-v2-Modules</link><description>&lt;p&gt;Go has a problem. Go modules place a strange naming requirement on modules version 2 or greater. Module names on modules v2+ must end in the major version ala &lt;code&gt;…/v2&lt;/code&gt;, and communication of this rule has been weak. It's non-obvious, and the community at large does not understand it.&lt;/p&gt;
&lt;p&gt;I have seen &lt;em&gt;many&lt;/em&gt; very large projects including Google owned projects get it wrong. &lt;/p&gt;
&lt;p&gt;I brought the issue up at my local Go meetup, and &lt;em&gt;no one&lt;/em&gt; had ever heard about the rule. They were very skeptical the rule existed at all.&lt;/p&gt;
&lt;h2&gt;A little history&lt;/h2&gt;
&lt;p&gt;For a long time Go did not include a built in method for versioning dependencies. It did include the &lt;a href="https://donatstudios.com/GithubsTotalSecurityFacepalm"&gt;sometimes controversial&lt;/a&gt; &lt;code&gt;go get&lt;/code&gt; method of fetching packages. The &lt;code&gt;go get&lt;/code&gt; tool &lt;a href="https://proxy.golang.org/"&gt;until recently&lt;/a&gt; simply cloned the HEAD of a packages primary branch based on URL and placed it in your &lt;code&gt;$GOPATH&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;In what has been oft linked to Go's &amp;quot;extremist position&amp;quot; on backwards compatibility, the expectation was largely that if you published a library, you were expected to maintain compatibility when at all possible. &lt;/p&gt;
&lt;p&gt;A plethora of tools popped up over the years to fill this void, &lt;a href="https://labix.org/gopkg.in"&gt;gopkg.in&lt;/a&gt;, &lt;a href="https://github.com/Masterminds/glide"&gt;glide&lt;/a&gt;, and even the &lt;em&gt;at one time&lt;/em&gt; &amp;quot;official experiment&amp;quot; &lt;a href="https://github.com/golang/dep"&gt;dep&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dep&lt;/code&gt; was the &lt;em&gt;heir apparent&lt;/em&gt; to dependency management with backing from Google. &lt;/p&gt;
&lt;p&gt;Seemingly suddenly however Russ &amp;quot;rsc&amp;quot; Cox sprung &lt;code&gt;vgo&lt;/code&gt; (aka Go Modules) &lt;a href="https://research.swtch.com/vgo-intro"&gt;onto the world&lt;/a&gt; as the official Go solution. There was seemingly no input from the community in its creation, to the chagrin of many. &lt;/p&gt;
&lt;p&gt;Whereas &lt;code&gt;dep&lt;/code&gt; was a largely &lt;em&gt;standard&lt;/em&gt; dependency manager in the vein of &lt;code&gt;npm&lt;/code&gt; and the like, Go modules is a decidedly opinionated &amp;quot;Go&amp;quot; solution. It's handled as part of the language as a build step. When you &lt;code&gt;go build&lt;/code&gt; if you are missing the versioned dependency, the build tool will fetch it.&lt;/p&gt;
&lt;p&gt;The dependencies requirements are listed in &lt;code&gt;go.mod&lt;/code&gt; and the exact versions expected  are in &lt;code&gt;go.sum&lt;/code&gt;. Both files are in their own sort of domain specific language. The prior has a syntax reminiscent of Go itself. The latter is a space separated list of dependency versions largely not intended for human consumption.&lt;/p&gt;
&lt;p&gt;The build step will add to these files as necessary, and running &lt;code&gt;go mod tidy&lt;/code&gt; will clean them up.&lt;/p&gt;
&lt;h2&gt;The v2+ problem in detail&lt;/h2&gt;
&lt;p&gt;Go modules place a very strange requirement on package developers. When a module hits major version 2 or higher, the module name &lt;strong&gt;must&lt;/strong&gt; end in the major version. The advantage to this is it creates a separate package. The result is that a project can now depend on multiple major versions of the same library.&lt;/p&gt;
&lt;p&gt;There are two tactics to achieving &lt;code&gt;/v2&lt;/code&gt; modules:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The first method&lt;/strong&gt; is to change the module name in your &lt;code&gt;go.mod&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;An example may seen
in the &lt;code&gt;go.mod&lt;/code&gt; of &lt;a href="https://github.com/google/go-github/blob/34cb1d623f03e277545da01608448d9fea80dc3b/go.mod#L1"&gt;github.com/google/go-github&lt;/a&gt; seems simple enough, but requires you to also change any cross references within your package. While not the end of the world, it is error prone and &lt;a href="https://github.com/google/go-github/blob/34cb1d623f03e277545da01608448d9fea80dc3b/scrape/apps.go#L20"&gt;even &lt;em&gt;Google&lt;/em&gt; missed some&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The biggest problem with this method is that it breaks subpackages in non-module-aware versions of Go. As time goes by this becomes less important, but in older versions of Go the package name had to exactly match it's location. &lt;code&gt;https://github.com/pkg/foo&lt;/code&gt; could not be &lt;code&gt;github.com/pkg/foo/v2&lt;/code&gt; when there is no v2 directory. The Go Team acknowledging this trouble and patched rudimentary module support into point releases 1.9.7 and 1.10.3 of the Go language to help ease the transition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The second method&lt;/strong&gt; and the method the Go Team themselves promote is leaving your &lt;code&gt;v1&lt;/code&gt; project &lt;em&gt;as is&lt;/em&gt; in the root of your repo, and actually creating a &lt;code&gt;v2/&lt;/code&gt; subfolder containing your &lt;code&gt;v2&lt;/code&gt; library. &lt;/p&gt;
&lt;p&gt;This feels weird, but the advantage is it works cleanly with older versions of Go that do not understand modules. Off the top of my head I only knew of a single project that went this route, and they appear to have gone back on it.&lt;/p&gt;
&lt;p&gt;For what it's worth, the official Go Blog tried to clear the situation up some, and posted a write-up about it. &lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.golang.org/v2-go-modules"&gt;blog.golang.org/v2-go-modules&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Even as a seasoned developer, I found this write-up somewhat impenetrable. For how important and unusual of a requirement this is, the write-up is not accessible enough.&lt;/p&gt;
&lt;p&gt;Many projects including Buildkite's &lt;code&gt;terminal-to-html&lt;/code&gt; simply didn't know about the requirement until they &lt;a href="https://github.com/buildkite/terminal-to-html/issues/74"&gt;&lt;em&gt;forget to handle it&lt;/em&gt;&lt;/a&gt;, and end up publishing broken releases. A v2+ Go library with a &lt;code&gt;go.mod&lt;/code&gt; file, but not respecting the module v2+ rules is a compile time error for dependants. This is worse for users than not being a Go module at all.&lt;/p&gt;
&lt;p&gt;Some projects like GORM sidestep the issue entirely by &lt;a href="https://gorm.io/docs/v2_release_note.html#Install:~:text=%2F%2F%20**NOTE**%20GORM%20%60v2.0.0%60%20released%20with%20git%20tag%20%60v1.20.0%60"&gt;tagging their 2.0 releases as far flung 1.x releases&lt;/a&gt;. That something of a solution, but smells terrible.&lt;/p&gt;
&lt;h2&gt;What's to be done?&lt;/h2&gt;
&lt;p&gt;First, I think the Go Team needs to do a better job of shining a light on this rule. They need to scream it from the rooftops. They need at the very least a section of the documentation that lays it out &lt;strong&gt;clearly and in layman's terms&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Beyond this, there's room for warnings from the Go tooling. Subpackages importing older versions of the root package should throw a warning. It's way too easy an issue to miss.&lt;/p&gt;
&lt;p&gt;There's room for similar notes on &lt;a href="https://godoc.org/"&gt;godoc.org&lt;/a&gt; / &lt;a href="https://pkg.go.dev/"&gt;pkg.go.dev&lt;/a&gt;, although the usefulness is questionable.&lt;/p&gt;
&lt;p&gt;The best and least likely option would be for Go to drop &lt;em&gt;the requirement&lt;/em&gt; and make it optional. I believe this is a workable solution. Packages who want to allow users to include multiple versions can follow the &lt;code&gt;v2&lt;/code&gt; guidelines, and others don't need to.&lt;/p&gt;
&lt;p&gt;An option I would personally promote, but is likely never going to happen, is to require &lt;code&gt;/v0&lt;/code&gt; and &lt;code&gt;/v1&lt;/code&gt; as well, such that you'd hit the issue right away rather than years into a project. Teach the convention early.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Discussion at: &lt;a href="https://news.ycombinator.com/item?id=24429045"&gt;news.ycombinator.com/item?id=24429045&lt;/a&gt;&lt;/p&gt;</description><author>Donat Studios</author><pubDate>Thu, 10 Sep 2020 09:11:12 GMT</pubDate><guid isPermaLink="true">https://donatstudios.com/Go-v2-Modules</guid></item><item><title>How to Install Hugo From Git Bash for Window Users</title><link>https://bartlomiejmika.com/posts/2020/how-to-install-hugo-from-git-bash-for-window-users/</link><description>&lt;p&gt;The purpose of this article is to help beginners understand how to do the &lt;a href="https://github.com/gohugoio/hugo#build-and-install-the-binaries-from-source-advanced-install"&gt;advanced install&lt;/a&gt; of &lt;a href="https://github.com/gohugoio/hugo"&gt;&lt;code&gt;hugo&lt;/code&gt;&lt;/a&gt; static site generator (SSG).&lt;/p&gt;</description><author>Bartlomiej Mika</author><pubDate>Thu, 10 Sep 2020 05:11:07 GMT</pubDate><guid isPermaLink="true">https://bartlomiejmika.com/posts/2020/how-to-install-hugo-from-git-bash-for-window-users/</guid></item><item><title>ErgoThink T420 Laptop Tray</title><link>https://peterlyons.com/problog/2020/09/ergothink-t420-laptop-tray/</link><description>&lt;p&gt;Last weekend I built a custom laptop tray design to fit my ThinkPad T480 laptop, my ergodox split keyboard, and my vertical mouse comfortably on my lap. We did 3 rounds of build/prototypes and I'm really happy with the one we have.&lt;/p&gt;
&lt;h2 id="motivation-and-context"&gt;Motivation and Context&lt;/h2&gt;
&lt;p&gt;I have two main setups where I do my computing. I have a sit/stand desk in my office well-appointed with tented split keyboard, vertical mouse, laptop stand putting the screen at proper height (which I also custom designed and built), etc. I also like to just use the laptop directly for brief sessions of reading and browsing where I don't have to do extensive typing.&lt;/p&gt;
&lt;p&gt;I wanted a way to work from the couch while also still having the great typing experience afforded by my ergodox keyboard. My ThinkPad T480 screen opens to a full 180 degrees which also puts the screen at a much more ergonomic position. I had a thought that if I could put the laptop fully open that might allow me to set up the ergodox where the laptop keyboard would normally be, turning the laptop keyboard into effectively just a monitor stand.&lt;/p&gt;
&lt;h2 id="conception"&gt;Conception&lt;/h2&gt;
&lt;p&gt;As these things generally go, I started to get ideas on a design while lying in bed trying unsuccessfully to fall asleep, so I got up and did some sketches in my notebook. The basic idea was to build a pair of C-shaped slots to hold the corners of the laptop down and then some curbs to keep the ergodox in a fixed position.&lt;/p&gt;
&lt;h2 id="prototyping"&gt;Prototyping&lt;/h2&gt;
&lt;p&gt;I was pretty excited to try it out and casting about in the shop we found some corner clamps we recently 3D printed just for fun that actually kind of worked to hold the laptop up. So that gave us a shortcut to a v1 prototype which we made out of 3/4" plywood for the base and some stacks of 1/2" plywood for the keyboard curbs.&lt;/p&gt;
&lt;p&gt;I was able to test that on Friday night and it worked, but the big piece of 3/4" plywood was really heavy and the slack in the corner clamps allowed the laptop to flap front to back quite a bit which made it a bit terrifying to carry around.&lt;/p&gt;
&lt;p&gt;But it was good enough to know the basic approach would be fine.&lt;/p&gt;
&lt;p&gt;So Saturday we did another version this time out of 1/2" plywood for everything. I designed some laptop clamps which had a pretty cool construction method:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rough cut some oversized rectangles big enough to make both sides of the clamp&lt;/li&gt;
&lt;li&gt;stack that 4 layers high and glue it up into a big block&lt;/li&gt;
&lt;li&gt;Then cut it down to final dimensions and square up the corners on the table saw sled
&lt;ul&gt;
&lt;li&gt;Cutting the long edge just barely fit in our sled's capacity&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The use a forstner bit to drill holes to fit where the laptop bottom pads go. Locate this so in the end it will be a semicircular cylinder slot instead of a full hole.&lt;/li&gt;
&lt;li&gt;Cut that in half&lt;/li&gt;
&lt;li&gt;On the table saw sled with the blade quite high, hog out the interior of the "C" shape and do test fits until sneaking up on a nice fit for the laptop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="v1 prototype" src="https://photos.peterlyons.com/2020/2020-09-03-01EHAV7T60C3X2ZPF2NJ9YAYS5.2048.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;We didn't get the construction fully dialed until v3 but once we did it's a good balance of easy to put the laptop in and take it out, but it's stable in use and also if you are walking around carrying the tray with you.&lt;/p&gt;
&lt;h2 id="v3-prototype"&gt;v3 prototype&lt;/h2&gt;
&lt;p&gt;v2 was much better but I wanted another crack at the laptop slots and a much smoother mouse area, so the next day we made v3 out of nice baltic birch plywood and sanded most surfaces at 80, 120, and 240 grit to get really smooth surfaces.&lt;/p&gt;
&lt;p&gt;&lt;img alt="v2 prototype" src="https://photos.peterlyons.com/2020/2020-09-06-01EHHK9EGG739N9SRK424J61AR.2048.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I bought the smallest hinges they sell at Lowe's and made some collapsible keyboard tenting supports. These ended up feeling really stable and solid.&lt;/p&gt;
&lt;h2 id="finishing-touches"&gt;Finishing touches&lt;/h2&gt;
&lt;p&gt;The gap between the ergodox and the laptop is small. Not even 2", so with the TRRS and USB cables coming out of the ergodox in that direction, they were feeling and looking cramped. I found a 9" TRRS cable with 90 degree connectors that fit the space perfectly and also a 6" mini USB to USB A 90-degree cable so now everything has just a tiny bit of slack so they can be comfortably connected and disconnected but are so well-sized that they don't dangle down onto the tray at all and have no need for coiling or cable management of any kind.&lt;/p&gt;
&lt;p&gt;&lt;img alt="over shoulder view" src="https://photos.peterlyons.com/2020/2020-09-08-01EHQSTED8R68CKYDMQJG0P5A9.2048.jpg" /&gt;&lt;/p&gt;
&lt;h2 id="putting-it-to-use"&gt;Putting it to Use&lt;/h2&gt;
&lt;p&gt;I'm planning a writing retreat later this month so this setup should get a lot of use. I'm looking forward to it!&lt;/p&gt;
&lt;h2 id="dual-purpose"&gt;Dual-Purpose&lt;/h2&gt;
&lt;p&gt;The icing on this cake was sort of a surprise. I can leave the whole tray/rig set up, place it on my desk, and it works fine there too. So this will replace the custom stand I built earlier and all I do to "undock" from the desk is disconnect the power cable and carry the tray away.&lt;/p&gt;
&lt;h2 id="build-photo-gallery"&gt;Build Photo Gallery&lt;/h2&gt;



&lt;div class="plop-album"&gt;
  &lt;figure class="album-viewer"&gt;
    &lt;img alt="" class="album-photo" src="https://peterlyons.com/problog/2020/09/ergothink-t420-laptop-tray/" /&gt;
  &lt;/figure&gt;
  &lt;div class="album-controls"&gt;
    &lt;button class="album-btn album-prev"&gt;&amp;larr; Prev&lt;/button&gt;
    &lt;span class="album-counter"&gt;&lt;/span&gt;
    &lt;button class="album-btn album-next"&gt;Next &amp;rarr;&lt;/button&gt;
  &lt;/div&gt;
  &lt;figcaption class="album-caption"&gt;&lt;/figcaption&gt;

  
&lt;/div&gt;</description><author>Pete's Points</author><pubDate>Thu, 10 Sep 2020 04:23:21 GMT</pubDate><guid isPermaLink="true">https://peterlyons.com/problog/2020/09/ergothink-t420-laptop-tray/</guid></item><item><title>San Francisco Hellscapes</title><link>https://faingezicht.com/photos/2020/09/10/bladerunner-sf/</link><description>In previous years, when fire season came around I took photos of the city skyline, complained about the raining ash, and marveled at how fires hundreds of miles away can impact our daily lives so much. Unfortunately, this is something I'm used to now, but yesterday was different. The air quality has been much worse than it was yesterday, even in recent weeks, but the sheer mindfuck of seeing the whole city shrouded in orange from dawn to dusk made it a truly surreal day.

I took most of the photos below around 1PM. There's minimal postprocessing, and the little color correction that I did was to get the white balance closer to reality, instead of the reddish tones that the camera applied to the photos. If anything, these look a bit over exposed, brighter than reality. We’ve worked _hard_ on making our cameras capture light to seem realistic under normal conditions, so it’s easy to forget technology does not actually capture reality. It's hard to get this right. The map is not the territory.</description><author>Avy Faingezicht</author><pubDate>Thu, 10 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/photos/2020/09/10/bladerunner-sf/</guid></item><item><title>Against Namespacing Personal Sites</title><link>https://www.swyx.io/namespacing-sites</link><description>I care a lot about creating Cool URIs so I have been paralyzed more than I should be about what I'm calling "URL Architecture". In true fashion, I'm blogging about it.</description><author>swyx's site RSS Feed</author><pubDate>Thu, 10 Sep 2020 01:15:08 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/namespacing-sites</guid></item><item><title>2020–09–10: PinePhone multi-boot image deduplication</title><link>https://xnux.eu/log/#010</link><author>megi's PinePhone Development Log</author><pubDate>Thu, 10 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#010</guid></item><item><title>Notes About Compilers</title><link>https://venam.net/blog/programming/2020/09/10/compiler_notes.html</link><description>Compilers, these wonderful and intricate pieces of software that do so much and that so many know little of. Similar to the previous article about computer architecture, I'll take a look at another essential, but lesser known, CS topic, Compilers.  I won't actually dive into much details but I'll keep it short to my notes, definitions, and what I actually found intriguing and helpful.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Thu, 10 Sep 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/programming/2020/09/10/compiler_notes.html</guid></item><item><title>What is the Value of Open Source Hardware Development?</title><link>https://stop.zona-m.net/2020/09/what-is-the-value-of-open-source-hardware-development/</link><description>&lt;p&gt;Sometimes, the value is in what you do NOT waste.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 09 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/what-is-the-value-of-open-source-hardware-development/</guid></item><item><title>List of JavaScript GUI Control libraries (dat.GUI alternatives)</title><link>https://xosh.org/javascript-control-ui/</link><description>These libraries can be used to quickly create a GUI for configureable parameters using sliders, checkboxes, colors pickers etc. dat.GUI is the most famous one and can be found in many canvas based demos. This is a list of dat.GUI and it&amp;rsquo;s alternatives.
To view preview HTML directly from Github you can use https://htmlpreview.github.io/ or https://raw.githack.com/ (rawgit bookmarklet). I have added raw.githack links for some demos.
dat.GUI https://github.com/dataarts/dat.gui
Tweakpane https://cocopon.github.io/tweakpane/</description><author>XOSH.ORG</author><pubDate>Wed, 09 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xosh.org/javascript-control-ui/</guid></item><item><title>Whoops! Page not found</title><link>https://b.agilob.net/404.html</link><description>That page can&amp;rsquo;t be found.
Our latest content is on the homepage.
Photo by Aron Visuals on Unsplash</description><author>Random Notes by agilob</author><pubDate>Tue, 08 Sep 2020 23:40:23 GMT</pubDate><guid isPermaLink="true">https://b.agilob.net/404.html</guid></item><item><title>The first thing to know about Artificial Intelligence? Its myths</title><link>https://stop.zona-m.net/2020/09/the-first-thing-to-know-about-artificial-intelligence-its-myths/</link><description>&lt;p&gt;Of course. What else?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 08 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/the-first-thing-to-know-about-artificial-intelligence-its-myths/</guid></item><item><title>How to Set Up SvelteKit with Tailwind CSS</title><link>https://www.swyx.io/svelte_tailwind_setup</link><description>A quick 3 step guide for myself on how to set up Svelte with Tailwind CSS</description><author>swyx's site RSS Feed</author><pubDate>Tue, 08 Sep 2020 19:30:58 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/svelte_tailwind_setup</guid></item><item><title>What it means to not test implementation details in React</title><link>https://maxrozen.com/dont-test-implementation-details-react</link><description>Most guides to testing React these days preach: 'Test functionality, not implementation details'. This article explains what that means, and how to do it.</description><author>Max Rozen</author><pubDate>Tue, 08 Sep 2020 12:48:48 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/dont-test-implementation-details-react</guid></item><item><title>2020–09–08: PinePhone multi-boot finishing touches / modem improvements</title><link>https://xnux.eu/log/#009</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 08 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#009</guid></item><item><title>2020–09–08: PinePhone multi-boot image optimizations</title><link>https://xnux.eu/log/#008</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 08 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#008</guid></item><item><title>[Computing] A brief introduction to SCSI</title><link>https://www.devever.net/~hl/scsi</link><description>&lt;p&gt;&lt;strong&gt;Introduction.&lt;/strong&gt; SCSI is an I/O subsystem architecture to allow I/O
peripherals to be attached to a system. It has over the years been used to
attach devices such as hard disk drives, SSDs, floppy drives, optical drives,
tape drives, media changers (for e.g. optical or tape media), RAID controllers
and storage enclosures containing other SCSI devices. In the past it has also
been used to attach scanners, printers and network interfaces. Today, it is
primarily used to attach hard drives, SSDs, optical drives, tape drives and
devices which support these (like medium changers for tape drives, RAID
controllers and storage enclosures). Other applications, such as scanners,
printers and network interfaces have long since moved to interfaces like USB or
PCI(e). SCSI itself evolved from, and is substantially influenced by, the
channel I/O system of IBM System/360 mainframes.&lt;/p&gt;</description><author>devever.net/~hl</author><pubDate>Mon, 07 Sep 2020 23:27:00 GMT</pubDate><guid isPermaLink="true">https://www.devever.net/~hl/scsi</guid></item><item><title>How to Start a Personal Blog With Hugo a Static Site Generator Written in Go (Part 2)</title><link>https://bartlomiejmika.com/posts/2020/how-to-start-a-personal-blog-with-hugo-a-static-site-generator-written-in-go-part-2/</link><description>&lt;p&gt;The purpose of this article is to help you deploy your website to the internet.&lt;/p&gt;</description><author>Bartlomiej Mika</author><pubDate>Mon, 07 Sep 2020 22:35:08 GMT</pubDate><guid isPermaLink="true">https://bartlomiejmika.com/posts/2020/how-to-start-a-personal-blog-with-hugo-a-static-site-generator-written-in-go-part-2/</guid></item><item><title>How to Start a Personal Blog With Hugo a Static Site Generator Written in Go (Part 1)</title><link>https://bartlomiejmika.com/posts/2020/how-to-start-a-personal-blog-with-hugo-a-static-site-generator-written-in-go-part-1/</link><description>&lt;p&gt;The purpose of this article is to help you setup a personal blog as quickly as possible. These are the instructions and notes I&amp;rsquo;ve written down when setting up my site that I&amp;rsquo;d like to share.&lt;/p&gt;</description><author>Bartlomiej Mika</author><pubDate>Mon, 07 Sep 2020 22:35:07 GMT</pubDate><guid isPermaLink="true">https://bartlomiejmika.com/posts/2020/how-to-start-a-personal-blog-with-hugo-a-static-site-generator-written-in-go-part-1/</guid></item><item><title>If You Sell Anything Online, This Book Will Make You Money</title><link>https://www.swyx.io/rob_hope_hot_tips</link><description>My glowing review of Rob Hope's Landing Page Hot Tips Book</description><author>swyx's site RSS Feed</author><pubDate>Mon, 07 Sep 2020 22:16:56 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/rob_hope_hot_tips</guid></item><item><title>NO CONSPIRACIES NEEDED HERE</title><link>https://stop.zona-m.net/2020/09/no-conspiracies-needed-here/</link><description>&lt;p&gt;Focus on change, instead.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 07 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/no-conspiracies-needed-here/</guid></item><item><title>Monterey Bay</title><link>https://faingezicht.com/photos/2020/09/07/monterey/</link><description>The first weekend after I got back to the US, Amol and Annabelle invited us to drive down to Monterey with them. Because of the fires, and because of COVID, we weren't sure the trip was going to work out, but it did, and I took a ton of photos.</description><author>Avy Faingezicht</author><pubDate>Mon, 07 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/photos/2020/09/07/monterey/</guid></item><item><title>Are we in a bubble? A look at the brave new world of zero rates</title><link>https://omarabid.com/zero-rates-world/</link><description>Explaining asset's price appreciation</description><author>Omar Abid - Personal Blog</author><pubDate>Mon, 07 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://omarabid.com/zero-rates-world/</guid></item><item><title>The case for comments in code</title><link>http://notes.eatonphil.com/the-case-for-comments-in-code.html</link><description>&lt;p&gt;When I first started programming, especially when asked for code
samples, my comments lacked purpose and would often duplicate in
English what the code clearly indicated. I knew that "commenting is
good" but as a beginner I had no further insight.&lt;/p&gt;
&lt;p&gt;Over time with the help of books like Clean Code, I grew disdainful of
comments. Good code should be self-documenting. Whenever I needed to
write a comment to explain something, I'd realize I could easily
rename some key variable or function. I grew more comfortable with
variables and functions with a few words in the title. Better to spend
time on good code structure and naming.&lt;/p&gt;
&lt;p class="note"&gt;
  I have always left TODOs though, since TODOs can't so easily be
  expressed in variable names. But even these TODOs concerned me
  because they existed in my issue tracker, or maybe should have.
&lt;/p&gt;&lt;p&gt;As I watched mature open source projects and mature engineers, I came
to value well-documented pull requests. Solid pull requests include or
link to all necessary background, opportunities failed or ignored, how
to use, links to external bugs requiring workarounds and the results
of performance evaluation.&lt;/p&gt;
&lt;p&gt;Beyond pull request descriptions, when I really wanted to grease a
pull request I'd use the pull request UI to add comments calling
reviewer attention to key changes in lines of the diff.&lt;/p&gt;
&lt;p&gt;Both kinds of guidance are a massive aid to reviewers, saving a lot of
time.&lt;/p&gt;
&lt;p&gt;But when I'd find a bug in code -- and I knew there was good pull
request documentation, even for pull requests as recent as six months
ago -- I've been repeatedly failed by the pull request and &lt;em&gt;pull
request comment&lt;/em&gt; search exposed by Github and Gitlab.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;knew&lt;/em&gt; there were links to documented oddities or bug reports in
pull request threads. But practically speaking, for historic pull
requests, pull request comments are useless.&lt;/p&gt;
&lt;p&gt;This is the single biggest reason I've started to push for more
comments in code. More so than all other tools (issue tracker, code
management system, etc.) comments in code have the greatest chance of
still being around and &lt;em&gt;easily searchable&lt;/em&gt; if they haven't been
deleted.&lt;/p&gt;
&lt;p class="note"&gt;
  Don't get me started on pull request documentation in an external
  medium like Slack. It's so rewarding to get or give instant feedback
  on changes on instant messengers, but good luck finding that
  discussion 3 months later.
&lt;/p&gt;&lt;p&gt;Every time I have to call out a line of code in a pull request, that's
immediate cause for that code to be modified with comments.&lt;/p&gt;
&lt;p&gt;Maybe I wouldn't do this if Github/Gitlab exposed a Google Docs-like
interface for browsing code line by line with links to all pull
request comment threads.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;The biggest reason to add comments in code (often linking to documented oddities or bug reports) is because it's impossible to search pull request threads historically in every source control management UI I've used.&lt;a href="https://t.co/JlHWfbUH5z"&gt;https://t.co/JlHWfbUH5z&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1303130504993136642?ref_src=twsrc%5Etfw"&gt;September 8, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Mon, 07 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/the-case-for-comments-in-code.html</guid></item><item><title>2020–09–07: PinePhone multi-boot image boot testing</title><link>https://xnux.eu/log/#007</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 07 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#007</guid></item><item><title>American Airlines is an e-currency company that happens to own some planes</title><link>https://jonlu.ca/posts/american-airlines</link><description>Examining how airline loyalty currencies shape American Airlines as much as flying passengers does.</description><author>JonLuca's Blog</author><pubDate>Sun, 06 Sep 2020 23:09:56 GMT</pubDate><guid isPermaLink="true">https://jonlu.ca/posts/american-airlines</guid></item><item><title>Now is the winter of our post-lockdown life...</title><link>https://stop.zona-m.net/2020/09/now-is-the-winter-of-our-post-lockdown-life.../</link><description>&lt;p&gt;&amp;hellip;looking more uncertain than ever.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sun, 06 Sep 2020 12:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/now-is-the-winter-of-our-post-lockdown-life.../</guid></item><item><title>The Rise of Chaos - Leaping to Tier 2</title><link>http://spirals.blog/articles/tier-2/</link><description>&lt;p&gt;In the development of human perspective, there exists a &lt;em&gt;profound&lt;/em&gt; leap. This shift is different from anything we’ve experienced before. It’s not the same as the expressive shift from Purple to Red. Or at all like the organized assembly from Red into Blue. Neither is it akin to the liberating force of Orange out of Blue’s box. Nor does it resemble the harmonious renouncing of Orange intro Green. It presents something else entirely.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Up until now, “our perspectives” have dominated “our thinking.” The values, beliefs, behaviors, and ways of life have stemmed from the way we are currently solving life’s problems. Our colors have held us hostage in a sense, you see. They have been Fighting over each-other for control, disagreeing with each other, and even going to war.&lt;/p&gt;
&lt;p&gt;Green introduces a concept that we should be solving OTHER people’s problems, and is dedicated to doing so. Towards the end of Green’s cycle, some things begin to make sense. Or rather, not make sense. Many aspects of life start to fall apart, actually. In all of Green’s attempts to bring justice and harmony to the world, and despite its struggles, protests, committees, and non-for-profits, there is just &lt;em&gt;too much complexity&lt;/em&gt; to come to a unanimous decision.&lt;/p&gt;
&lt;p&gt;Naively, Green believes that the group will always come to the &lt;strong&gt;right conclusion&lt;/strong&gt;. It operates as a whole, serving minorities and the down-trodden, insisting that, with kindness and openness, it can “fix the world.” But the reality is much deeper than this. Because Green’s scope of awareness is so expansive, it takes on the world. Naturally, things become far more complicated. Put simply, there is no &lt;em&gt;easy&lt;/em&gt; answer to climate change, racism, or the energy crisis.&lt;/p&gt;
&lt;h2&gt;“Maybe we don’t have the answers”&lt;/h2&gt;
&lt;p&gt;Beyond peak Green, we awaken to how &lt;em&gt;&lt;strong&gt;the way we’ve been living until now is causing more problems than it’s solving.&lt;/strong&gt;&lt;/em&gt; Each color believes it has the answers, but it only has a part of the bigger picture. Despite all our efforts to fix things, they’ve only gotten worse since we’ve entered Green.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s [Green] a very warm system, but the person gets so tied up in this business of attempting to express self or attempting to let others express. So, because he or she doesn’t have to worry about trying to stay alive, or trying to overcome the storm (or things of that sort) that it sort of loses sight of the fact that you gotta do something to stay alive around here!&lt;br /&gt;
– Clare Graves - &lt;a href="https://youtu.be/tt3Uk1f3y_U?t=3138"&gt;In Conversation with Clare W. Graves. (Youtube)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Beyond peak Green, one begins to see the cracks of the well-intentioned councils and board panels. As much as we do not want to admit it, &lt;strong&gt;our group does not seem to have the answers&lt;/strong&gt;. Those still pulled by a strong Green will work with others to try to find the answer. It takes a strong reason or something that has gone very wrong to push a Green out of the collective.&lt;/p&gt;
&lt;p&gt;However, we’ve entered a time in our history where answers &lt;em&gt;&lt;strong&gt;must&lt;/strong&gt;&lt;/em&gt; be generated. The very survival of our species depends on it. As Green’s “collective wisdom” breaks down, we find ourselves searching for answers wherever we can get them – regardless of where it comes from.&lt;/p&gt;
&lt;h2&gt;From “Surviving” to “Being” - A Spiral Reset&lt;/h2&gt;
&lt;p&gt;The leap into Yellow from Green interestingly presents many similar life conditions to that of Beige. The chaos of the wild is re-introduced as the complexities of modern life. This time much harder. One might say the Great Spiral is reset.&lt;/p&gt;
&lt;p&gt;The shift to Tier 2 is like a song that changes key in the middle. It sounds similar, follows a very familiar if not identical pattern of melodies and chords, but is &lt;strong&gt;fundamentally different&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tier 1 (Beige–Green) exists in a very &lt;strong&gt;survivalist mentality&lt;/strong&gt;, doing what it can to solve the problems in its life. Tier 1 colors are fixated on having, wanting, needing, and acting in ways to end the feeling of shortcomings.&lt;/p&gt;
&lt;p&gt;Beyond Green, Tier 2 focuses on the survival of not just oneself, but the entire Spiral as a whole. As such, the need of the individual &lt;em&gt;truly&lt;/em&gt; shrink, and along with it, the fear associated with losing what one has in Tier 1. Tier 2 perspective shifts into a mode of &lt;strong&gt;“being”&lt;/strong&gt; with reality as &lt;em&gt;&lt;strong&gt;it is, not as we want it to be.&lt;/strong&gt;&lt;/em&gt; Accepting and seeking out the natural order. A radically alternative lens in which to see our world.&lt;/p&gt;
&lt;h2&gt;A call for better thinking and empathy&lt;/h2&gt;
&lt;p&gt;Bluntly, there are not enough of us who are thinking in these terms. The problems we are now facing as a species appear insurmountable because we don’t understand each other and are not working together.&lt;/p&gt;
&lt;p&gt;Tools like Spiral give us frameworks to understand others (even if we vehemently disagree with them). If you are reading this, I implore you to find someone who, like you, is interested in this, and share it with them. We are not enough as it currently stands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Empathy and intelligence are on the rise, but not as fast as the sea levels.&lt;/strong&gt; We need you; we need more. Humanity needs the action-oriented empaths and the harmonious problem-solvers.&lt;/p&gt;
&lt;p&gt;If you are resonating, if you recognize the importance of this call, please consider &lt;a href="https://join.slack.com/t/spiralsblog/shared_invite/zt-h4zmiolw-tCZAYSJn2YNm5bMcvYaoQA"&gt;joining our open slack channel&lt;/a&gt;. All are welcome. All are needed.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 06 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/tier-2/</guid></item><item><title>Which company wants to make it easier to punish researchers...</title><link>https://stop.zona-m.net/2020/09/which-company-wants-to-make-it-easier-to-punish-researchers.../</link><description>&lt;p&gt;&amp;hellip;for finding flaws in its software?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 05 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/which-company-wants-to-make-it-easier-to-punish-researchers.../</guid></item><item><title>Passing AWS Solution Architect Associate</title><link>https://prashamhtrivedi.in/passing_aws_saa.html</link><description>This is the post about AWS Solution Architect Exam and tips to pass the exam.</description><author>Prasham H Trivedi</author><pubDate>Sat, 05 Sep 2020 15:25:20 GMT</pubDate><guid isPermaLink="true">https://prashamhtrivedi.in/passing_aws_saa.html</guid></item><item><title>The most efficient way to solve problems: not having them</title><link>https://lucasfcosta.com/blog/not-having-problems/</link><description>It's Monday. The first of the seven alarms you've set on your phone soars louder than the Big Ben. It sends chills down your spine announcing the impending doom: your 8 AM commute. You put on that wh...</description><author>Lucas F. Costa - Blog</author><pubDate>Sat, 05 Sep 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://lucasfcosta.com/blog/not-having-problems/</guid></item><item><title>How we recharged the team with a fallow week</title><link>https://ilearnt.com/blog/fallowweek/</link><description>&lt;p&gt;Due to the ongoing COVID situation the team had been struggling to stay focussed and motivated. The inability to go out, the lack of change of scenery and the sameness every day has been taking its toll. To try to address this we actively encouraged them to take time off - which, given the limitations on travel, was less appealing than it normally would be.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sat, 05 Sep 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/fallowweek/</guid></item><item><title>Goat Lake</title><link>https://sam.hooke.me/trip/2020/09/goat-lake/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;p&gt;No trip report yet.&lt;/p&gt;</description><author>Sam Hooke</author><pubDate>Sat, 05 Sep 2020 06:30:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/09/goat-lake/</guid></item><item><title>London to Orkney, and most of the NC500, in an electric car</title><link>https://michael-lewis.com/posts/london-to-orkney-and-most-of-the-nc500-in-an-electric-car/</link><description>&lt;h2 id="introduction"&gt;
  Introduction
  &lt;a class="heading-link" href="#introduction"&gt;
    &lt;i class="fa-solid fa-link" title="Link to heading"&gt;&lt;/i&gt;
    &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
  &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;A few years back, I was an avid reader of long distance electric vehicle road trip reports. It seemed like the people making them were intrepid pioneers in a new era of transportation. Well here&amp;rsquo;s my slightly belated contribution to the genre.&lt;/p&gt;
&lt;h2 id="summary"&gt;
  Summary
  &lt;a class="heading-link" href="#summary"&gt;
    &lt;i class="fa-solid fa-link" title="Link to heading"&gt;&lt;/i&gt;
    &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
  &lt;/a&gt;
&lt;/h2&gt;
&lt;h3 id="route"&gt;
  Route
  &lt;a class="heading-link" href="#route"&gt;
    &lt;i class="fa-solid fa-link" title="Link to heading"&gt;&lt;/i&gt;
    &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
  &lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Route and summary" src="https://michael-lewis.com/images/roadtrip-routeandsummary.jpg" /&gt;&lt;/p&gt;</description><author>Michael Ian Lewis</author><pubDate>Sat, 05 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://michael-lewis.com/posts/london-to-orkney-and-most-of-the-nc500-in-an-electric-car/</guid></item><item><title>My time fighting COVID-19 as a CDC software engineer</title><link>https://daniel.do/article/my-time-fighting-covid-19-as-a-cdc-software-engineer</link><description>The most stressful period of my career.</description><author>Daniel Immke</author><pubDate>Sat, 05 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://daniel.do/article/my-time-fighting-covid-19-as-a-cdc-software-engineer</guid></item><item><title>Quarantine in the 1600s</title><link>https://lambdaland.org/posts/2020-09-05-quarantine-in-1600s/</link><description>&lt;p&gt;It’s been a long six months that we’ve been under quarantine and other disease-limiting measures. It hasn’t been easy, but thanks to something I saw at &lt;a class="link-external" href="https://en.wikipedia.org/wiki/K%C3%B6nigstein_Fortress" rel="external"&gt;Königsstein Fortress&lt;/a&gt; I’m not complaining. Here’s why:&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Sat, 05 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-09-05-quarantine-in-1600s/</guid></item><item><title>Gem Island</title><link>https://nickp.svbtle.com/gem-island</link><description>&lt;p&gt;Are you fresh off the back of the long weekend and looking to sink your teeth into some combinatorics and induction? Great then you’ve come to the right place so pull your discrete mathematician stocking over your head and let’s get started. &lt;/p&gt;

&lt;p&gt;Welcome to Gem Island! Home to &lt;code class="prettyprint"&gt;N&lt;/code&gt; happy islanders. Each of which has exactly one gem. Each night something peculiar happens. One of the gems on the island is chosen uniformly at random and it splits creating a new gem for the owner. This process repeats each night for &lt;code class="prettyprint"&gt;D&lt;/code&gt; nights. Here is an example of all 6 situations that could arise if there were (&lt;code class="prettyprint"&gt;N=2&lt;/code&gt;) islanders after (&lt;code class="prettyprint"&gt;D=2&lt;/code&gt;) nights. Here we’ve coloured the first islander’s gems red, the second green and the vertical bar separates the islanders to make things easier to read. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/kDZiWq8aXQuhxS96SLYYix0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-04 at 3.41.42 PM.png" src="https://svbtleusercontent.com/kDZiWq8aXQuhxS96SLYYix0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are interested in the expected value, of the number of gems, the &lt;code class="prettyprint"&gt;R&lt;/code&gt; richest islanders have. In the case above the &lt;code class="prettyprint"&gt;R=1&lt;/code&gt; richest islanders has on average &lt;code class="prettyprint"&gt;(3 + 3 + 2 + 2 + 3 + 3) / 6&lt;/code&gt; gems. Where as the &lt;code class="prettyprint"&gt;R=2&lt;/code&gt; richest islanders would have&lt;code class="prettyprint"&gt;( (3+1) + (3+1) + (2+2) + (2+2) + (1+3) + (1+3) ) / 6 = N + D&lt;/code&gt;. In fact if &lt;code class="prettyprint"&gt;N &amp;lt;= R&lt;/code&gt; the answer is going to be &lt;code class="prettyprint"&gt;N + D&lt;/code&gt; because at the end of the process there is always the same number of total gems on the island. So we have our problem and it’s completely described by just three numbers &lt;code class="prettyprint"&gt;N&lt;/code&gt;, &lt;code class="prettyprint"&gt;D&lt;/code&gt; and &lt;code class="prettyprint"&gt;R&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before looking for a solution to the actual problem let’s simulate out a few more examples. Here’s what things would look like with &lt;code class="prettyprint"&gt;N=3&lt;/code&gt; islanders after &lt;code class="prettyprint"&gt;D=2&lt;/code&gt; nights.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/pppbii7vD4HGvHFzHusBUU0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-04 at 3.41.25 PM.png" src="https://svbtleusercontent.com/pppbii7vD4HGvHFzHusBUU0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s the situation for &lt;code class="prettyprint"&gt;N=3&lt;/code&gt; and &lt;code class="prettyprint"&gt;D=3&lt;/code&gt;. Things are exploding a bit and there are 60 final distributions of gems in the leaves of the tree. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/xufbGqVLjw3tiyYy6h7xCT0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-04 at 3.41.04 PM.png" src="https://svbtleusercontent.com/xufbGqVLjw3tiyYy6h7xCT0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What about &lt;code class="prettyprint"&gt;N=4&lt;/code&gt; islanders after &lt;code class="prettyprint"&gt;D=3&lt;/code&gt; days? Just showing the final distributions, there are 120:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/iZHDhgBbP1WGn5YXYAciLT0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-08 at 9.18.21 AM.png" src="https://svbtleusercontent.com/iZHDhgBbP1WGn5YXYAciLT0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You get the idea. So before attempting to solve this problem it’s interesting to consider 3 related questions. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many distributions of gems are possible? &lt;/li&gt;
&lt;li&gt;How many of them are unique? &lt;/li&gt;
&lt;li&gt;How many of them are unique permutations (not permutations of others)? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using the example of &lt;code class="prettyprint"&gt;N=2&lt;/code&gt; and &lt;code class="prettyprint"&gt;D=2&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/r7cWuqAKPiYx5xLjMmJ2iP0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-04 at 3.41.42 PM.png" src="https://svbtleusercontent.com/r7cWuqAKPiYx5xLjMmJ2iP0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are 6 total distributions:&lt;br /&gt;
&lt;code class="prettyprint"&gt;(3,1)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(3,1)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(2,2)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(2,2)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(1,3)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(1,3)&lt;/code&gt; of which 3 are unique: &lt;code class="prettyprint"&gt;(1,3)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(3,1)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(2,2)&lt;/code&gt; and 2 are unique permutations: &lt;code class="prettyprint"&gt;(3,1)&lt;/code&gt; and &lt;code class="prettyprint"&gt;(2,2)&lt;/code&gt; because &lt;code class="prettyprint"&gt;(3,1)&lt;/code&gt; is a permutation of &lt;code class="prettyprint"&gt;(1,3)&lt;/code&gt;. Now we could stop there and it would be fun to come up with answers to those three questions. &lt;/p&gt;

&lt;p&gt;Let’s answer that first questions because the diagram above gives a good illustration. How many distributions of gems are there are there for a given &lt;code class="prettyprint"&gt;N&lt;/code&gt; and &lt;code class="prettyprint"&gt;D&lt;/code&gt;? Well there are &lt;code class="prettyprint"&gt;N&lt;/code&gt; possible transitions from the first state, then &lt;code class="prettyprint"&gt;N+1&lt;/code&gt;, then &lt;code class="prettyprint"&gt;N+2&lt;/code&gt; and so on, &lt;code class="prettyprint"&gt;D&lt;/code&gt; times. So the number of final distributions of gems that are possible are &lt;code class="prettyprint"&gt;N * (N+1) * ... * (N+D-1)&lt;/code&gt;. It looks like numbers of this form are called &lt;a href="https://en.wikipedia.org/wiki/Falling_and_rising_factorials"&gt;rising factorials&lt;/a&gt;: &lt;code class="prettyprint"&gt;RF(N, D) = N * (N+1) * ... * (N+D-1)&lt;/code&gt;. &lt;/p&gt;
&lt;h2 id="solution-1-on_2"&gt;Solution 1 - O(N!) &lt;a class="head_anchor" href="#solution-1-on_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This actually gives us our first solution to the problem. If we could count the number of gems the &lt;code class="prettyprint"&gt;R&lt;/code&gt; riches islanders have in each of the &lt;code class="prettyprint"&gt;RF(N, D&lt;/code&gt;) distributions we could divide by that number and that would give us an answer. Coding this up requires completely enumerating all the final distributions and then summing up the &lt;code class="prettyprint"&gt;R&lt;/code&gt; highest value in each one. Slow and steady can win the race:&lt;/p&gt;

&lt;pre&gt;&lt;code class="prettyprint lang-python"&gt;def rf(N, D):
    """
    rising factorial - returns n * (n+1) ... * (n+d-1)
    """
    ret = 1
    for x in range(D):
        ret *= (x + D)
    return ret

def recurse(N, D, R, gems):


    if D == 0:
        counts = [0] * N
        for g in gems:
            counts[g-1] += 1

        # return the sum of gems R richest islanders have
        return sum(sorted(counts)[::-1][:R])

    ret = 0
    for g in gems:
        gems.append(g)
        ret += recurse(N, D - 1, R, gems)
        gems.pop(-1)
    return ret

if __name__ == '__main__':
    N, D, R = 2, 2, 1 
    # gems stores which islanders owns which gems. 
    # g[a] = b mean the a'th gem is owned by islander b
    # start with each of the n islanders having one gem. 
    # gems = [1, 2, ..., n]
    gems = [ x for x in range(1, N + 1)]
    sumr = complete_enumeration(D, N, R, gems)
    expected = sumr / rf(N, D)
    print(expected)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;While correct this solution is going to be offensively slow, in the order of &lt;code class="prettyprint"&gt;O(N!)&lt;/code&gt; so let’s try and find something faster. Let’s look back at all the distributions possible from &lt;code class="prettyprint"&gt;N=3&lt;/code&gt; and &lt;code class="prettyprint"&gt;D=3&lt;/code&gt; again:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/69y2tfzAaqTbLgHw8DChBF0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-05 at 1.13.59 PM.png" src="https://svbtleusercontent.com/69y2tfzAaqTbLgHw8DChBF0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that there are 60 different distributions but lots of them are duplicates and there are only 10 unique distributions: &lt;code class="prettyprint"&gt;(4,1,1)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(1,4,1)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(1,1,4)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(2,2,2)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(1,2,3)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(1,3,2)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(2,1,3)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(2,3,1)&lt;/code&gt;, &lt;code class="prettyprint"&gt;(3,1,2)&lt;/code&gt; and &lt;code class="prettyprint"&gt;(3,2,1)&lt;/code&gt;. How do we compute that &lt;code class="prettyprint"&gt;10&lt;/code&gt; directly from &lt;code class="prettyprint"&gt;N&lt;/code&gt; and &lt;code class="prettyprint"&gt;D&lt;/code&gt;? Firstly the sum of elements is always &lt;code class="prettyprint"&gt;D+N&lt;/code&gt;. Also, and surprisingly ,. each of these unique distributions is also equally likely and in the case of &lt;code class="prettyprint"&gt;N=D=3&lt;/code&gt; will appear 6 times. This is not super obvious so we should probably try and prove that as it would mean we only need to consider many fewer distributions. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/6KAK9wnXXvzY8z675M9i2W0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-05 at 1.13.45 PM.png" src="https://svbtleusercontent.com/6KAK9wnXXvzY8z675M9i2W0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="aside-proof-by-induction_2"&gt;Aside: Proof by Induction &lt;a class="head_anchor" href="#aside-proof-by-induction_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Proving that each of the unique distributions is equally likely can be done by induction on &lt;code class="prettyprint"&gt;D&lt;/code&gt;. For &lt;code class="prettyprint"&gt;D=0&lt;/code&gt; there is only the initial distribution where each islander has one gem &lt;code class="prettyprint"&gt;(1, 1, ... , 1)&lt;/code&gt;. For a higher value of &lt;code class="prettyprint"&gt;D&lt;/code&gt; there are &lt;code class="prettyprint"&gt;N&lt;/code&gt; potential ways to get to that distribution which we can call &lt;code class="prettyprint"&gt;(g1, g2, ... ,gN)&lt;/code&gt;. These &lt;code class="prettyprint"&gt;N&lt;/code&gt; ways are each from a distribution with one less gem. The probability that we get from a previous distribution, namely &lt;code class="prettyprint"&gt;(g1, g2, ..., gK-1, ..., gN)&lt;/code&gt; to &lt;code class="prettyprint"&gt;(g1, g2, ... ,gN)&lt;/code&gt; is &lt;code class="prettyprint"&gt;(gK - 1) / (N + D - 1)&lt;/code&gt; as one of the &lt;code class="prettyprint"&gt;gK - 1&lt;/code&gt; has  to be the one that splits. Since the probability for each distribution for &lt;code class="prettyprint"&gt;D-1&lt;/code&gt; is some fixed &lt;code class="prettyprint"&gt;P&lt;/code&gt; by the induction hypothesis then the total probability is &lt;code class="prettyprint"&gt;(P * D) / (N + D - 1)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="solution-2-onsup4sup_2"&gt;Solution 2 - O(N&lt;sup&gt;4)&lt;/sup&gt; &lt;a class="head_anchor" href="#solution-2-onsup4sup_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So how many &lt;em&gt;unique&lt;/em&gt; distributions are there? Fortunately there is a closed form for this using combinatorics. Think of creating a distribution by having a bag full of labels with each islanders name on it. There are many labels with each islanders name on it too. Then take &lt;code class="prettyprint"&gt;D&lt;/code&gt; labels from the bag and each time you do that corresponds to that islander getting a gem. The key here is repetition is allowed. The number of ways of choosing &lt;code class="prettyprint"&gt;D&lt;/code&gt; items from a set of &lt;code class="prettyprint"&gt;N&lt;/code&gt; is &lt;code class="prettyprint"&gt;N choose D = choose(N, D)&lt;/code&gt;. While allowing repetition is done using the &lt;a href="https://en.wikipedia.org/wiki/Stars_and_bars_(combinatorics)"&gt;multiset coefficient&lt;/a&gt; &lt;code class="prettyprint"&gt;multichoose(N, D) = choose(N + D - 1, N)&lt;/code&gt;.  So in the above example with &lt;code class="prettyprint"&gt;N=3&lt;/code&gt; and &lt;code class="prettyprint"&gt;D=3&lt;/code&gt;: &lt;code class="prettyprint"&gt;multichoose(3, 3) = choose(3+3-1, 3) = 10&lt;/code&gt;. Now since all these unique distributions are equally probably we can calculate the sum of the gems the &lt;code class="prettyprint"&gt;R&lt;/code&gt; richest islanders have in each and divide by &lt;code class="prettyprint"&gt;choose(N+D-1, D)&lt;/code&gt;. The values of &lt;code class="prettyprint"&gt;choose(N, K)&lt;/code&gt; can be precomputed using the &lt;a href="https://en.wikipedia.org/wiki/Binomial_coefficient"&gt;recurrence relation&lt;/a&gt; &lt;code class="prettyprint"&gt;choose(N, K) = choose(N-1, K) + choose(N-1, K-1)&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="prettyprint lang-python"&gt;# Precompute the values of n choose k
MAX = 50
nCk = np.zeros((MAX, MAX), dtype='uint')
nCk[:, 0] = 1

for n in range(1, MAX):
    for k in range(1, n + 1):
        nCk[n][k] = nCk[n-1][k] + nCk[n-1][k-1]

def choose(nCk, n, k):
    return nCk[n][k]

def multichoose(nCk, n, k):
    return choose(nCk, n + k - 1, k)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cool so we’ve answered the second of our &lt;em&gt;related&lt;/em&gt; questions above. Now let’s try another solution. Instead of enumerating all the distributions - knowing that each of the unique ones is equally likely lets count the number of ways of allocating &lt;code class="prettyprint"&gt;D&lt;/code&gt; gems to the islanders and also the total number of gems the &lt;code class="prettyprint"&gt;R&lt;/code&gt; richest islanders have. Imagine trying to do this in a structured way that you can easily describe what has already being allocated without having to store all the previously allocated gems as we did in the previous solution with the &lt;code class="prettyprint"&gt;gems&lt;/code&gt; list. The reason to do this is if we can describe the state using fewer variables and additionally relate the state to other states we can typically compute the value efficiently using &lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming"&gt;dynamic programming&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In our previous solution our function took parameters &lt;code class="prettyprint"&gt;N, D, R&lt;/code&gt; and also a &lt;code class="prettyprint"&gt;gems&lt;/code&gt; list which could have contained &lt;code class="prettyprint"&gt;RF(N, D)&lt;/code&gt; (many) different values. That list is a problem. Imagine instead that we are counting the number of unique distributions of gems the islands could end up with. Let imagine we are allocating gems in descending order so if we are allocating 3 gems to some set of islanders we don’t need to worry about whether any islanders after that though would have more than 3 gems. We will call the number of gems we are currently allocating &lt;code class="prettyprint"&gt;i&lt;/code&gt;. Let’s also remember how many gems we have left to allocating knowing that we need to allocate &lt;code class="prettyprint"&gt;N+D&lt;/code&gt; gems in total. Let call that &lt;code class="prettyprint"&gt;j&lt;/code&gt;. And finally let’s remember the number of islanders who still need to have gems allocated to them knowing that each islander needs at least one gem, at more &lt;code class="prettyprint"&gt;D+1&lt;/code&gt; gems and the total gems should equal &lt;code class="prettyprint"&gt;N+D&lt;/code&gt;. Let’s call that &lt;code class="prettyprint"&gt;k&lt;/code&gt;. So now we have some partial state describing the number of ways of allocating &lt;code class="prettyprint"&gt;i&lt;/code&gt; or fewer gems to &lt;code class="prettyprint"&gt;k&lt;/code&gt; islanders having &lt;code class="prettyprint"&gt;j&lt;/code&gt; gems left to allocate as &lt;code class="prettyprint"&gt;F[i][j][k]&lt;/code&gt; and we are seeking &lt;code class="prettyprint"&gt;F[D+1][D+N][N]&lt;/code&gt;. This may not seem helpful at the moment but the important this to remember is we are describing something similar to the &lt;code class="prettyprint"&gt;recurse&lt;/code&gt; function in the previous solution with a drastically reduce number of states. `&lt;code class="prettyprint"&gt;(D+1)*(D+N)*N&lt;/code&gt; is far smaller than &lt;code class="prettyprint"&gt;N*D*RF(N, D)&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;But we need a way to compute &lt;code class="prettyprint"&gt;F[D+1][D+N][N]&lt;/code&gt; without visiting states more than once The key to doing this is describing &lt;code class="prettyprint"&gt;F[i][j][k]&lt;/code&gt; in terms of other states. If we are at &lt;code class="prettyprint"&gt;F[i][j][k]&lt;/code&gt; then there is some subset (of size say &lt;code class="prettyprint"&gt;s&lt;/code&gt;) of the &lt;code class="prettyprint"&gt;k&lt;/code&gt; remaining islanders that are each going to get &lt;code class="prettyprint"&gt;i&lt;/code&gt; gems. How many subsets are there well there are &lt;code class="prettyprint"&gt;choose(k, s)&lt;/code&gt;. Then we are done allocating &lt;code class="prettyprint"&gt;i&lt;/code&gt; gems and transition to state &lt;code class="prettyprint"&gt;F[i-1][j - i*s][k - s]&lt;/code&gt;. So our recurrence is: &lt;code class="prettyprint"&gt;F[i][j][k] = choose(k, s) * F[i-1][j - i*s][k-s]&lt;/code&gt; summed over all valid &lt;code class="prettyprint"&gt;s&lt;/code&gt;. We can keep another state &lt;code class="prettyprint"&gt;G[i][j][k]&lt;/code&gt; to collect the sum (instead of the count) of the gems the &lt;code class="prettyprint"&gt;R&lt;/code&gt; richest islanders have and compute it in a very similar way. This all leads to a nice compact solution which run ins &lt;code class="prettyprint"&gt;O(N^4)&lt;/code&gt;, much faster than our previous one but still very slow. Also while it’s a bit mind-bending to try and look at the code directly and understand what is going one knowing what &lt;code class="prettyprint"&gt;F[i][j][k]&lt;/code&gt; and &lt;code class="prettyprint"&gt;G[i][j][k]&lt;/code&gt; store and their recurrence relation is all that is needed. The rest is just bounds checking.&lt;/p&gt;

&lt;pre&gt;&lt;code class="prettyprint lang-python"&gt;def dynamic_programming(N, D, R):

    F = np.zeros((D+1+1, D+N+1, N+1), dtype='double')
    G = np.zeros((D+1+1, D+N+1, N+1), dtype='double')

    F[0][0][0] = 1

    for i in range(1, D + 1 + 1):
        for j in range(0, D+N+1):
            for k in range(0, N+1):
                for s in range(0, min(k + 1, 1 + j // i) ):
                    kCs = choose(k, s)
                    F[i][j][k] += kCs * F[i-1][j-s*i][k-s]

                    # compute the contribution to the sum of gems
                    # R richest islanders have as gems are allocated
                    # in descending order
                    if R - (N-k) &amp;gt; 0:
                        factor = (i-1) * min(R-(N-k), s)
                    else:
                        factor = 0

                    G[i][j][k] += kCs * G[i-1][j-i*s][k-s]
                    G[i][j][k] += kCs * factor*F[i-1][j-s*i][k-s]



    f = F[D+1][D+N][N]
    g = G[D+1][D+N][N]
    return g / f + R


if __name__ == '__main__':
    N, D, R = 10, 10, 2
    expected = dynamic_programming(N, D, R)
    print(expected)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the final expected value is always at least &lt;code class="prettyprint"&gt;R&lt;/code&gt; because each islander starts with one gems. So we can add that contribution at the end and assume islanders start with zeros gems each where as in fact they start with 1.&lt;/p&gt;
&lt;h2 id="solution-3-onsup3sup_2"&gt;Solution 3 - O(N&lt;sup&gt;3)&lt;/sup&gt; &lt;a class="head_anchor" href="#solution-3-onsup3sup_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’re making good progress here. We’ve answered two of our related questions and gotten a solution that will run in &lt;code class="prettyprint"&gt;O(N^4)&lt;/code&gt;. So let’s look at the third related question, how many unique distributions are there (excluding permutations). We can compute this using &lt;a href="https://en.wikipedia.org/wiki/Multinomial_theorem"&gt;multinomial co-efficients&lt;/a&gt;. This is like asking how many unique permutations are there of the word &lt;code class="prettyprint"&gt;MISSISSIPPI&lt;/code&gt;. There are &lt;code class="prettyprint"&gt;11!&lt;/code&gt; permutations but many are repeated. So we divide by the number of ways of permuting the repeated groups &lt;code class="prettyprint"&gt;I&lt;/code&gt;, &lt;code class="prettyprint"&gt;S&lt;/code&gt; and &lt;code class="prettyprint"&gt;P&lt;/code&gt; which is &lt;code class="prettyprint"&gt;4!&lt;/code&gt;, &lt;code class="prettyprint"&gt;4!&lt;/code&gt; and &lt;code class="prettyprint"&gt;2!&lt;/code&gt;. So &lt;code class="prettyprint"&gt;11! / (4!*4!*2!) = 34650&lt;/code&gt; is the number of unique permutations of the letters &lt;code class="prettyprint"&gt;MISSISSIPPI&lt;/code&gt;. We can do the same thing with gems distributions let again look back at the small example with &lt;code class="prettyprint"&gt;N=D=2&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/95XFCJLCd59fuAWSPB3RAz0xspap.png"&gt;&lt;img alt="Screen Shot 2020-09-04 at 3.41.42 PM.png" src="https://svbtleusercontent.com/95XFCJLCd59fuAWSPB3RAz0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are &lt;code class="prettyprint"&gt;6&lt;/code&gt; distributions and only two unique permutations: &lt;code class="prettyprint"&gt;(3,1)&lt;/code&gt; and &lt;code class="prettyprint"&gt;(2,2)&lt;/code&gt;.  There is &lt;code class="prettyprint"&gt;1  = 2! / 2!&lt;/code&gt; unique permutations of &lt;code class="prettyprint"&gt;(2, 2)&lt;/code&gt; and there are &lt;code class="prettyprint"&gt;2 = 2! / (1!*1!)&lt;/code&gt; unique permutation of &lt;code class="prettyprint"&gt;(3, 1)&lt;/code&gt; for a total of &lt;code class="prettyprint"&gt;3&lt;/code&gt; unique distributions. This is sort of helpful at this point but what we really need to do is look at how to describe our state with fewer or smaller variables. We previously allocated amounts of gems from largest to smallest. Let’s look at things a different way and start with all islanders having exactly 1 gem. There is some subset of islands that will receive no more gems during the process they will end the process with 1 gem. But there is a subset which will gain 1 or more gems. So let’s again describe our state of the number of ways of allocating &lt;code class="prettyprint"&gt;i&lt;/code&gt; islanders with &lt;code class="prettyprint"&gt;j&lt;/code&gt; gems as &lt;code class="prettyprint"&gt;F[i][j]&lt;/code&gt; and then our recurrence relation becomes &lt;code class="prettyprint"&gt;F[i][j] = choose(i, k) * F[k][j-k]&lt;/code&gt;. This is much clearer and describes the same information. Coding this up gives a solution that is an order of magnitude faster at &lt;code class="prettyprint"&gt;O(N^3)&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class="prettyprint lang-python"&gt;def dynamic_programming(N, D, R):

    F = np.zeros((N+1, D+1), dtype='float')
    G = np.zeros((N+1, D+1), dtype='float')

    F[0][0] = 1.0

    for i in range(N + 1):
        for j in range(D + 1):
            for k in range( min(i, j) + 1):
                iCk = choose[i][k]
                F[i][j] += F[k][j-k] * iCk
                G[i][j] += (G[k][j-k] + min(r, k) * F[k][j-k]) * iCk

    return F[N][D] / G[N][D] + r
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we’ve answered our three related questions and can confidently count the number of distributions, unique distributions and unique permutations. We’ve also got three different and increasingly faster solutions to the problem. With our understanding let’s try and make one final attempt. &lt;/p&gt;
&lt;h2 id="the-illusive-onsup2sup-solution_2"&gt;The Illusive O(N&lt;sup&gt;2)&lt;/sup&gt; Solution &lt;a class="head_anchor" href="#the-illusive-onsup2sup-solution_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this point you’ve probably drawn lots of those tree diagrams and counted things many times so let’s look at the problem in a different way. Let &lt;code class="prettyprint"&gt;S(N, D, R)&lt;/code&gt; be the sum of the number of gems the &lt;code class="prettyprint"&gt;R&lt;/code&gt; richest islanders have at the end of the process. So for &lt;code class="prettyprint"&gt;N=D=2&lt;/code&gt; and &lt;code class="prettyprint"&gt;R=1&lt;/code&gt;,  &lt;code class="prettyprint"&gt;S(N, D, R)&lt;/code&gt; equals &lt;code class="prettyprint"&gt;16&lt;/code&gt; and we can divide by number of unique distributions &lt;code class="prettyprint"&gt;multichoose(N, D) = 6&lt;/code&gt; which gives the answer &lt;code class="prettyprint"&gt;2.666 ...&lt;/code&gt;. We know how to compute the &lt;code class="prettyprint"&gt;multichoose&lt;/code&gt; so how do we compute &lt;code class="prettyprint"&gt;S(N, D, R)?&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here’s an analogy. Imagine if I said compute the expected value of sequence &lt;code class="prettyprint"&gt;1, 4, 2&lt;/code&gt;. You would add them up and divide by &lt;code class="prettyprint"&gt;3&lt;/code&gt;. That would work. Now instead of giving you the actual values &lt;code class="prettyprint"&gt;1, 4, 2&lt;/code&gt; I gave you a function &lt;code class="prettyprint"&gt;V(K)&lt;/code&gt; and told you that &lt;code class="prettyprint"&gt;V(K)&lt;/code&gt; was the number of values in the sequence that are greater than or equal to &lt;code class="prettyprint"&gt;K&lt;/code&gt;. So &lt;code class="prettyprint"&gt;V(0) = 3&lt;/code&gt;, &lt;code class="prettyprint"&gt;V(1) = 3&lt;/code&gt;, &lt;code class="prettyprint"&gt;V(2) = 2&lt;/code&gt;, &lt;code class="prettyprint"&gt;V(3) = 1&lt;/code&gt;, &lt;code class="prettyprint"&gt;V(4) = 1&lt;/code&gt; and &lt;code class="prettyprint"&gt;V(5) = 0&lt;/code&gt;. How would you compute the expected value? Well you could just sum up the values of &lt;code class="prettyprint"&gt;V(K)&lt;/code&gt; for all &lt;code class="prettyprint"&gt;K&lt;/code&gt; from &lt;code class="prettyprint"&gt;1&lt;/code&gt; upwards which would equal &lt;code class="prettyprint"&gt;3 + 2 + 1 + 1 = 7&lt;/code&gt; and again divide by &lt;code class="prettyprint"&gt;3&lt;/code&gt;. What’s nice about this approach is if I asked you to sum the &lt;code class="prettyprint"&gt;R=2&lt;/code&gt; largest number in that sequence you could just do that by summing &lt;code class="prettyprint"&gt;min(R, V(K))&lt;/code&gt; instead of &lt;code class="prettyprint"&gt;V(K)&lt;/code&gt; and get &lt;code class="prettyprint"&gt;2 + 2 + 1 + 1 = 6&lt;/code&gt; which is the correct answer. You don’t need to sort any thing or know anything about the ordering. &lt;/p&gt;

&lt;p&gt;Knowing that let’s define &lt;code class="prettyprint"&gt;S(N, D, R)&lt;/code&gt; as the sum of all &lt;code class="prettyprint"&gt;min(K, R)*V(K, Y)&lt;/code&gt; and this &lt;code class="prettyprint"&gt;V(K, Y)&lt;/code&gt; is the number of unique distributions of gems where &lt;em&gt;exactly&lt;/em&gt; &lt;code class="prettyprint"&gt;K&lt;/code&gt; have at least &lt;code class="prettyprint"&gt;Y&lt;/code&gt; gems each. If we also say that &lt;code class="prettyprint"&gt;W(K, Y)&lt;/code&gt; is the number of unique distributions of gems where &lt;em&gt;at least&lt;/em&gt; &lt;code class="prettyprint"&gt;K&lt;/code&gt; islanders have at least &lt;code class="prettyprint"&gt;Y&lt;/code&gt; gems each. Note the difference between &lt;code class="prettyprint"&gt;V&lt;/code&gt; and &lt;code class="prettyprint"&gt;W&lt;/code&gt;. Then &lt;code class="prettyprint"&gt;V(K, Y) = W(K,Y) - W(K+1),Y)&lt;/code&gt; So we just need to find a way to compute &lt;code class="prettyprint"&gt;W(K, Y)&lt;/code&gt; which can be done almost directly. First we choose the &lt;code class="prettyprint"&gt;K&lt;/code&gt; islanders that will each be getting &lt;code class="prettyprint"&gt;Y&lt;/code&gt; gems and then allocate the remaining gems as we please. &lt;code class="prettyprint"&gt;K&lt;/code&gt; islanders can be chosen from &lt;code class="prettyprint"&gt;N&lt;/code&gt; as &lt;code class="prettyprint"&gt;choose(N,K)&lt;/code&gt; and then the remaining &lt;code class="prettyprint"&gt;N + D - (Y-1)*K&lt;/code&gt; gems can be allocated to any of the islands in &lt;code class="prettyprint"&gt;choose(N + D - (Y-1)*K - 1, N + D - (Y-1)*K)&lt;/code&gt; ways. The only problems is that this will lead to some double counting so we need to use the &lt;a href="https://en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle"&gt;inclusion-exclusion principle&lt;/a&gt; to compute &lt;code class="prettyprint"&gt;W(K, Y):&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class="prettyprint lang-python"&gt;def W(N, D, K, Y):

    ret = 0
    for L in range(K, N + 1):
        if D - L*(Y-1) &amp;gt;= 0:
            incl_excl =(-1)**(L-K)*choose(L-1,K-1)
            x = incl_excl*choose(N,L)*choose(N+D-L*(Y-1)-1,D-L*(Y-1))
            ret += x
    return ret
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And having &lt;code class="prettyprint"&gt;W&lt;/code&gt; we can compute &lt;code class="prettyprint"&gt;V&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="prettyprint lang-python"&gt;def V(N, D, K, Y):
    return W(N, D, K, Y) - W(N, D, K+1, Y)

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and then we can sum up the &lt;code class="prettyprint"&gt;V&lt;/code&gt; table to compute &lt;code class="prettyprint"&gt;S&lt;/code&gt; and hence our expected value:&lt;/p&gt;

&lt;pre&gt;&lt;code class="prettyprint lang-python"&gt;def S(N, D, R):

    ret = 0
    for K in range(1, N + 1):
        for Y in range(1, D + 2):
            ret += min(R, K) * V(N, D, K, Y)

    return ret

expected = S(N, D, R) / choose(N + D - 1, D)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This solution will run in &lt;code class="prettyprint"&gt;O(N^2)&lt;/code&gt; and compute the correct answer. I really like problems like this. They are entirely described by some very small inputs, in this case just three numbers &lt;code class="prettyprint"&gt;N&lt;/code&gt;, &lt;code class="prettyprint"&gt;D&lt;/code&gt; and &lt;code class="prettyprint"&gt;R&lt;/code&gt; and admit a simple yet prohibitively slow solution by directly simulating the process. But digging in a bit more with some combinatorics yields increasing elegant and faster solutions. Is there a faster solution than &lt;code class="prettyprint"&gt;O(N^2)&lt;/code&gt;? I don’t know, maybe there is even a closed for solution to this problem which I would love to see if it exists!&lt;/p&gt;

&lt;p&gt;This post is based on a question from ICPC World Finals 2018.&lt;/p&gt;</description><author>Nicholas Pilkington</author><pubDate>Sat, 05 Sep 2020 01:40:25 GMT</pubDate><guid isPermaLink="true">https://nickp.svbtle.com/gem-island</guid></item><item><title>2020–09–05: PinePhone multi-boot image</title><link>https://xnux.eu/log/#006</link><author>megi's PinePhone Development Log</author><pubDate>Sat, 05 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#006</guid></item><item><title>Writing Useful Error Messages</title><link>/error-messages/</link><description>&lt;p&gt;Server-side developers often overlook the fact that they are not immune to considering user experience in the design of their systems. Part of this is consideration around error messages. As I spoke about in my article about crafting quality health checks, people don't get angry when something doesn't work, but rather when something doesn't work for some inexplicable reason. In server sided systems, we explain those reasons through the form of error messages returned via an API, or some other mechanism to get a piece of text explaining the issue back to the originator of the request. But how can we write useful error messages? Here are my 5 tips.&lt;/p&gt;
&lt;h2&gt;Make them actionable&lt;/h2&gt;
&lt;p&gt;Actionable advice will always be helpful for your users. But don't just tell them, provide a means for them to take that action that you are suggesting. As an example, let's say your application requires the email address to be verified via a unique link sent to said email address. In the case where the user logs in without verifying the email address, you could return an error message like this. &amp;quot;Please verify your email address joe.bloggs@example.net to continue&amp;quot;. This might seem perfectly sensible and even actionable advice. But to go a step further to make it 'great', we could also include a button to &amp;quot;Resend the verification email&amp;quot; because chances are, the verification email you sent originally is long gone into the rabbit hole of that persons inbox. By providing a button to, in part, perform the action you require, it will be more likely for the user to follow through with the action.&lt;/p&gt;
&lt;p&gt;In other cases, it might not be possible to partially perform an action that your system requires. In these cases, be as clear as possible about what the system would need to work - even if it requires multiple steps. For example, you might have an API that requires parameters &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot; and &amp;quot;C&amp;quot;. But the caller only passes in parameter &amp;quot;A&amp;quot;. What should the error message be?
In most cases, it would probably be:
&lt;code&gt;Please specify parameter &amp;quot;B&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The user would then dutifully add parameter &amp;quot;B&amp;quot; and rerun the request. Only to be given &lt;em&gt;another&lt;/em&gt; error:
&lt;code&gt;Please specify parameter &amp;quot;C&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;At this point, keyboards will be broken, fists will be clenched and Irish coffees will be set to brew - not the response you want from a user of your service.&lt;/p&gt;
&lt;p&gt;Let's rewind and see if we can make the original error more actionable - the user has not passed in two required parameters for our API&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
  &amp;quot;errors&amp;quot;: {
    &amp;quot;B&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;number&amp;quot;, &amp;quot;required&amp;quot;: true},
    &amp;quot;C&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;, &amp;quot;required&amp;quot;: true}
  },
  &amp;quot;documentation&amp;quot;: &amp;quot;https://kryptoking.com/v2/bitcoin#parameters&amp;quot;
  &amp;quot;message&amp;quot;: &amp;quot;Please specify parameter &amp;quot;B&amp;quot; of type Number and parameter &amp;quot;C&amp;quot; of type String. Please see the documentation at https://kryptoking.com/v2/bitcoin#parameters for more details&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok so this is a little more than a message, but still is included in the overall error response. What we have here is a concise breakdown of exactly what the caller of the API needs to do to perform a valid request, as well as being provided a link to further documentation if required. Additionally, the &lt;code&gt;errors&lt;/code&gt; object contains a payload that is easily parsable by a computer to perhaps automatically correct errors on the fly without the developers intervention.&lt;/p&gt;
&lt;p&gt;In both examples, it was clear what the user needed to do next and that's what you should aim to achieve.&lt;/p&gt;
&lt;h2&gt;Remove internal/tech lingo&lt;/h2&gt;
&lt;p&gt;This is one particularly for services consumed by non-technical audiences, who may be unfamiliar with terms we as developers use everyday. We need to use language that, as Lego would put it, can be used by ages 4+. For example, if a users authentication token is invalid, rather than displaying an error &amp;quot;Error: JWT has expired&amp;quot;. We should sign the user out automatically and display a friendly messages such as, &amp;quot;We signed you out because we weren't sure you were still there! Please log in again using your account details below&amp;quot;. Same error, different angle.&lt;/p&gt;
&lt;p&gt;I am always on a crusade with whatever I work on, to remove terms from systems that would require a dictionary to understand. You should aim to do this in any messages that get displayed to users as well. Otherwise, further to point number 1, it would not be as actionable as it could have been.&lt;/p&gt;
&lt;h2&gt;Get rid of them!&lt;/h2&gt;
&lt;p&gt;The best error messages are the ones that don't exist at all. Although you don't want to be burdening your system with translating a million different data input types to the ones you want, I'm almost sure that whatever system you work on, there is a way you can automatically correct an error without the user knowing. Maybe it's a default value you can assign, maybe it's a common data type that users mix-up, whatever the case, take a look at calls to your system that return errors and find patterns in them to seek out ways you can improve the system or the documentation.&lt;/p&gt;
&lt;h2&gt;Don't blame the user&lt;/h2&gt;
&lt;p&gt;One of the worst things you can do in error messages, is pin the blame on the user. Avoid using terms such as &amp;quot;Your&amp;quot; or &amp;quot;You&amp;quot;. In an example we used earlier we spoke of a system that auto logged you out if you were idle for too long. This could be blamed on the user - e.g., &amp;quot;You were idle for too long so you were logged out. Please log in again to continue&amp;quot;. It contains actionable steps, it's not robotic and there was no tech lingo. But it makes the user feel like an idiot because of a constraint that the system built. Don't blame your users, blame yourself if anyone. I've seen no end of error messages, especially unknown ones that say words to the effect of: &amp;quot;Something went wrong in our system. Our engineers are working hard to fix it. Please site reference number: 12345 to our support channels if the issue persists&amp;quot;.&lt;/p&gt;
&lt;p&gt;Be empathetic to your users and use it as an opportunity to improve your service, maybe your documentation needs clarifying or maybe this is an easy mistake to make (misspelling of a parameter perhaps). Attack these problems, not your users.&lt;/p&gt;
&lt;h2&gt;Be direct but not robotic&lt;/h2&gt;
&lt;p&gt;&amp;quot;Invalid Password Provided&amp;quot;, &amp;quot;This field has an error&amp;quot; and &amp;quot;Bad Request: Unexpected end of input&amp;quot; are all error messages I've had in the past, maybe you can remember some equally ridiculous yourselves. What's wrong with these messages? Well asides, from the fact that they are in-actionable, they also use a tone that might be preferred by a Terminator T1000 but probably not by the &amp;quot;humans&amp;quot;. Robotic language is rife in all kinds of messaging, but especially errors - the idea being that by being robotic, it's clear and direct for the person to understand. But in reality, it comes off as distant, cold and frankly useless. Inject some humanity and a bit of fun into your error messages. Psychologist have studied and found that a great way to instantly lift your mood is to simply smile. Smiling is contagious - if we add fun and humanness (if that's a word) into our tone of writing, then even though a user has an issue and maybe slightly annoyed, it will be impossible to maintain that position by being so friendly. Kill them with kindness so to speak (but maybe avoid killing your users because that would make you a terminator).&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully you've learnt some new tricks to help you craft great error messages. As an additional hint, try to include this as part of your code review process where you scan any external (or heck, even internal) facing messages and analyse them for quality. If possible, get someone unfamiliar with the system to review the messages so that they can be understood by all.&lt;/p&gt;</description><author/><pubDate>Fri, 04 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/error-messages/</guid></item><item><title>2020–09–04: Pinebook Pro and Levinboot</title><link>https://xnux.eu/log/#005</link><author>megi's PinePhone Development Log</author><pubDate>Fri, 04 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#005</guid></item><item><title>No ARM sale, please</title><link>https://stop.zona-m.net/2020/09/no-arm-sale-please/</link><description>&lt;p&gt;Because microelectronics make all your world work.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 03 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/no-arm-sale-please/</guid></item><item><title>Automating Blog Images using Alfred File Actions</title><link>http://evantravers.com/articles/2020/09/03/automating-blog-images-using-alfred-file-actions/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/09/actions.png" /&gt;&lt;/p&gt;&lt;p&gt;This automation is really ugly, but it makes my life so much easier. Automation can make you faster, but it can also make you more consistent.&lt;/p&gt;
&lt;p&gt;When I'm working on a blog post, I'm frequently pulling airdropped photos from my phone, screenshots, and random illustrations to put in the current draft. All these artifacts need to go to the right folder in my git repo.&lt;/p&gt;
&lt;p&gt;The correct file location for an image (for me!) is:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://images.evantravers.com/articles/&amp;amp;lbraceYYYY&amp;amp;rbrace/&amp;amp;lbraceMM&amp;amp;rbrace/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Especially early in the month, that folder doesn't always exist. Worse, it has duplicates in both the &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; folders of my static site… so it's often hard to find the right folder even using Alfred's fast file search. I usually end up typing the name of a recent image, opening the containing folder in Finder, then navigating and doing it manually. I'd often put the image in &lt;code&gt;build&lt;/code&gt; instead of &lt;code&gt;source&lt;/code&gt;, or other mistakes.&lt;/p&gt;
&lt;p&gt;No longer!&lt;/p&gt;
&lt;p&gt;I finally wrote a tiny script and added it as an Alfred Workflow as a File Action. That means if I select any file on my computer or find it in Alfred, then hit Tab to act on it, I can select my workflow with speed.&lt;/p&gt;
&lt;p&gt;The workflow looks like this in Alfred:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="alfred workflow" src="https://images.evantravers.com/articles/2020/09/alfred.png" /&gt;
&lt;/figure&gt;
&lt;p&gt;And the bash script is stupid and simple.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-bash" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;# I choose to pass the arguments as &amp;amp;lbracequery&amp;amp;rbrace instead of&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# the default $1&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;HOME&lt;/span&gt;&lt;span&gt;/src/github.com/evantravers/evantravers.com&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;folder&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;/sourcehttps://images.evantravers.com/articles/&lt;/span&gt;&lt;span&gt;$(&lt;/span&gt;&lt;span&gt;date&lt;/span&gt; &lt;span&gt;+%Y/%m/&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;mkdir&lt;/span&gt; &lt;span&gt;-p&lt;/span&gt; &lt;span&gt;$&lt;/span&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;folder&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# the OSX default `cp` command doesn't have this argument.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# I'm using `gcp` from &amp;quot;brew install coreutils&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;/usr/local/bin/gcp&lt;/span&gt; &lt;span&gt;-t&lt;/span&gt; &lt;span&gt;$&lt;/span&gt;&lt;span&gt;repo&lt;/span&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt;folder&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;query&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now… no matter whether the folder exists, and no matter how I find the image… it's a one keypress away from being in exactly the right place. 👍&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;The trick for using GNU &lt;code&gt;cp&lt;/code&gt; on OS X I got from &lt;a href="https://askubuntu.com/a/816826"&gt;this ask ubuntu question&lt;/a&gt;. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Thu, 03 Sep 2020 14:16:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/09/03/automating-blog-images-using-alfred-file-actions/</guid></item><item><title>Homage to Chocolate</title><link>https://nutcroft.mataroa.blog/blog/homage-to-chocolate/</link><description>&lt;p&gt;Chocolate is a true heavenly wonder of this world.&lt;/p&gt;
&lt;p&gt;Every time I see some chocolate, I feel an amazement just by looking, smelling and feeling such a substance. Its texture, rough yet soft. Its colour, original and satisfying. Its smell, deep and luscious.&lt;/p&gt;
&lt;p&gt;The structure of a chocolate is one of its defining characteristics. Rigid and firm but if one opts for partitioning, they could easily snap it. When looking at the edges of what used to be a connection, a view into the chocolate’s soul surfaces. A view that is authentic, beautiful, perfect in its imperfectness of the uneven crack.&lt;/p&gt;
&lt;p&gt;In the same way it breaks by hand, it breaks by mouth. Teeth slowly crush the actualised divinity and with each crack the sublime material is divided in half. In this very process, inimitable sensations develop. Transcendental flavours fly all around one’s mouth, an explosion of saliva takes place and a hurricane of frenzy cacao intervenes — one nobody wants to stop.&lt;/p&gt;
&lt;p&gt;Yet only a handful of seconds later it does. This is one of those moments — how could we ever not appreciate the fact that we have as much of this celestial elixir we want. The limit is in our digestive apparatus, not in the abundance of the world. I now understand why people say we should be more thankful. It’s due to chocolate.&lt;/p&gt;
&lt;p&gt;One would think that even the thought of chocolate ending as a resource would upset me. Yet, I feel peace. Even if chocolate completely disappears from the world, I would be serenely jubilant that we had the opportunity to experience it.&lt;/p&gt;
&lt;p&gt;Nevertheless, we still have loads of chocolate and every day I can buy a well sized portion for one unit of currency. Isn’t that even more amazing?&lt;/p&gt;</description><author>nutcroft</author><pubDate>Thu, 03 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/homage-to-chocolate/</guid></item><item><title>A reminder of what to do with fossil fuels</title><link>https://stop.zona-m.net/2020/09/a-reminder-of-what-to-do-with-fossil-fuels/</link><description>&lt;p&gt;Make them obsolete, of course. Because physics.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 02 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/a-reminder-of-what-to-do-with-fossil-fuels/</guid></item><item><title>How fast do those things shoot out from the jewelweed pods?</title><link>https://andrew.gr/stories/jewelweed/</link><description>I have no idea how to run RSS feeds, so please read this story on my website &lt;a href="https://andrew.gr/stories/jewelweed/"&gt;here&lt;/a&gt;!</description><author>Andrew's Stories</author><pubDate>Wed, 02 Sep 2020 15:02:00 GMT</pubDate><guid isPermaLink="true">https://andrew.gr/stories/jewelweed/</guid></item><item><title>Follow-up: Customizing a Keyboard Layout</title><link>http://evantravers.com/articles/2020/09/02/follow-up-customizing-a-keyboard-layout/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/09/kyria.jpg" /&gt;&lt;/p&gt;&lt;p&gt;In February, I &lt;a href="/articles/2020/02/22/customizing-a-keyboard-layout/"&gt;wrote about my journey to customize a keyboard layout&lt;/a&gt;. I tend to write while I'm still thinking and processing, so a lot has changed since that post. For the two of you who care… here's what I'm typing on &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#symbol-layer" id="symbol-layer"&gt;&lt;/a&gt;Symbol Layer&lt;/h2&gt;
&lt;p&gt;For the past two years, I had been using a variant of the Planck layout, which has symbols on two layers: Lower and Raise. Raise has all the unshifted symbols, and Lower has all the shifted variants.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;  This means that you can kind of reason your way around the board, and find things based on existing muscle memory… or by glancing up at your laptop keyboard.&lt;/p&gt;
&lt;p&gt;In my last post, I discussed how using a keyboard with thumb modifiers made this more complicated… my thumbs went from merely hitting the space bar to layers, space, and all four modifiers.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;2&lt;/a&gt;&lt;/sup&gt; While I don't program for a living at the moment I still write a &lt;strong&gt;lot&lt;/strong&gt; of code and markdown and my thumbs were tired and slow.&lt;/p&gt;
&lt;p&gt;Part of the solution was to create a layer with &lt;em&gt;only&lt;/em&gt; symbols. In the last post, I counted up all the symbols on a standard keyboard and came up with 26… which easily fits within the 3x10 grid that is a subset of all my keyboard layouts:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-plaintext" tabindex="0"&gt;&lt;div class="line"&gt;/* Symbols
&lt;/div&gt;&lt;div class="line"&gt; *
&lt;/div&gt;&lt;div class="line"&gt; * ,---------------------------------------.
&lt;/div&gt;&lt;div class="line"&gt; * | ! | @ | &amp;amp;lbrace | &amp;amp;rbrace | | | ^ | _ | + | / | \ |
&lt;/div&gt;&lt;div class="line"&gt; * |---+---+---+---+---+---+---+---+---+---|
&lt;/div&gt;&lt;div class="line"&gt; * | # | $ | ( | ) | ` | / | - | = | * | &amp;quot; |
&lt;/div&gt;&lt;div class="line"&gt; * |---+---+---+---+---+---+---+---+---+---|
&lt;/div&gt;&lt;div class="line"&gt; * | % | ^ | [ | ] | ~ | &amp;amp; | ? | &amp;lt; | &amp;gt; | : |
&lt;/div&gt;&lt;div class="line"&gt; * `---------------------------------------'
&lt;/div&gt;&lt;div class="line"&gt; */
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a little messy. It has been tweaked steadily over the past seven months, so I honestly don't even remember the reasons for some of this now. I started with the default kyria/ergodox layout and modified to maximize &amp;quot;logicalness&amp;quot;.&lt;/p&gt;
&lt;p&gt;The two columns on the left are basically the LH part of the number row. I &lt;em&gt;believe&lt;/em&gt; this is identical to the Ergodox EZ default layout and Kyria default layout. I then borrowed the Ergodox's decision to put all the brackets and braces together. Coming from the Planck layout, this was probably the biggest change, since the Planck puts the numrow special characters across the top of the board in their &amp;quot;normal&amp;quot; order, so &lt;code&gt;()&lt;/code&gt; and &lt;code&gt;[]&lt;/code&gt; moved from RH to LH. I filled some of the extra spaces with duplicate characters or a few characters that still available on a shifted layer.&lt;/p&gt;
&lt;p&gt;If you decide to do something similar… and you are going to break &lt;em&gt;every&lt;/em&gt; standard keyboard convention, I recommend starting with something very basic and changing it based on the keys you type the most. I optimized for markdown, javascript, and elixir… since that's what I spend the most time in.&lt;/p&gt;
&lt;p&gt;One downside to this is that some muscle memory for keyboard shortcuts in Vim and gmail have to be relearned. That is a pretty big barrier, but I adapted quickly.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-3" id="fnref-3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I had to keep tweaking things to make sure it made sense for the kind of strings that I type, but eventually I became a well oiled special character typing machine thanks to some solid time practicing on &lt;a href="https://www.typingclub.com/sportal/program-3/457.play"&gt;typingclub.com's excellent symbol practice strings&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#space-for-layers" id="space-for-layers"&gt;&lt;/a&gt;Space for Layers&lt;/h2&gt;
&lt;p&gt;I then started using the spacebars as layer toggles. If I tap my spacebar, it behaves as a normal spacebar, if I hold the spacebar, I can access my layers. I think the default Kyria layout does this… but I had it disabled because I wasn't able to cope at first. It took some adjusting of the timing, but now I haven't had a problem with it.&lt;/p&gt;
&lt;p&gt;Downside: many applications use a spacebar hold for panning around a canvas… I may need to dive into the settings to add a timeout, but for now I've simply added a &amp;quot;normal&amp;quot; spacebar in my Design Shortcuts layer, and that works just fine. 🤷‍♂️&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#mods" id="mods"&gt;&lt;/a&gt;Mods&lt;/h2&gt;
&lt;p&gt;Let's talk about &amp;quot;home row modifiers.&amp;quot; I'm definitely not the first person to write about them, and there are &lt;a href="https://www.youtube.com/watch?v=TnE8Qu7a58M"&gt;many people&lt;/a&gt; who have been using them for a lot longer.&lt;/p&gt;
&lt;p&gt;I know I had read about it in the past, but I really started to consider it while researching layouts for the &lt;a href="https://github.com/foostan/crkbd"&gt;corne keyboard&lt;/a&gt; and discovered the &lt;a href="https://github.com/manna-harbour/miryoku"&gt;miryoku layout&lt;/a&gt;. Among many of the interesting tricks in this layout is that the home row keys &lt;code&gt;asdfjkl;&lt;/code&gt; become modifiers if held. I realized that this would relegate my thumbs to only space, layers, and outer mods… and gave it a try. It takes some tweaking to your tap-hold settings in QMK, and definitely some practice in typing, but I think I'm sold on the concept after two months of trying it.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-plaintext" tabindex="0"&gt;&lt;div class="line"&gt;/* Home row modifiers
&lt;/div&gt;&lt;div class="line"&gt; *
&lt;/div&gt;&lt;div class="line"&gt; * ,---------------------------------------.
&lt;/div&gt;&lt;div class="line"&gt; * |   |   |   |   |   |   |   |   |   |   |
&lt;/div&gt;&lt;div class="line"&gt; * |---+---+---+---+---+---+---+---+---+---|
&lt;/div&gt;&lt;div class="line"&gt; * | ⌘ | ⌥ | ⌃ | ⇧ |   |   | ⇧ | ⌃ | ⌥ | ⌘ |
&lt;/div&gt;&lt;div class="line"&gt; * |---+---+---+---+---+---+---+---+---+---|
&lt;/div&gt;&lt;div class="line"&gt; * |   |   |   |   |   |   |   |   |   |   |
&lt;/div&gt;&lt;div class="line"&gt; * `---------------------------------------'
&lt;/div&gt;&lt;div class="line"&gt; */
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It took at least two weeks before I stopped accidentally opening print dialogs and other annoyances. I believe the trick (for me) was learning to let go of each key as soon as the key actuates. I think I had a bad habit of holding a key until the next key press because of my piano training trying to type &lt;a href="https://www.merriam-webster.com/dictionary/legato"&gt;legato&lt;/a&gt;. I also think I located my hand on the keyboard based on the last key pressed… but now that I move my hands away from home row so rarely that is not an issue.&lt;/p&gt;
&lt;p&gt;&lt;a href="/articles/2019/04/03/my-keyboard-setup/#controlling-your-keyboard"&gt;My old Planck layout&lt;/a&gt; had the mods at the bottom under each finger. I think that helped me get my brain ready for home row modifiers. Now that I have tried moving those modifiers up to home row … I don't believe I'm going back. If you are an emacs user, definitely consider checking this technique out. No more contorting or twisting of your hand to get your ring and pinky finger onto the mods at the bottom corner of the keyboard… you don't have to move your hand at &lt;em&gt;all&lt;/em&gt;. I use Readline shortcuts heavily while in a terminal, and now that alt/meta and control are so easy to reach… sometimes I jump around without even realizing how easy it is.&lt;/p&gt;
&lt;p&gt;While home row modifiers are the most wild modification I've yet tried to a keyboard, they are also the most rewarding from an ergonomic perspective. If you are willing to tweak the location of symbols for ergonomics, you are probably the target market.&lt;/p&gt;
&lt;p&gt;There is at least one downside… at least the way I have it configured. Just like the spacebar before, you can't hold down &lt;code&gt;j&lt;/code&gt; and scroll in vim… because the &lt;code&gt;j&lt;/code&gt; doesn't repeat, it just becomes a &lt;code&gt;⇧&lt;/code&gt; (shift) modifier. Honestly… holding down &lt;code&gt;j&lt;/code&gt; to scroll is a little bit of a vim anti-pattern, and I have adjusted to it, but that may be really annoying to you.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-4" id="fnref-4"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#all-together-now" id="all-together-now"&gt;&lt;/a&gt;All together now.&lt;/h2&gt;
&lt;figure&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/09/layout.png" /&gt;
  &lt;figcaption&gt;
    &lt;p&gt;Here's what it all looks like together in a sort of exploded view. As you can see... I'm using a &lt;em&gt;lot&lt;/em&gt; less keys, especially on the thumbs. Mostly trying to minimize the main grid and three thumb keys. The inner 3x10 grid is always the same, but the "wrapper" keys differ slightly from board to board.&lt;/p&gt;
    &lt;p&gt;Blue is symbols, Orange is control, Green is shortcuts, and pink are holds (mod-taps). I actually left out of the image features and layers, like the media keys, F1-F12, and the RGB controls... because it got too busy.&lt;/p&gt;
    &lt;p&gt;If you want to look at the layout on keyboard-layout-editor.com, click &lt;a href="http://www.keyboard-layout-editor.com/#/gists/ec70784c2cf2a294063e4b1b900e5257"&gt;here&lt;/a&gt;.&lt;/p&gt;
    &lt;p&gt;Just putting this thing together has given me new ideas...&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I spend most of my day typing markdown for emails, blog posts, and documentation for work. My fingers almost never stretch beyond one key up or down from home row, and my thumbs almost never leave my spacebars. I rarely stretch my pinkies out to the outer column unless I'm accessing my macro/custom layers.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-5" id="fnref-5"&gt;5&lt;/a&gt;&lt;/sup&gt; Most of the &lt;a href="/articles/2020/02/22/customizing-a-keyboard-layout/#the-outer-keys"&gt;&amp;quot;outer keys&amp;quot;&lt;/a&gt; are on the unused four thumb keys or on layers. There's only six of them after all.&lt;/p&gt;
&lt;p&gt;I'm still tweaking and learning, and about to try a new corne keyboard that's sitting in front of me waiting for switches, but this feels really good. Even with shifting with my pointer fingers (weird right?) I'm still getting regular 100+ wpm on &lt;a href="https://monkey-type.com/"&gt;monkey-type.com&lt;/a&gt;, mostly on quotes.&lt;/p&gt;
&lt;p&gt;I'm sure this will continue to change... I've got that Corne keyboard ready to be completed, and an Atreus from keyboard.io coming at some point that will teach me new lessons and make me try new things.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;This is a nice memory trick to help folks remember where things might be… for instance the letter &lt;code&gt;Q&lt;/code&gt; with the Raise layer enabled is &lt;code&gt;1&lt;/code&gt;, and with the lower layer enabled is &lt;code&gt;!&lt;/code&gt;. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;Typing a common string like &lt;code&gt;&amp;lt;!-- --&amp;gt;&lt;/code&gt; (a comment in HTML) requires 9 separate thumb movements. Every character alternates between a different layer, space, or shift! &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-3"&gt;
&lt;p&gt;Most of the issues had to do with relearning jumps related to &lt;code&gt;()&lt;/code&gt; or toggling options in unimpaired using &lt;code&gt;[]&lt;/code&gt;. It really wasn't that bad. Actions like copying the current selection are even easier in some cases: &lt;code&gt;&amp;quot;*y&lt;/code&gt; requires a lot less movement. &lt;a class="footnote-backref" href="#fnref-3"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-4"&gt;
&lt;p&gt;This will also affect gaming… because most of &lt;code&gt;wasd&lt;/code&gt; can not be held either. This doesn't bother me though… on a keyboard this small I'm probably going to make a gaming layer anyway. &lt;a class="footnote-backref" href="#fnref-4"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-5"&gt;
&lt;p&gt;I've moved &lt;code&gt;'&lt;/code&gt; and &lt;code&gt;&amp;quot;&lt;/code&gt; on layers and forced myself to use them. I may move them to a thumb key on a layer eventually… it's a little out of the way. &lt;a class="footnote-backref" href="#fnref-5"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Wed, 02 Sep 2020 14:04:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/09/02/follow-up-customizing-a-keyboard-layout/</guid></item><item><title>Man's Search for Meaning</title><link>https://arunmani.in/library/mans-search-for-meaning/</link><description>A lot of tough and difficult scenarios.</description><author>Arun Mani</author><pubDate>Wed, 02 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://arunmani.in/library/mans-search-for-meaning/</guid></item><item><title>Intersection Observer Debugger</title><link>https://github.com/pomber/intersection-observer-debugger</link><description>A visual debugger for the IntersectionObserver API</description><author>Rodrigo Pombo</author><pubDate>Wed, 02 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://github.com/pomber/intersection-observer-debugger</guid></item><item><title>Broot 1.0</title><link>https://dystroy.org/blog/broot-1-0/</link><description>&lt;p&gt;8 months ago, but it feels like years ago, somebody shared a link to broot &lt;a href="https://news.ycombinator.com/item?id=21998638"&gt;on Hacker News&lt;/a&gt;. There was some very kind messages and broot gained a few users. But I had more in my TODO list.&lt;/p&gt;
&lt;p&gt;A lot was done since.&lt;/p&gt;
&lt;p&gt;At first sight, &lt;a href="https://dystroy.org/broot"&gt;broot&lt;/a&gt; didn't change much:
It looks the same and what could be done then can still be done the same way, 500 commits and 60 releases later.&lt;/p&gt;</description><author>dystroy|Canop / blog</author><pubDate>Wed, 02 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dystroy.org/blog/broot-1-0/</guid></item><item><title>2020–09–02: Progress on the multi-boot image</title><link>https://xnux.eu/log/#004</link><author>megi's PinePhone Development Log</author><pubDate>Wed, 02 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#004</guid></item><item><title>Inexpensive Dynamic DNS over IRC</title><link>https://purpleidea.com/blog/2020/09/01/inexpensive-dns-over-irc/</link><description>&lt;p&gt;The one thing that I&amp;rsquo;ve been using for longer than &lt;code&gt;ssh&lt;/code&gt; is dynamic dns. In this
article I&amp;rsquo;ll explain how I built an inexpensive, reliable, private alternative
to the mainstream tools commonly available today using only golang and &lt;a href="https://en.wikipedia.org/wiki/Internet_Relay_Chat"&gt;IRC&lt;/a&gt;.&lt;/p&gt;


&lt;br /&gt;&lt;span style="text-decoration: underline; font-weight: bold;"&gt;Background&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;

&lt;p&gt;I&amp;rsquo;ve had an account with &lt;code&gt;dyndns.org&lt;/code&gt; for a long time. They used to be free, but
then they cut off the free tier, but left existing accounts alone, until they
eventually cut all the non-payers off entirely. I think we need an inexpensive
way of giving up-and-coming GNU+Linux hackers a way to &lt;code&gt;ssh&lt;/code&gt; home, and run their
&lt;a href="https://purpleidea.com/blog/2013/10/18/desktop-notifications-for-irssi-in-screen-through-ssh-in-gnome-terminal/"&gt;irssi sessions&lt;/a&gt;,
without having to pay. I also wanted something reliable that wouldn&amp;rsquo;t disappear
the way dyndns did.&lt;/p&gt;</description><author>The Technical Blog of James on purpleidea.com</author><pubDate>Wed, 02 Sep 2020 00:08:00 GMT</pubDate><guid isPermaLink="true">https://purpleidea.com/blog/2020/09/01/inexpensive-dns-over-irc/</guid></item><item><title>A round-up of topology-based papers at ICML 2020</title><link>https://bastian.rieck.me/blog/2020/icml_topology_roundup/</link><description>&lt;p&gt;With this year&amp;rsquo;s &lt;a href="https://icml.cc/Conferences/2020"&gt;International Conference on Machine Learning (ICML)&lt;/a&gt;
being over, it is time to have another instalment of this series.
Similar to &lt;a href="https://bastian.rieck.me/blog/2019/icml_tda_roundup/"&gt;last year&amp;rsquo;s post&lt;/a&gt;, I shall cover
several papers that caught my attention because of their use of
topological concepts&amp;mdash;however, &lt;em&gt;unlike&lt;/em&gt; last year, I shall not
restrict the selection to papers using &lt;a href="https://en.wikipedia.org/wiki/Topological_data_analysis"&gt;topological data analysis (TDA)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Caveat lector&lt;/strong&gt;: I might have missed some promising papers. Any
suggestions for additions are more than welcome! Please reach out
to me via &lt;a href="https://twitter.com/Pseudomanifold"&gt;Twitter&lt;/a&gt; or
&lt;a href="mailto:bastian@rieck.me"&gt;e-mail&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="chen-et-al-learning-flat-latent-manifolds-with-vaes"&gt;Chen et al.: Learning Flat Latent Manifolds with VAEs&lt;/h1&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Learning Flat Latent Manifolds with VAEs" src="https://bastian.rieck.me/images/icml20_chen.png" width="500" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/abs/2002.04881"&gt;Learning Flat Latent Manifolds with VAEs&lt;/a&gt;
by &lt;a href="https://argmax.ai/team/nutan-chen"&gt;Nutan Chen&lt;/a&gt;, &lt;a href="https://www.argmax.ai/team/alexej-klushyn"&gt;Alexej Klushyn&lt;/a&gt;,
Francesco Ferroni, &lt;a href="http://bayerj.github.io"&gt;Justin Bayer&lt;/a&gt;, and
&lt;a href="https://argmax.ai/team/patrick-van-der-smagt"&gt;Patrick van der Smagt&lt;/a&gt;
discusses an interesting modification of variational autoencoders, viz.
an extended loss term that regularises the latent space to be
&lt;em&gt;flat&lt;/em&gt; (i.e. having no &lt;a href="https://en.wikipedia.org/wiki/Curvature"&gt;curvature&lt;/a&gt;).
The main idea is to ensure that the &lt;a href="https://en.wikipedia.org/wiki/Metric_tensor"&gt;Riemannian metric tensor&lt;/a&gt;
is the identity matrix.&lt;/p&gt;
&lt;p&gt;The ingenious implication of such a latent space is that the Euclidean
distance is a good proxy for the similarity between data points, whereas
this is &lt;em&gt;not&lt;/em&gt; a priori the case for other latent spaces. It is interesting
to note that there is a &amp;lsquo;sibling&amp;rsquo; paper to this one, which was published
at ICLR 2020, namely &lt;a href="https://openreview.net/pdf?id=S1g6xeSKDS"&gt;Mixed-curvature Variational Autoencoders&lt;/a&gt;.
This paper presents an autoencoder whose latent space is a product of
Riemannian manifolds, whose curvature is either fixed or learnable.&lt;/p&gt;
&lt;p&gt;I am glad to see that curvature is starting to attract more attention
from the machine learning community. It is such a fundamental property
of a manifold but can influence the validity of many calculations in
latent spaces. It also has some beneficial properties for &lt;a href="https://openreview.net/pdf?id=BylEqnVFDB"&gt;graph
classification&lt;/a&gt;, but this is
maybe a better topic for a subsequent post!&lt;/p&gt;
&lt;h1 id="hofer-et-al-graph-filtration-learning"&gt;Hofer et al.: Graph Filtration Learning&lt;/h1&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Graph Filtration Learning" src="https://bastian.rieck.me/images/icml20_hoferb.png" width="500" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/abs/1905.10996"&gt;Graph Filtration Learning&lt;/a&gt; by
&lt;a href="https://www.researchgate.net/profile/Christoph_Hofer8"&gt;Christoph Hofer&lt;/a&gt;,
&lt;a href="https://www.uni-salzburg.at/index.php?id=213185&amp;amp;L=1"&gt;Florian Graf&lt;/a&gt;,
&lt;a href="https://bastian.rieck.me"&gt;Bastian Rieck&lt;/a&gt;,
&lt;a href="http://wwwx.cs.unc.edu/~mn/?q=content/overview"&gt;Marc Niethammer&lt;/a&gt;, and
&lt;a href="https://rkwitt.github.io/"&gt;Roland Kwitt&lt;/a&gt; is arguably&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; the first step
towards properly integrating topological features into neural networks
for graph classification! Briefly put, we developed a homological
&lt;code&gt;READOUT&lt;/code&gt; function (to use the parlance of graph neural networks)
that gives rise to a learnable filter function&amp;mdash;a &lt;em&gt;filtration&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This concept might be unknown to some readers, but a filtration in this
context is a scalar-valued function on the vertices of a graph that
permits &lt;em&gt;sorting&lt;/em&gt; it. Filtrations serve as the backbone for many
topology-based algorithms, primarily for the aforementioned &lt;a href="https://christian.bock.ml/posts/persistent_homology/"&gt;persistent homology&lt;/a&gt;,
which permits us to study multi-scale topological
features (connected components, cycles, etc.) of an object.
Prior to this paper, filtrations were pre-defined or chosen based on
some target function, such as the vertex degree function of a graph. Our
approach changes this&amp;mdash;leading to a filtration that is learnable in an
end-to-end fashion and thus specifically designed for a classification
problem.&lt;/p&gt;
&lt;p&gt;We manage to achieve this by first initialising our filter function
based on a regular graph neural network; essentially, one level of
message passing between nodes is sufficient. This provides us with
a non-trivial filter function whose performance we can subsequently
adjust by calculating the topological features induced by said filter,
and vectorising the resulting representations. Since each of these steps
is differentiable&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, the resulting function is also differentiable,
making it possible to adjust the filter for the best classification
results.&lt;/p&gt;
&lt;p&gt;I would recommend this paper to anyone who is interested in learning
more about the benefits that a topology-based perspective brings to
certain application problems. Being able to learn the &lt;em&gt;right&lt;/em&gt; topological features
to classify a set of graphs opens up exciting opportunities.&lt;/p&gt;
&lt;h1 id="hofer-et-al-topologically-densified-distributions"&gt;Hofer et al.: Topologically Densified Distributions&lt;/h1&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Topologically Densified Distribution" src="https://bastian.rieck.me/images/icml20_hofera.png" width="500" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/abs/2002.04805"&gt;Topologically Densified Distributions&lt;/a&gt;
by &lt;a href="https://www.researchgate.net/profile/Christoph_Hofer8"&gt;Christoph Hofer&lt;/a&gt;,
&lt;a href="https://www.uni-salzburg.at/index.php?id=213185&amp;amp;L=1"&gt;Florian Graf&lt;/a&gt;,
&lt;a href="http://wwwx.cs.unc.edu/~mn/?q=content/overview"&gt;Marc Niethammer&lt;/a&gt;, and
&lt;a href="https://rkwitt.github.io/"&gt;Roland Kwitt&lt;/a&gt; studies regularisation properties of
over-parametrised neural networks in the context of small sample-size learning.
This is achieved by studying the properties of latent
representations (the paper uses the term &lt;em&gt;internal representation&lt;/em&gt;,
but this is equivalent). More precisely, generalisation properties are
analysed via the &lt;a href="https://en.wikipedia.org/wiki/Pushforward_measure"&gt;push-forward probability measure&lt;/a&gt;
induced by the latent representation (or &lt;em&gt;encoding&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;The authors show that probability mass concentration around training
samples in the latent space is linked to the generalisation capabilities
of a model, but, even more exciting, such a concentration can be achieved by applying
topological constraints on samples from that space! In the context of
this paper, such constraints pertain to measuring the &lt;em&gt;connectivity&lt;/em&gt; of
samples. This is achieved using &lt;a href="https://christian.bock.ml/posts/persistent_homology/"&gt;persistent homology&lt;/a&gt;, specifically,
by calculating a zero-dimensional Vietoris&amp;ndash;Rips complex&amp;mdash;if you are
not familiar with this term, just think of a minimum spanning tree.&lt;/p&gt;
&lt;p&gt;What I particularly enjoyed about this paper is that it starts providing
solid answers to fundamental concepts in machine learning. All too often,
we remain in the realm of the empirical and just &lt;em&gt;observe&lt;/em&gt; whether our
network generalises. This paper ventures into hitherto-unknown territories
and gives us a theoretical justification!&lt;/p&gt;
&lt;h1 id="moor-et-al-topological-autoencoders"&gt;Moor et al.: Topological Autoencoders&lt;/h1&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Topological Autoencoders" src="https://bastian.rieck.me/images/icml20_moor.png" width="250" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/abs/1906.00722"&gt;Topological Autoencoders&lt;/a&gt; by
&lt;a href="https://michaelmoor.ml"&gt;Michael Moor&lt;/a&gt;,
&lt;a href="https://expectationmax.github.io"&gt;Max Horn&lt;/a&gt;,
&lt;a href="https://bastian.rieck.me"&gt;Bastian Rieck&lt;/a&gt;, and
&lt;a href="https://bsse.ethz.ch/mlcb/karsten.html"&gt;Karsten Borgwardt&lt;/a&gt; deals with
regularising the latent space in terms of its topology. More precisely,
we preserve the topological features of the input data in the respective
latent space (on the batch level, respectively). While we restrict
our experiments to connected components for now (so no cycles
yet, even though our method generalises to higher dimensions),
our approach makes it possible to create latent representations
that &amp;lsquo;mimic&amp;rsquo; the topological features of the input.&lt;/p&gt;
&lt;p&gt;This leads to a nice plug-and-play loss term that can be easily
integrated into most architectures, and we can demonstrate that, among
others, it considerably improves the quality of a &amp;lsquo;vanilla&amp;rsquo; autoencoder
architecture. To achieve this goal, we had to solve all kinds of
interesting adventures, one of them being how to make everything
differentiable. Interestingly, we end up with a similar necessary
condition for differentiability than for the graph filtration learning
paper, viz. the pairwise distances between different samples of the
input batch need to be &lt;em&gt;unique&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The coolest feature of our method is that it technically &lt;em&gt;only&lt;/em&gt; requires
a distance metric between input samples&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;, nothing more&amp;mdash;no feature
vector representation or anything. It can thus conceivably be used to
represent the topology of any object you fancy (including
documents, images, and graphs).&lt;/p&gt;
&lt;p&gt;If you are interested in a beautifully-animated high-level introduction
to this publication, you should take the time to read Michael&amp;rsquo;s &lt;a href="https://michaelmoor.ml/blog/topoae/main/"&gt;blog post on our paper&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="rezende-et-al-normalizing-flows-on-tori-and-spheres"&gt;Rezende et al.: Normalizing Flows on Tori and Spheres&lt;/h1&gt;
&lt;div style="text-align: center;"&gt;
&lt;figure&gt;&lt;img alt="Normalizing Flows on Tori and Spheres" src="https://bastian.rieck.me/images/icml20_rezende.png" width="500" /&gt;
&lt;/figure&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://arxiv.org/abs/2002.02428"&gt;Normalizing Flows on Tori and Spheres&lt;/a&gt; by
&lt;a href="https://danilorezende.com/"&gt;Danilo Jimenez Rezende&lt;/a&gt;,
&lt;a href="https://gpapamak.github.io"&gt;George Papamakarios&lt;/a&gt;,
&lt;a href="https://scholar.google.com/citations?user=o-h0vrQAAAAJ"&gt;Sébastien Racanière&lt;/a&gt;,
&lt;a href="http://malbergo.me"&gt;Michael S. Albergo&lt;/a&gt;,
&lt;a href="https://scholar.google.com/citations?user=zK77P6MAAAAJ"&gt;Gurtej Kanwar&lt;/a&gt;,
&lt;a href="https://web.mit.edu/physics/people/faculty/shanahan_phiala.html"&gt;Phiala E.  Shanahan&lt;/a&gt;,
and &lt;a href="http://theoryandpractice.org"&gt;Kyle Cranmer&lt;/a&gt;
present a novel method for calculating normalising flows on more complex
spaces than the usual Euclidean ones. Specifically, as the title
implies, they develop methods for calculating such flows on tori and
spheres.&lt;/p&gt;
&lt;p&gt;What I enjoyed about this paper is the smart way of constructing flows
iteratively: first, flows on the circle are being constructed (using
different concepts for defining a &lt;a href="https://en.wikipedia.org/wiki/Diffeomorphism"&gt;diffeomorphism&lt;/a&gt;, the most favourite of
mine being a &lt;a href="https://en.wikipedia.org/wiki/M%C3%B6bius_transformation"&gt;Möbius transformation&lt;/a&gt;).
Since a torus can be described as the Cartesian product of circles, this
is sufficient to describe flows on tori of arbitrary dimensions! Next,
the flows are generalised to higher-dimensional spheres.&lt;/p&gt;
&lt;p&gt;While I am by no means and expert in normalising flows, I liked
reading this paper a lot. The theory is well-developed and it is another
one of those publications that shows you how to go beyond the boundaries
of what is currently possible. Moreover, I enjoyed the discussion of the
implementation details&amp;mdash;it turns out that achieving numerical stability
here is another feat that deserves some mention!&lt;/p&gt;
&lt;h1 id="summary"&gt;Summary&lt;/h1&gt;
&lt;p&gt;This year&amp;rsquo;s ICML also featured an interesting array of topology-based
papers. Not all of them fit neatly into the field of topological data
analysis (TDA), but I am happy to see that the community is
starting to pick up this fundamental topic. I remain convinced that
a topology-driven perspective is needed to answer certain foundational
questions in machine learning. Here&amp;rsquo;s to the future of topology!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Even if say so myself.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Under mild assumptions, viz. provided that the filter function
values are unique for each vertex. This can always be achieved by
a small symbolic perturbation.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Practically, it might not even require the properties of a metric,
although the mathematician in me is screaming at the horrors of this
thought.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Tue, 01 Sep 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/icml_topology_roundup/</guid></item><item><title>Tech giants: maximum damage with minimum effort</title><link>https://stop.zona-m.net/2020/09/tech-giants-maximum-damage-with-minimum-effort/</link><description>&lt;p&gt;And, which is even more impressive, in good faith, so far.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 01 Sep 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/09/tech-giants-maximum-damage-with-minimum-effort/</guid></item><item><title>Examples of large production-grade, open-source React apps</title><link>https://maxrozen.com/examples-of-large-production-grade-open-source-react-apps</link><description>All of the to-do apps are great for starting to learn React, but what about real-life? Let's see what real production React apps are like.</description><author>Max Rozen</author><pubDate>Tue, 01 Sep 2020 11:42:05 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/examples-of-large-production-grade-open-source-react-apps</guid></item><item><title>Casio CZ-101 Review</title><link>https://ajxs.me/blog/Casio_CZ-101_Review.html</link><description>A review of the Casio CZ-101 synthesizer, from the charitable perspective of someone with experience in ugly, digital
noise: An industrial musician.</description><author>ajxs.me</author><pubDate>Tue, 01 Sep 2020 03:48:19 GMT</pubDate><guid isPermaLink="true">https://ajxs.me/blog/Casio_CZ-101_Review.html</guid></item><item><title>What I’ve been reading in August</title><link>https://dannas.name/2020/09/01/august-roundup</link><description>Here are the articles, videos, and tools that I’m excited about this August.</description><author>Daniel Näslund</author><pubDate>Tue, 01 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dannas.name/2020/09/01/august-roundup</guid></item><item><title>Most people don't want a computer</title><link>https://jasoneckert.github.io/myblog/most-people-dont-want-a-computer/</link><description>&lt;p&gt;In the past few decades, people of all ages across North America have become technology-literate in some way or another. Many of them weren&amp;rsquo;t introduced to technology via desktop or laptop computers, but instead through a smartphone or tablet. Similarly, many desktop and laptop users have switched to using their smartphone or tablet over the past decade to interact with the online world.&lt;/p&gt;
&lt;p&gt;After all, smartphones and tablets are incredibly easy to use. You open an app to do what you want (social media, shopping, taking pics of food, etc.), and the rest can be done in a Web browser. It doesn&amp;rsquo;t matter where your files are stored locally because they&amp;rsquo;re easily searchable, and they&amp;rsquo;re automatically synced to the cloud so that you don&amp;rsquo;t lose them.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Tue, 01 Sep 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/most-people-dont-want-a-computer/</guid></item><item><title>2020–09–01: More p-boot cleanups and an example configuration</title><link>https://xnux.eu/log/#003</link><author>megi's PinePhone Development Log</author><pubDate>Tue, 01 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#003</guid></item><item><title>Effective Data Visualization Part 3: Line charts and stacked area charts</title><link>https://bytepawn.com/effective-data-visualization-part-3-line-charts.html</link><description>&lt;p&gt;Most charts should be line charts or stacked area chart, because they communicate valuable trend information and are easy to parse for the human eyes and brain. &lt;br /&gt;&lt;br /&gt; &lt;img src="/images/p3-weekly-double.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Tue, 01 Sep 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/effective-data-visualization-part-3-line-charts.html</guid></item><item><title>Space Force: Season 1</title><link>https://olshansky.info/tv/space_force_season_1/</link><description>Olshansky's review of Space Force: Season 1</description><author>🦉 olshansky 🦁</author><pubDate>Tue, 01 Sep 2020 00:46:35 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/tv/space_force_season_1/</guid></item><item><title>Books and Links: August</title><link>http://evantravers.com/articles/2020/08/31/books-and-links-august/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/08/feet.jpg" /&gt;&lt;/p&gt;&lt;p&gt;This has been a big month for us. Some new little feet walked through our door, and we are greatly blessed. I have small quiet projects rolling on all my hobbies: hammerspoon, keyboards, and zettelkasten automation... but I've been trying to give my best to my family. This blog is moth and rust ultimately.&lt;/p&gt;
&lt;p&gt;I did write some of my favorite things I've ever posted to the site &lt;a href="/articles/2020/08"&gt;this August&lt;/a&gt;, so I guess the extra time spent rocking the cradle jogged my brain as well. 🤷&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#tiny-habits-by-bj-fogg" id="tiny-habits-by-bj-fogg"&gt;&lt;/a&gt;Tiny Habits by BJ Fogg&lt;/h3&gt;
&lt;figure&gt;
  &lt;img src="https://images.evantravers.com/articles/2020/08/diagrams.png" /&gt;
  &lt;figcaption&gt;
    &lt;p&gt;I borrowed the book from the library, so I hand drew some copies of all the diagrams from the book.&lt;/p&gt;
    &lt;p&gt;I wound up just buying a physical copy.&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I finally finished Tiny Habits by BJ Fogg. I'll probably re-read it with my wife at some point.&lt;/p&gt;
&lt;p&gt;I think Tiny Habits will make a difference in my life. The idea of designing for behavior change by making small changes that build over time is also common to Atomic Habits… But the behavior model that Fogg talks about seems to be easier to get into and could build up change after change in all areas of life.&lt;/p&gt;
&lt;p&gt;I’m also excited about the possibilities of creating positive change in my family or in my office. The story about the father helping create behavior change for his teenage son by requiring less and celebrating more seems plausible and useful.&lt;/p&gt;
&lt;p&gt;After finally getting through that many pages of self-help, I blew through at least &lt;em&gt;four&lt;/em&gt; light fiction which was &lt;em&gt;wonderful&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;p&gt;As has been the case for a little bit, my formerly smooth automation for generating these posts has been &lt;em&gt;utterly&lt;/em&gt; destroyed by my transitions between plaintext note systems, so here's some cherry-picked items.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-onion-for-design-systems-atomic-design-and-pace-layering--by-leslie-mu--aug-2020--ux-collective" id="the-onion-for-design-systems-atomic-design-and-pace-layering--by-leslie-mu--aug-2020--ux-collective"&gt;&lt;/a&gt;The onion for Design Systems: atomic design and pace layering | by Leslie Mu | Aug, 2020 | UX Collective&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Keeping Pace Layering in mind, the design team should be more careful when expanding and iterating the atoms and molecules than organisms and templates, since the lower level the component is on, the more it’s applied to higher-level components, which means the changes are more impactful. On the contrary, the team should have more flexibility and freedom iterating organisms and templates. It’s a mental thing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://uxdesign.cc/the-onion-for-design-systems-atomic-design-and-pace-layering-4cc59a3c486"&gt;The onion for Design Systems: atomic design and pace layering | by Leslie Mu | Aug, 2020 | UX Collective&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#adactio-journaldesign-principles-for-the-webthe-links" id="adactio-journaldesign-principles-for-the-webthe-links"&gt;&lt;/a&gt;Adactio: Journal—Design Principles For The Web—the links&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Should you be interested in the links that I’ll be bombarding the attendees with, I’ve gathered them here in one place (and they’re also on the website of An Event Apart). The narrative structure of the talk might not be clear from scanning down a list of links, but there’s some good stuff here that you can dive into if you want to know what the inside of my head is like.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The links in this article are a &lt;em&gt;very&lt;/em&gt; good reading list for anyone who develops or designs for the web.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://adactio.com/journal/17310"&gt;Adactio: Journal—Design Principles For The Web—the links&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#a-clean-start-for-the-web---macwrightcom" id="a-clean-start-for-the-web---macwrightcom"&gt;&lt;/a&gt;A clean start for the web - macwright.com&lt;/h3&gt;
&lt;p&gt;An interesting perspective about the web's problems… carefully dissecting the two major use cases: delivering documents, and delivering applications.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The web has gotten much harder to develop for.&lt;/p&gt;
&lt;p&gt;The web has had about 25 years to grow, few opportunities to shrink, and is now surrounded by an extremely short-sighted culture that is an outgrowth of economic and career short-termism. There are lots of ways to do anything, and some of the most popular ways of building applications on the web are - in my opinion - usually ghoulish overkill.&lt;/p&gt;
&lt;p&gt;The best way for folks to enter web development in 2020 is to choose a niche, like Vue.js or React, and hope that there’s a CSS and accessibility expert on their team.&lt;/p&gt;
&lt;p&gt;For folks who just want to create a web page, who don’t want to enter an industry, there’s a baffling array of techniques, but all the simplest, probably-best ones are stigmatized. It’s easier to stumble into building your resume in React with GraphQL than it is to type some HTML in Notepad.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There's a reasonable take on the &amp;quot;web is too hard&amp;quot; conversation, pointing out that it's mostly from one perspective judging another.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When I read blog posts from ‘traditional web developers’ who are mad that HTML &amp;amp; CSS aren’t enough anymore and that everything is complicated – I think this is largely that the application stack for building websites has replaced the document stack in a lot of places. Where we would use Jekyll or server-side rendering, we now use React or Vue.js. There are advantages to that, but for a lot of minimally-interactive websites, it’s throwing away decades worth of knowledge in exchange for certain performance perks that might not even matter.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Wright goes on to propose two different webs… one for applications and a leaner, accessible one for documents. It's an interesting take.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://macwright.com/2020/08/22/clean-starts-for-the-web.html"&gt;A clean start for the web - macwright.com&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-hiring-post--quarrelsome" id="the-hiring-post--quarrelsome"&gt;&lt;/a&gt;The Hiring Post — Quarrelsome&lt;/h3&gt;
&lt;p&gt;Very good post on building a system that identifies excellent talent… no more good old boy systems or confusing patterns.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are people who have the social skills to actively listen to someone else’s technical points, to guide a discussion with questions of their own, or to spot opportunities to redirect a tough question back to familiar territory. Those people build impressive resumes. They effortlessly pass “culture fit” tests. And a lot of them can’t code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://sockpuppet.org/blog/2015/03/06/the-hiring-post/"&gt;The Hiring Post — Quarrelsome&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Mon, 31 Aug 2020 23:09:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/08/31/books-and-links-august/</guid></item><item><title>Hooray for nuclear batteries...</title><link>https://stop.zona-m.net/2020/08/hooray-for-nuclear-batteries.../</link><description>&lt;p&gt;Seriously. As long as&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 31 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/hooray-for-nuclear-batteries.../</guid></item><item><title>(Basic) Thoughts on Nim</title><link>https://ciesie.com/post/thoughts_on_nim_01/</link><description>&lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: this is a very opinionated post. I&amp;rsquo;m not claiming I&amp;rsquo;m right. I&amp;rsquo;m describing
my observations.&lt;/p&gt;
&lt;p&gt;This is a great time when it comes to new, fun programming languages. Languages
like &lt;em&gt;Rust&lt;/em&gt;, &lt;em&gt;Zig&lt;/em&gt;, &lt;em&gt;Odin&lt;/em&gt;, &lt;em&gt;Nim&lt;/em&gt;, &lt;em&gt;Jai&lt;/em&gt; bring something new to the table. Those
are only the languages I&amp;rsquo;m keeping tabs on. There is way more projects worth following.&lt;/p&gt;
&lt;p&gt;This post is about &lt;em&gt;Nim&lt;/em&gt;. I use a lot of &lt;em&gt;Python&lt;/em&gt; and I enjoy it less and less everyday.
It&amp;rsquo;s a good language with a great standard library. The community is thriving with great
projects. &lt;em&gt;Python2&lt;/em&gt; has been put in the freezer which means that soon there will only be
one, proper &lt;em&gt;Python&lt;/em&gt; version. There is a lot of fundamental things about &lt;em&gt;Python&lt;/em&gt; that
just don&amp;rsquo;t overlap with my opinions.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Mon, 31 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/thoughts_on_nim_01/</guid></item><item><title>2020-08-31</title><link>https://ho.dges.online/pictures/2020-08-31/</link><description/><author>ho.dges.online</author><pubDate>Mon, 31 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/pictures/2020-08-31/</guid></item><item><title>How to On-board New Hires Remotely</title><link>https://justingarrison.com/blog/2020-08-31-remote-onboarding/</link><description>Tips for new employee's first week</description><author>Justin Garrison's Homepage</author><pubDate>Mon, 31 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://justingarrison.com/blog/2020-08-31-remote-onboarding/</guid></item><item><title>Affinity Designer Google Display Ads Template.</title><link>https://danielsada.tech/blog/affinity-google/</link><description>Hey everyone, here&amp;rsquo;s a .aftemplate file for you to download that includes all of the Display Google Ads templates.
Edit November 25 2020: It seems there is a bug which generates an extra pixel when exporting, you need to put it in a integer (not decimal) X and Y position for it to export to the right size. I&amp;rsquo;ve updated the file with correct X and Y positions.</description><author>Daniel Sada Caraveo | Developer Productivity &amp;amp; Culture</author><pubDate>Mon, 31 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://danielsada.tech/blog/affinity-google/</guid></item><item><title>2020–08–31: Releasing p-boot GUI bootloader</title><link>https://xnux.eu/log/#002</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 31 Aug 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#002</guid></item><item><title>2020–08–31: Getting started</title><link>https://xnux.eu/log/#001</link><author>megi's PinePhone Development Log</author><pubDate>Mon, 31 Aug 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://xnux.eu/log/#001</guid></item><item><title>Thoughts on user growth and product</title><link>https://jonlu.ca/posts/thoughts-on-product</link><description>Reflections on product engineering, growth work, experimentation, and building for user behavior.</description><author>JonLuca's Blog</author><pubDate>Sun, 30 Aug 2020 03:51:20 GMT</pubDate><guid isPermaLink="true">https://jonlu.ca/posts/thoughts-on-product</guid></item><item><title>Growing into Green - An Introduction</title><link>http://spirals.blog/articles/green-introduction/</link><description>&lt;div class="toc"&gt;
&lt;p&gt;Green represents the “sixth stage” of human existence. If you’re new to Spiral, please first read:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/what-is-spiral-dynamics/"&gt;What is Spiral Dynamics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/beige-introduction/"&gt;Beginning in Beige&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/purple-introduction/"&gt;Progressing to Purple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/red-introduction/"&gt;Rising to Red&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/blue-introduction/"&gt;Believing in Blue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/orange-introduction/"&gt;Out-performing in Orange&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's highly encouraged you read these before this article. Thanks!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Hey fellow human ✌️, I’m stoked you’re here. Thanks for joining us. The time has come for us to let go for a moment, center ourselves, and breathe. Just breathe. You know? We’re going to go on a journey today. Together.&lt;/p&gt;
&lt;p&gt;You see, some things have changed since &lt;a href="https://spirals.blog/articles/orange-introduction"&gt;our last article&lt;/a&gt;. A lot actually. Let me explain.&lt;/p&gt;
&lt;p&gt;That Orange stuff was pretty intense. We did it for a while, maybe even got good at it, and ran into some problems (like every color really). We had the riches, private jet, food, experiences, and anything else that money could buy. Or so we thought. Turns out, we can’t buy happiness.&lt;/p&gt;
&lt;p&gt;You see, what happened is we started pissing people off. And hurting people. Not always intentionally, of course, but Orange has this tendency to never stop you see. It just keeps going and going and going… This became a problem. It is not only in our personal lives (late nights at work away from our partners, constant challenging of those around us, and a bit of an ego trip if we’re honest) but also at a more systemic level. We exploited communities, countries, movements, governments, laws, you name it — anything we could do to get ahead. We weren’t evil per se, just a little self-absorbed, so to speak. You with me?&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Leaving Orange - The Good Guy/Gal&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Rethinking" src="http://spirals.blog/articles/green-introduction/rethinking-orange.jpg" /&gt;
&lt;em&gt;Photo by Johnathan Kaufman @j_photos357&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We had SO much that we became wasteful. We still are a bit. We became so focused on OUR success that we forgot about everyone else’s. As our eyes were opened to how our actions were affecting others (akin to how Red affected Purple), we rediscovered a part of our humanity lost in the competitive arena of Orange.&lt;/p&gt;
&lt;p&gt;This awakening is often unpleasant for those who move through it. We become more conscious of feelings (not something a pure Orange really cares for) and how much we’ve neglected them in ourselves and others. If we’re still pulled by the allures of Orange, we often get very good at managing appearances at this point. We &lt;em&gt;&lt;strong&gt;want&lt;/strong&gt;&lt;/em&gt; to be the better person, but we’re honestly still pulled or fueled by the Orange perspective. Think of, for example, the “ethical attempts” of individuals or companies who “try” to care about the environment, but really they’re just doing it to manage perceptions. We get it. It’s not an easy transition.&lt;/p&gt;
&lt;p&gt;Sometimes, the warmth and peacefulness of our newfound Green can be jerked back suddenly. As we tiptoe out of the shiny world of material success and status into a more human, centered, and equal playing field, the Orange perspective often fights us. It becomes a war in our heads as we toss-up between working towards our goals and remembering to help those who need us most. After all, do you really need that extra bonus at work? Someone else probably needs your help more.&lt;/p&gt;
&lt;p&gt;While we’re transitioning, Orange will wake up to the importance of others in achieving our objectives. It will use people, not necessarily in a nefarious way, so that we all benefit. In moments of clarity, we aspire to be the “Good Guy/Gal,” but we still have work to do on our authenticity. And others can see this too.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is this all there is?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ultimately, if we become successful at Orange, we often don’t feel acceptance from others. Maybe our tactics were slightly unethical. Perhaps we disregarded others’ needs or time to make room for our own ambitions. Or it could also be that we earn more in a month than others do in a lifetime 🤷‍♂️. Either way, something has to change.&lt;/p&gt;
&lt;h2&gt;Entering Green: Journey to the center&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Into the forest" src="http://spirals.blog/articles/green-introduction/enter-green.jpg" /&gt;
&lt;em&gt;Photo by John Towner @heytowner&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Over time, if our life conditions adjust, achievement gives way to emotion. We recognize we don’t need all the crap we’ve accumulated (It doesn’t really make us happier anyway). We start treating people as humans. Our own humanity is re-presented to us. Once again, the great pendulum of Spiral swings from “I” (express-self) to “We” (sacrifice-self).&lt;/p&gt;
&lt;p&gt;The road bends away from the brightly-lit, flashy, boulevard, and steers into a calm forest. Since we’re not competing with everyone so much, we now have a chance to really understand who and why they are. The need for status drops away, rendering us all human. All equal. All deserving of love and rights and community.&lt;/p&gt;
&lt;p&gt;The artificial divisions we constructed and clung to in Blue and Orange soon feel isolating and cold. With our new Green appreciation for harmony and acceptance, we tear down these “unnecessary” walls and bring everyone into the same space. Everyone is welcome. As long as you agree with our values.&lt;/p&gt;
&lt;p&gt;With our excessive array of physical possessions sold, our corporate jobs on the back seat, and a new desire for connection on our minds, our spirituality is re-awoken. Maybe we even move to an ashram or commune for the hardcore Green’s amongst us 🙂. We begin the quest to find our center, exploring the inner beings of ourselves and others.&lt;/p&gt;
&lt;p&gt;The future and the past drop away, and we are left with…now. You speak to most Green’s, ask them what’s important about life, and they’ll tell you it’s about being present. Many experiment with vegetarianism/veganism, horrified by these new feelings and how they pertain to the meat/dairy industry. Maybe we take up yoga or meditation. We get into nature more as it just feels &lt;em&gt;so much&lt;/em&gt; better to be amongst the earth, the animals, and the fresh air. The smog-ridden rat race feels unimportant to us now. “Why was it ever?” We think.&lt;/p&gt;
&lt;p&gt;Some typical Green behaviors, beliefs, thoughts, and concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A deep concern for our earth, climate change, and conservation of nature&lt;/li&gt;
&lt;li&gt;Refreshment of spirituality, and a desire to “reach out and touch the universe”&lt;/li&gt;
&lt;li&gt;Political correctness&lt;/li&gt;
&lt;li&gt;Energy and enthusiasm for &lt;em&gt;&lt;strong&gt;cooperative&lt;/strong&gt;&lt;/em&gt; ventures&lt;/li&gt;
&lt;li&gt;Lack of interest in materialism, the Man/Establishment, advertising, and the Blue or Orange Narrative&lt;/li&gt;
&lt;li&gt;“Peace and love, man”&lt;/li&gt;
&lt;li&gt;Listening intently to others&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;A cultural awakening&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Culture" src="http://spirals.blog/articles/green-introduction/culture.jpg" /&gt;
&lt;em&gt;Photo by Sorasak @boontohhgraphy&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Interestingly, perspective &lt;strong&gt;before&lt;/strong&gt; Green is not always the most accepting of other cultures. Purple often feels threatened by stark contrast, Red wants to explore and conquer it, but not understand it. Blue is disapproving of anything that doesn’t fit its Truth, and for Orange, much of the time, it’s about how many likes the Instagram photo of Phi Phi Island gets.&lt;/p&gt;
&lt;p&gt;Green has done away with all the material success, comparing, dogma, rules, and fears of difference that other colors may posses. Everyone is equal and important. Being you a CEO of an international conglomerate, or a Mexican street-food vendor, each person’s story needs to be heard. That is the beauty of Green. There is a space for everyone (mostly).&lt;/p&gt;
&lt;p&gt;Many Green’s (if they’ve solved enough of the Blue or Orange problem and have enough money) LOVE to travel. If you’ve ever met a young grasshopper, with stars in their eyes, joining a volunteering cause, learning yoga in Bali or India, or just wanting to “connect with other ways of life” – there’s a decent bet they’re fueled by a Green appreciation for the world.&lt;/p&gt;
&lt;p&gt;Where this becomes unhealthy is if those preaching peace, love, and giving up the nine-to-five have not yet solved the problems of where they’re at. If you can’t afford to quit your job, you’re not helping the world in the long run. No matter how many endangered creatures you save. Eventually, you will end up running out of resources, and someone (often our parents or friends) will have to support us while we re-address our negative “moving-away-from” Blue or Orange. In short, &lt;strong&gt;solve your own problems before trying to solve the worlds.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Rise of the minorities&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Minority" src="http://spirals.blog/articles/green-introduction/minority.jpg" /&gt;
&lt;em&gt;Photo by Sharon McCutcheon @sharonmccutcheon&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Green’s love for all is not limited to just culture. It will stand up for anyone it feels is underrepresented, or oppressed by dogma, greed, and unjust treatment. Green is the liberating force. The social justice. The White Knight. The activist. The human rights advocate.&lt;/p&gt;
&lt;p&gt;This opposition to the Blue/Orange establishment is an important one; when done correctly and for the right reasons. The women’s movement of the 60s, the airing-out of America’s systemic racism during 2020, protection, and preservation of important natural ecosystems and areas – they all have a powerful and dramatic impact on how we live our lives. If it wasn’t for Green, Orange would continue to exploit and outsmart others, and Blue would be fixed in it’s box forever.&lt;/p&gt;
&lt;p&gt;As you might have guessed, Green’s causes are often twisted by Blue. They become hijacked by those who do not see the real intent, and turn essential movements into “isms” – losing all the original love of it’s Green originator, and becoming a rule-based, check-the-box, “belief”.&lt;/p&gt;
&lt;p&gt;To risk saying something incredibly controversial, why is it only “&lt;strong&gt;Black&lt;/strong&gt; Live’s Matter” in 2020? Why isn’t it “&lt;em&gt;&lt;strong&gt;ALL&lt;/strong&gt;&lt;/em&gt; Lives Matter”? Are there not other oppressed groups and races worth standing up for? When we choose “our” cause, we neglect the true purpose of many of these movements. We are ALL human. We are ALL living souls (animals included) that abide on this earth. We ALL belong.&lt;/p&gt;
&lt;p&gt;At a business/organizational level, many are now choosing to update their policies to foster a more diverse and fair workplace. This is an &lt;strong&gt;EXCELLENT&lt;/strong&gt; thing! (Especially considering our history) However, when this is translated into a Blue process, it loses its power entirely. Ever heard of a “diversity hire”? When Blue takes control of the process, they will seek out and hire purely to check the box with very little consideration of who they’re hiring, and how they think. True diversity, true equality means &lt;strong&gt;equal opportunity&lt;/strong&gt;. Not equal numbers.&lt;/p&gt;
&lt;h2&gt;Harmony: The Language of Green&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Harmony" src="http://spirals.blog/articles/green-introduction/harmony.jpg" /&gt;
&lt;em&gt;Photo by Louis Hansel @shotsoflouis @louishansel&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Healthy Green communicates with sincere warmth and authenticity. They make for fantastic listeners, passionate lovers, and when coupled with other colors, excellent leaders.&lt;/p&gt;
&lt;p&gt;A Green’s spirit is lifted by sharing positive vibes. Bringing others into the fold, hearing new stories, and communicating with a kindness and openness not found previously. A Green seeks to harmonize.&lt;/p&gt;
&lt;p&gt;This is the guiding principle of how Green organizes itself into communities and groups. Green’s relativistic (meaning the truth is relative to the individual) perspective produces a “consensus-based” style of coming to decisions as a group. Everyone must be heard, feelings must be voiced, and we all must agree. Together. The authority in Green lies in the group, not externally. This means there is no need to compete, and comparisons between ourselves (👀 Orange) become irrelevant. We’re all in this together.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Blue stands up for its beliefs. Orange enjoys debating to win. Green builds consensus to enhance feelings of inclusion in the group.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Green often has very high levels of interpersonal abilities. Warm and harmonious interaction is integral to it’s self-satisfaction. Put simply, you feel happy when you’re making others happy and will go at great lengths to do so. This is the crux of Green’s biggest issue – but we’ll get to that a bit later.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Green’s Perspective: Relativism&lt;/h2&gt;
&lt;p&gt;&lt;img alt="relativism" src="http://spirals.blog/articles/green-introduction/relativism.jpg" /&gt;
&lt;em&gt;Photo by Louis Hansel @shotsoflouis @louishansel&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;We’re &lt;em&gt;ALL&lt;/em&gt; right&lt;/h3&gt;
&lt;p&gt;With Green’s new social superpowers, it re-addresses two major concepts learned earlier.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blue’s “we have the Truth” 👉 Green’s criticizing of rigid boundaries/dogma.&lt;/li&gt;
&lt;li&gt;Orange’s “tried-and-true” experience 👉 others stories and perspectives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These shifts give way to an epiphany.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If I’m not 100% right, and neither is the higher power, perhaps we all are!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This becomes the driving force behind Green seeking out authentic relating and genuine connection. It’s also why it defends everyone. To a Green, it’s all subjective, and we have a right to think what we want.&lt;/p&gt;
&lt;p&gt;The issue with extreme relativity is concrete decisions are difficult to make as others enter the equation. We’ll address this more below.&lt;/p&gt;
&lt;h3&gt;Are you with us?&lt;/h3&gt;
&lt;p&gt;There’s only one thing that Green is harshly judgmental of. Judgementalism. Kind of ironic, right 😅? Green will include anyone and tolerate anyone, &lt;strong&gt;as long as they agree to do the same&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Blue sorts “horizontally,” so to speak, dissecting the world into groups with an overarching “Us vs. Them”. Conversely, Orange sorts “vertically”; it doesn’t matter where you come from, rather where you are in the hierarchy. Green does away with sorting and lumps everyone into the same group. It’s incredibly inclusive.&lt;/p&gt;
&lt;p&gt;There’s a caveat, however. Green will only include you if you share in the experience, embrace diversity and openness, and contribute and share your resources. Don’t do this, and you fall subject to collective guilt, emotional manipulation, and many “holier-than-thou” attempts of social conditioning. Like colors before, Green is still quite judgmental. It believes it has the answer to life.&lt;/p&gt;
&lt;p&gt;As Green intensifies, so too does the desire to level hierarchy and status. Taken too far, this idea can turn companies and organizations into “Flat Land”. A place of no hierarchy, no order, and ironically, no diversity.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Spirituality - Green’s Quest of Enlightenment&lt;/h2&gt;
&lt;p&gt;&lt;img alt="yoga" src="http://spirals.blog/articles/green-introduction/yoga.jpg" /&gt;
&lt;em&gt;Photo by Kaylee Garrett @realkayls&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With emotions, community, and humanity now at the forefront of a Green’s mind, spirituality rises as a focus for many. With the harshness of Orange behind us, we journey back to our core selves and what it means to be human.&lt;/p&gt;
&lt;p&gt;The scientific, analytic perspective of Orange gives way to metaphysics and emotions. We foray into experimentation with mind-altering drugs, deep meditation, breathwork, circling, yoga, and rediscover many “ancient Purple rituals. Of course, there are a multitude of other activities that promise the awakening of your Chakras, balancing your energy, and other various spiritual objectives.&lt;/p&gt;
&lt;p&gt;Commonly, Green’s dis-interest in materialism leads them to renounce much of their life and possessions to pursue a simpler existence. This is witnessed consistently in many eastern spiritual practices, wherein an aspiring monk or guru will forgo much of life pleasures to connect with what they feel really matters; the human mind, body, and spirit.&lt;/p&gt;
&lt;p&gt;Taken too far (as it so very often is), these activities lead one to become sanctimonious. We think we’re better somehow. Somewhere along the way towards “self-actualization” we convince ourselves that we’ve somehow entered a higher consciousness. &lt;strong&gt;Many Green’s think they’re Turquoise&lt;/strong&gt;, but they’re kidding themselves. Sadly, much of Green seems currently pre-disposed for this style of thought.&lt;/p&gt;
&lt;p&gt;This is dangerous and unhealthy as, more often than not, these individuals believe that they have experienced or “reached” something others have not. If you have yet to “connect and be one with the universe” then there is something wrong, and you need to be “fixed”. Needless to say, if you happen to bump into one of these disillusioned, “woke”, travelers at your next music festival, it can be a little unsettling.&lt;/p&gt;
&lt;p&gt;All that aside, Green’s re-focus on deep healing, healthy introspection, self-acceptance, meditation, and healthy mind/body brings a joyous and much needed breathe of fresh air to this point of the Spiral.&lt;/p&gt;
&lt;h2&gt;Getting out of hand: Green’s Problems&lt;/h2&gt;
&lt;p&gt;&lt;img alt="consensus" src="http://spirals.blog/articles/green-introduction/consensus.jpg" /&gt;
&lt;em&gt;Photo by Antenna @antenna&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Ok, we’ll admit it, there’s a few problems with Green. Despite its fuzziness and inclusivity, like every color, it introduces new issues when something becomes too overactive. For Green, it can be extremely challenging to admit to some of these as it prides itself on its consideration of others’ feelings.&lt;/p&gt;
&lt;h3&gt;Collective Guilt&lt;/h3&gt;
&lt;p&gt;Green has a tendency to feel guilt from its past Orange/Blue life. It can become uncomfortable when the topic of how they became successful (both individually or culturally) and due to it’s empathy, push others to follow the same path. This often becomes dogmatic.&lt;/p&gt;
&lt;p&gt;Communally, this can become an incredibly powerful limiter to ideas and freedom of expression (especially from other colors). There’s often a “Go along to get along” attitude. We become so aware, deeply felt, of others and their pains that we take them on as our own. Some take this further and feel they are somehow responsible.&lt;/p&gt;
&lt;p&gt;Sometimes, the pressures of caring can be overwhelming. A healthy Green knows when to stop and look after themselves. And yes, this is hard.&lt;/p&gt;
&lt;h3&gt;Too offended&lt;/h3&gt;
&lt;p&gt;In their open-source policy document for contributing, Microsoft has stated that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Even a single person being offended is one too many”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Green’s quest for making everyone comfortable is plain impractical when taken to a larger scale. In its attempts of inclusivity, it becomes so rigid, so afraid of offending or triggering someone, that it dilutes the entire experience for everyone involved.&lt;/p&gt;
&lt;p&gt;The reality is that any decision you make (especially at a product, government, or leadership level) will rub someone the wrong way. The work should not be placed in just reducing “offensive” concepts, but instead training and helping others become more tolerant. This would resolve many of Green’s problems.&lt;/p&gt;
&lt;h3&gt;We can be anything we choose&lt;/h3&gt;
&lt;p&gt;Until you can’t. Let me explain.&lt;/p&gt;
&lt;p&gt;You’ll often hear (or feel) an Orange say:
“I am far superior to you”&lt;/p&gt;
&lt;p&gt;Green shifts this into:
“Any one of us can be anything we choose”&lt;/p&gt;
&lt;p&gt;In our typical Green fashion, we create space for anyone to be whomever they chose. The reality is, we all have &lt;em&gt;&lt;strong&gt;very real&lt;/strong&gt;&lt;/em&gt; limitations and capacities (something Yellow emerges to deal with). Despite how much you &lt;em&gt;want&lt;/em&gt; to be something, sometimes you just can’t. Our range of possibilities, especially when it comes to Spiral, is directly proportional to our life conditions. What have we been exposed to?&lt;/p&gt;
&lt;p&gt;If you’ve never lived through and solved the problems of Blue, Orange, Green, then reached the limitations of all these, shifted into tier 2 thinking, spent YEARS of your life trying to fix things there, and then encountering THOSE issues, Turquoise won’t make sense. It doesn’t matter how many meditation and yoga retreats you’ve been to. We simply cannot understand perspective beyond our current level of thinking. We may &lt;em&gt;think&lt;/em&gt; we can, but this is only intellectual. It is not, as ancient India referred to as “sati”, an &lt;em&gt;experiential knowing&lt;/em&gt;. Sorry.&lt;/p&gt;
&lt;h3&gt;Too slow&lt;/h3&gt;
&lt;p&gt;As mentioned earlier, Green’s authority comes from the group. The decisions often must be unanimous. For this to happen, everyone must come to the same conclusion. For those who have experienced this, it is akin to herding cats.&lt;/p&gt;
&lt;p&gt;Fundamentally, the issue with much of Green’s leadership is due to the underpinning belief that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Harmony leads to productivity&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This simply is not true. While harmony is a noble value and objective of many a team, are we truly aware of what it will take to achieve the elusive “harmony”?&lt;/p&gt;
&lt;p&gt;Anyone who has worked on the board of a non-profit, inside any social endeavor, or within volunteering organizations, will have had the same experience.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An idea is presented&lt;/li&gt;
&lt;li&gt;It is discussed, and everyone’s opinions and concerns are voiced&lt;/li&gt;
&lt;li&gt;The idea is concluded to need more work, and another meeting is scheduled to address these issues&lt;/li&gt;
&lt;li&gt;Next month, a new person is on the team, and when the improved idea is revealed, they also take issue, but with something else.&lt;/li&gt;
&lt;li&gt;Rinse and repeat for months. Sometimes years.&lt;/li&gt;
&lt;li&gt;Maybe, just maybe, we will come to a conclusion.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sadly, this is how much of Green operates. Everyone has the opportunity to speak and contribute. It’s very well-intentioned, but it fails to realize that the whole time they spent calmly deliberating if they should spend the investor’s money on a new marketing campaign, the competition had already beat them to market.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Beyond collectivism&lt;/h2&gt;
&lt;p&gt;&lt;img alt="world" src="http://spirals.blog/articles/green-introduction/world.jpg" /&gt;
&lt;em&gt;Photo by NASA @nasa&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The efficacy of consensus, equal say for everyone, and suppression of individuality (hello Purple and Blue) can take its toll on some. If it’s not yet apparent, Green’s caring intentions have yet to manifest any &lt;em&gt;actual&lt;/em&gt; change to some of the world’s biggest looming problems. Perhaps Green is not equipped to deal with them.&lt;/p&gt;
&lt;p&gt;Personally, the author has felt that Green has some of the most important messages in the world, with no ability to actuate anything substantial. Equality, global warming, racism, free speech, human rights, the list goes on. Despite Green’s plea at their rallies and policy sessions, they seem entirely incapable of achieving any real difference.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Why?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Complexity. A topic for the next time.&lt;/p&gt;
&lt;p&gt;Thanks for reading, friend.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 30 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/green-introduction/</guid></item><item><title>Types of Notetaking</title><link>https://thomascountz.com/2020/08/30/types-of-notetaking</link><description>&lt;p&gt;Earlier this week, my pair and I struck upon something interesting, and I stopped to take notes.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Every time I see you taking notes, you’re using a new method!&lt;/p&gt;

  &lt;p&gt;— Pair&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;She’s not wrong. Over the past several years, I’ve tried many different ways of capturing my thoughts: yellow legal pads, &lt;a href="https://basecamp.com"&gt;Basecamp&lt;/a&gt;, &lt;a href="https://notion.so"&gt;Notion&lt;/a&gt;, &lt;a href="https://github.com/vimwiki/vimwiki"&gt;Vimwiki&lt;/a&gt;, &lt;a href="https://orgmode.org/"&gt;Org Mode&lt;/a&gt;, &lt;a href="https://tyke.app/"&gt;Tyke&lt;/a&gt;, index cards, &lt;a href="https://www.gitbook.com/"&gt;Gitbook&lt;/a&gt;, blogging with &lt;a href="https://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; and &lt;a href="https://medium.com"&gt;Medium&lt;/a&gt;, Slack/Emails to self, &lt;a href="https://www.gingerlabs.com/"&gt;Notability&lt;/a&gt;, and voice notes. I didn’t switch note taking styles because I liked to try new things, I switched because I hadn’t found a note-taking tool that fit all of my needs. I’ve researched and tried different note taking systems like &lt;a href="https://gettingthingsdone.com/"&gt;Getting Things Done&lt;/a&gt; and &lt;a href="https://www.buildingasecondbrain.com/"&gt;Building a Second Brain&lt;/a&gt;, but as soon as a system or tool caused me to think more about note taking and less about what I was taking notes on, I struggled to keep focused and motivated.&lt;/p&gt;

&lt;p&gt;I realized that I should drop all of that and let my intuition guide how I record information best. It turns out that trying to force everything I wanted to write down into one system caused me to feel frustrated and confused. For some things,  &lt;a href="https://github.com/vimwiki/vimwiki"&gt;Vimwiki&lt;/a&gt; was perfect! For others, it felt clunky and difficult. A pocketbook was awesome for a while, then suddenly I felt like I could never keep things straight.&lt;/p&gt;

&lt;p&gt;Once I stopped fighting this battle, I found that there were three types of notes that I was taking and therefore there were three different tools/methods I could use to take them.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;div style="text-align: center;"&gt;
  &lt;h2&gt;
    Contents
  &lt;/h2&gt;
    &lt;p&gt;&lt;a href="#actionable-todos"&gt;Actionable TODOs&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;&lt;a href="#in-situ-documentation"&gt;In Situ Documentation&lt;/a&gt;&lt;/p&gt;
    &lt;p&gt;&lt;a href="#long-form-reference"&gt;Long-form Reference&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="actionable-todos"&gt;Actionable TODOs&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Buzz. Buzz.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I check my phone. It’s a text from my husband:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If you stop by the grocery store, I just used the last few onions. Can you grab some?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TODOs and short-term tasks come at me from all directions and at any time. Old me would just try to remember everything, but I’ve realized just how much bandwidth and brain cycles that takes up, so I’ve taken to writing these things down. I write down things that are “actionable,” and are “obvious when they’re done,” like “take out trash,” or “fill out form DL-80.”&lt;/p&gt;

&lt;p&gt;My criteria for a TODO tool:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Readily available&lt;/strong&gt; — I need access to my TODO list at all times. I don’t know when I’ll have the opportunity to check something off my list and I don’t know where I’ll be when I need to add a new task.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Low friction&lt;/strong&gt; — Capturing a TODO needs to be a quick activity so that I can continue on with my day. Having to also schedule a reminder, add a category, a priority value, and a description, before I could “save” a task limited my willingness to commit to writing down my TODOs&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Non-ceremoneous&lt;/strong&gt; — similar to being low friction, I don’t want any other features tied to my TODO notes besides creating a task and marking as task a finished. For example, one TODO tool generated a weekly chart displaying how many tasks I completed compared to last week. I started re-structuring my TODOs to effect these outcomes and meant that I was no longer focusing on the tasks themselves.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="my-solution-a-passport-sized-notebook-and-pen"&gt;My solution: a passport-sized notebook and pen&lt;/h3&gt;

&lt;p&gt;I can carry this notebook and pen most places with me, and I’m un-apologetic about what I write in it. I mix work-related things with personal task, and I scribble quick “…can you write down this number…” notes, too. Even though it’s for “tasks,” I occasionally find myself taking temporal notes like, “finished reading Convenience Store Woman” and ideas like “write blog post about note taking.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A pocketbook is an always-charged smartphone.&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="in-situ-documentation"&gt;In Situ Documentation&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Do you remember what we ended up deciding on Friday?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a world of synchronous-first communication, after an hours long meeting, the last thing I want to do is write down everything we just talked about. More than that, after an hours long meeting, the last &lt;em&gt;last&lt;/em&gt; thing I want to do is feel like we forgot everything we talked about.&lt;/p&gt;

&lt;p&gt;Sometimes the meetings I’m in are a bit chaotic and cover a lot of ground. (Often more like &lt;a href="https://en.wikipedia.org/wiki/Mob_programming"&gt;mob programming&lt;/a&gt; than a meeting). In these cases, I’ve found that rapid-fire note taking has allowed me to both 1) keep a reference of what we may have decided and 2) free up my brain to keep listening.&lt;/p&gt;

&lt;p&gt;Contemporaneous Work Notes look like this for me:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Draft-zero&lt;/strong&gt; — I think of these notes as casting a very wide net. I scribe almost continuously and more often than not, half of it is garbage. With that said, I need a tool that can help me create private unedited drafts that allow me to hone the 50% later.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Adaptable&lt;/strong&gt; — I might be taking notes during a meeting, while pairing, during code review, etc. I need a system that adapts to however my brain feels like organizing information in the moment. Besides a date, these notes can end up looking very different: a doddle here, a line reference there, a TODO might sneak in—who knows?!&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Disposible&lt;/strong&gt; — These notes depreciate in value over time. Ideally, I reference these notes shortly after taking them in order to formalize something that may need to be shared. When I’m done, the in situ notes shouldn’t contain any important information that isn’t captured in a different form elsewhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="my-solution-yellow-legal-pad-and-mechanical-pencil"&gt;My solution: yellow legal pad and mechanical pencil*&lt;/h3&gt;

&lt;p&gt;Yellow legal pads are beloved (and hated) by many for their accessibility and ease of use, see: &lt;a href="https://www.legalaffairs.org/issues/May-June-2005/scene_snider_mayjun05.msp"&gt;The Illustrious History of the Yellow Legal Pad&lt;/a&gt;. I fell in love with them because they feel limitless. I found that when taking notes in beautiful leather-bound $40 notebook, I became a bit too precious about what I would write in it and began to edit my notes before I put pencil to paper! On the contrary, yellow legal pads are cheap, thin, and always open. I prefer a mechanical pencil because I feel as though I can write cleaner lines with a 0.5mm lead than I can with an equally fine pen. Also, I &lt;em&gt;do&lt;/em&gt; erase things sometimes, especially if I’m trying to capture a concept in an illustration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A yellow legal pad is a private portable whiteboard.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*In an effort to minimize my impact on the environment, I’ve moved to using &lt;a href="https://www.gingerlabs.com/"&gt;Notability&lt;/a&gt; on the iPad with an Apple Pencil or folding yellow legal pad pages into four—using one section per day and both sides of the page.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="long-form-reference"&gt;Long-Form Reference&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CUT TO&lt;/strong&gt;: Thomas is, yet again, digging through the pages of &lt;a href="https://shop.jcoglan.com/building-git/"&gt;Building Git by James Coglan&lt;/a&gt; to remember how Ruby’s &lt;code class="language-plaintext highlighter-rouge"&gt;open3&lt;/code&gt; module exposes child processes to IO streams.&lt;/p&gt;

&lt;p&gt;I love diving deep into different topics, often topics that I may not directly visit or use again in my day-to-day work. Take &lt;a href="https://www.thomascountz.com/tag/machine-learning/"&gt;machine learning&lt;/a&gt; for example. When I first studied it, I learned quite a lot! But, just a few months later, when I revisited data science, I felt as though I was back to square one. Not only can I have notes to come back to, I’ve noticed that my comprehension increases when I’m able to write new information down in my own words.&lt;/p&gt;

&lt;p&gt;My solution to avoid this type of thing is to take long-form reference notes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Reference-able&lt;/strong&gt; — As you might be able to guess, these notes have to be notes that I can come back to and understand. That means that these aren’t draft-zero notes, they’re well crafted and continuously editable as I learn and discover new things. They’re written with the reader in mind, even on the first pass.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Structured&lt;/strong&gt; — These notes should be both hierarchical and linkable. If I taking notes on material that is related to notes I’ve taken in the past, I want to connect them somehow. This helps with referencing things later, but also helps as I’m editing.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Pleasurable&lt;/strong&gt; — It’s important to me that these notes be enjoyable to write and to read. This means the ergonomics have to be comfortable and familiar and help me to focus on the content, rather than the styling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="my-solution-gitbookpersonal-wiki"&gt;My solution: &lt;a href="https://www.gitbook.com/"&gt;Gitbook&lt;/a&gt;/personal wiki&lt;/h3&gt;

&lt;p&gt;This is a new venture for me, but you can find the beginnings of this journey at &lt;a href="https://research.thomascountz.com"&gt;research.thomascountz.com&lt;/a&gt;. Gitbook has switch from self-hosted to a SAAS offering in the past few years, but still offer free services for individuals. I enjoy Gitbook because the online editor is intuitive and comfortable, and all of my notes are backed by git/Github, which means exportability. Also, I like that these notes are public. They’re not quite a blog post, but being able to link directly to specific notes is helpful when sharing ideas.&lt;/p&gt;

&lt;p&gt;I’ve also taken to recording personal project documentation in wiki format. Even when I’m working alone, I prefer to write asynchronous documentation as though I’m together with a team. These project docs help me link thoughts and ideas together that would otherwise decay over time as other priorities come into focus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A personal wiki is the brain’s external hard drive.&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="your-notes-your-way"&gt;Your Notes, Your Way!&lt;/h2&gt;

&lt;p&gt;It’s with this combination of a small notebook, yellow legal pad, and personal wiki that I declutter my brain and keep focused. What’s your preferred note-taking method/tool? Do you have one that fits all your needs or are you like me: different tools for different situations? I’d love to hear your thoughts!&lt;/p&gt;</description><author>Thomas Countz</author><pubDate>Sun, 30 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thomascountz.com/2020/08/30/types-of-notetaking</guid></item><item><title>An introduction to Panopticon</title><link>https://explog.in/https://explog.in/notes/panopticon.html</link><description>&lt;p&gt;
    Panopticon is a Python tracer I've written as an alternative to using
    a debugger. Instead of manually stepping through code, I'd much rather
    have a computer do it for me.
    &lt;/p&gt;

    &lt;p&gt;
    Since writing this post panopticon has evolved to include &lt;code&gt;probes&lt;/code&gt;:
    which can instrument code you might not have full control over.
    &lt;/p&gt;

    &lt;p&gt;
    (I'd initially written this post as documentation, but ultimately
    realized it's better suited as a post and I can do a much better job
    of documentation within the project.)
    &lt;/p&gt;</description><author>RSS</author><pubDate>Sun, 30 Aug 2020 02:05:00 GMT</pubDate><guid isPermaLink="true">https://explog.in/https://explog.in/notes/panopticon.html</guid></item><item><title>How to Create Luck</title><link>https://www.swyx.io/create-luck</link><description>Your entire worldview changes when you realize you can create luck.</description><author>swyx's site RSS Feed</author><pubDate>Sun, 30 Aug 2020 00:23:06 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/create-luck</guid></item><item><title>The wastefulness of wireless</title><link>https://stop.zona-m.net/2020/08/the-wastefulness-of-wireless/</link><description>&lt;p&gt;Wireless CHARGING, that is.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 29 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/the-wastefulness-of-wireless/</guid></item><item><title>Antenna Analysis from Ham Radio to PCBs</title><link>https://shielddigitaldesign.com/posts/2020/antenna/</link><description>&lt;p&gt;
Has anyone else ever thought about why so many engineers are also
active amateur radio operators? My theory is that there's just so much
passion for the science and practical use of these complex electronic
systems! We enjoy the problems, challenges and solutions so much that
we want to find other ways outside of work to find those same
experiences. In this case, I've got a story that starts with some
amateur radio equipment but comes full-circle to address an extremely
common design issue. Specifically, we'll look at the Arrow OSJ antenna
performance as well as the characteristics of a printed circuit board
antenna.&lt;/p&gt;</description><author>Shield Digital Design</author><pubDate>Sat, 29 Aug 2020 19:00:00 GMT</pubDate><guid isPermaLink="true">https://shielddigitaldesign.com/posts/2020/antenna/</guid></item><item><title>What running out of SATA ports looks like</title><link>https://ounapuu.ee/posts/2020/08/29/what-running-out-of-sata-ports-looks-like/</link><description>How I slapped two hard drives on a long PCIe x1 card.</description><author>./techtipsy</author><pubDate>Sat, 29 Aug 2020 17:21:21 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/08/29/what-running-out-of-sata-ports-looks-like/</guid></item><item><title>Running on fumes</title><link>https://ounapuu.ee/posts/2020/08/29/running-on-fumes/</link><description>0GB ought to be enough for anybody.</description><author>./techtipsy</author><pubDate>Sat, 29 Aug 2020 16:42:19 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/08/29/running-on-fumes/</guid></item><item><title>Day One</title><link>https://utf9k.net/blog/day-one/</link><description>Thoughts upon entering my second job in the industry</description><author>utf9k</author><pubDate>Sat, 29 Aug 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/day-one/</guid></item><item><title>Snoqualmie Falls</title><link>https://sam.hooke.me/trip/2020/08/snoqualmie-falls/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;p&gt;No trip report yet.&lt;/p&gt;</description><author>Sam Hooke</author><pubDate>Sat, 29 Aug 2020 11:30:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/08/snoqualmie-falls/</guid></item><item><title>Blowout Creek</title><link>https://sam.hooke.me/trip/2020/08/blowout-creek/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;p&gt;No trip report yet.&lt;/p&gt;</description><author>Sam Hooke</author><pubDate>Sat, 29 Aug 2020 06:00:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/08/blowout-creek/</guid></item><item><title>Banks create money out of thin air, but it's less impressive than it sounds</title><link>https://www.attejuvonen.fi/money-out-of-thin-air/</link><description>Most people are familiar with central banks’ ability to create money out of thin air. A central bank has access to physical printing presses…</description><author>TODO</author><pubDate>Sat, 29 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.attejuvonen.fi/money-out-of-thin-air/</guid></item><item><title>Algorithmic Colonization of Africa, part 2</title><link>https://stop.zona-m.net/2020/08/algorithmic-colonization-of-africa-part-2/</link><description>&lt;p&gt;Some &amp;ldquo;Global North&amp;rdquo; things to avoid in Africa&amp;hellip; and in the Global North too!&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 28 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/algorithmic-colonization-of-africa-part-2/</guid></item><item><title>How to Structure a React Project</title><link>https://bartlomiejmika.com/posts/2020/how-to-structure-react-project/</link><description>&lt;p&gt;In the article you will get the boilerplate structure I use for &lt;a href="https://bartlomiejmika.com/tags/react/"&gt;#React&lt;/a&gt; projects.&lt;/p&gt;</description><author>Bartlomiej Mika</author><pubDate>Fri, 28 Aug 2020 17:38:31 GMT</pubDate><guid isPermaLink="true">https://bartlomiejmika.com/posts/2020/how-to-structure-react-project/</guid></item><item><title>Devlog #3: entity movement</title><link>https://domwillia.ms/devlog3</link><description>A barely coherent rant about a year of progress (or lack thereof) in the realm of entity movement and path finding.</description><author>Dom Williams</author><pubDate>Fri, 28 Aug 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://domwillia.ms/devlog3</guid></item><item><title>Putting your Keyboard on Steroids with Karabiner Elements</title><link>https://www.swyx.io/karabiner_lindquist</link><description>I did a livestream with John Lindquist from Egghead.io today, and he blew my mind on how much mileage you can get out of your keyboard!</description><author>swyx's site RSS Feed</author><pubDate>Fri, 28 Aug 2020 05:10:46 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/karabiner_lindquist</guid></item><item><title>Faster macOS dock auto-hide</title><link>https://xenodium.com/faster-macos-dock-auto-hide</link><description>&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/faster-macos-dock-auto-hide/dock.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Via Marcin Swieczkowski's &lt;a href="https://www.bytedude.com/upgrading-the-osx-dock/"&gt;Upgrading The OSX Dock&lt;/a&gt;, change default to make macOS's dock auto-hide faster:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;defaults write com.apple.dock autohide-time-modifier -float 0.2; killall Dock
&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Fri, 28 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/faster-macos-dock-auto-hide</guid></item><item><title>react-fit-to-viewport</title><link>https://github.com/pomber/react-fit-to-viewport</link><description>Automatically scales the content to fit it inside the viewport</description><author>Rodrigo Pombo</author><pubDate>Fri, 28 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://github.com/pomber/react-fit-to-viewport</guid></item><item><title>Building Awesome Application Health Checks</title><link>/health-checks/</link><description>&lt;p&gt;For many, having a health check in your application may be somewhat of an afterthought. Maybe your application does have a health check, but you've got no idea if it actually works. I didn't give it much of a thought until I truly understood that one of the key pillars of good development is monitoring. And to be able to monitor a service, you need to know if it's up, down or fallen down the stairs.&lt;/p&gt;
&lt;p&gt;Application health checks can be useful not only for internal usage but also external and can aid with supporting customers. Take a look at many large companies and they all have public status pages (especially developer focused ones). Aren't they embarrassed whenever they go down? Perhaps, but it's a natural part of all systems, and the benefit to them is that customers can easily see that they are aware of the problem and are actively working to fix it. Otherwise, they'd be crowding support channels and generally getting frustrated.&lt;/p&gt;
&lt;h2&gt;So health checks are important, but how can we create one?&lt;/h2&gt;
&lt;p&gt;If you have a health check in your application, chances are it might look something like this&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ts"&gt;import express from &amp;quot;express&amp;quot;;

const router = express.Router();

router.all(&amp;quot;/health&amp;quot;, (req, res) =&amp;gt; {
  res.status(200);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok! Good start. In this basic example, this express API is telling the caller of the &lt;code&gt;/health&lt;/code&gt; endpoint that it is up. That can be important information to know, but fairly redundant in some cases. For example, if you host your application using AWS Lambda, Azure Functions, or whatever the GCP one is, then, in reality, all this endpoint is doing is telling you that the cloud provider has not gone down - which is far less likely that your application being unhealthy.&lt;/p&gt;
&lt;h2&gt;Define &amp;quot;unhealthy&amp;quot;&lt;/h2&gt;
&lt;p&gt;A good place to start is to define what unhealthy means for your service. In other words, at what stage will your core application become unusable to the point where your customers will react something like this.&lt;/p&gt;
&lt;div class="image"&gt;
	&lt;img src="https://media0.giphy.com/media/M11UVCRrc0LUk/giphy.gif" /&gt;
&lt;/div&gt;
&lt;p&gt;Nowadays, systems are never usually completely &amp;quot;down&amp;quot; but rather have failure points across a range of services. For example, if you run a microservice architected infrastructure then perhaps one piece of functionality will not work but the core of the application will. Your health checks and your messaging to customers needs to reflect this.&lt;/p&gt;
&lt;p&gt;At Cappfinity, we depend on a number of services to run a pipeline for customers and their candidates alike. Our &amp;quot;unhealthy&amp;quot; state would be when our scoring provider is down, our API and Database are unreachable or when our authentication provider is down. If any of these three components go down then we would not be able to deliver a core service to our customers. Depending on your business, you may have more or less components that you critically depend on.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As an aside, try to look into each one of these components to see if you can deliver a reduced experience if they are unavailable. Netflix do this to great success and you can read more about that here: &lt;a href="https://netflixtechblog.com/making-the-netflix-api-more-resilient-a8ec62159c2d"&gt;https://netflixtechblog.com/making-the-netflix-api-more-resilient-a8ec62159c2d&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Improving the health check&lt;/h2&gt;
&lt;p&gt;Ok so we've defined what &amp;quot;unhealthy&amp;quot; is, so now we need to build the health check itself.&lt;/p&gt;
&lt;p&gt;First, let's dive into each of our critical components and add an endpoint or monitoring around if they can connect to all of their dependant third parties.
For example, if our API depends on a Database and an authentication provider then we might have the following&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ts"&gt;import express from &amp;quot;express&amp;quot;;
import Database from &amp;quot;./lib/database&amp;quot;;
import Auth from &amp;quot;./lib/auth&amp;quot;;

const router = express.Router();

router.all(&amp;quot;/health&amp;quot;, async (req, res) =&amp;gt; {
  const db = await Database.connect(); // check we can connect to the database
  const auth = await Auth.getUserById(1); // check if we can get a random user from our auth provider

  return res.json({
    db: db ? &amp;quot;healthy&amp;quot; : &amp;quot;unhealthy&amp;quot;,
    auth: auth ? &amp;quot;healthy&amp;quot; : &amp;quot;unhealthy&amp;quot;,
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great, so now we're able to tell any caller of this endpoint that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The API is up&lt;/li&gt;
&lt;li&gt;The Database is up&lt;/li&gt;
&lt;li&gt;The authentication provider is up&lt;/li&gt;
&lt;li&gt;The API can connect to the database&lt;/li&gt;
&lt;li&gt;The API can connect to the authentication provider&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The last two points are key, because although you might be able to create a new service that goes and pings these services to see if they are up, you are not telling the caller if those services can be reached. Often, firewalls, static IP's, bad credentials, and other application issues can prevent a service from connecting to another. So it's important to test the connectivity from which ever service relies on it.&lt;/p&gt;
&lt;h2&gt;Internal vs External&lt;/h2&gt;
&lt;p&gt;That health check endpoint is exactly what developers need to assist with debugging a service. However, saying that your database is down to a customer is not really relevant and may even confuse them. In all reality, if you are building a customer facing experience for your service status then you need to think about how to communicate what the impact for them is.&lt;/p&gt;
&lt;p&gt;For example, take a look at Slack status page&lt;/p&gt;
&lt;div class="image"&gt;
	&lt;img src="../../assets/images/slackstatus.png" /&gt;
&lt;/div&gt;
&lt;p&gt;You can see that it doesn't contained detailed break downs of information, but rather individual components of a system that a customer will be familiar with - messaging, login, notifications etc. You should follow a similar pattern, if your system is an API that delivers Woody Harrelson's face as placeholder images for frontend developers, then perhaps you'd have the following services you can report on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The API&lt;/li&gt;
&lt;li&gt;Harrelson import system - for importing a continuous feed of Woody Harrelson's and cropping out everything but the face&lt;/li&gt;
&lt;li&gt;Harrelson's calculator service - the service for getting the correct Woody Harrelson picture based on the size requested by the caller&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can then report those data points to a frontend status page whilst keeping your in-depth health checks that are only accessible by your developers internally.&lt;/p&gt;
&lt;div class="image"&gt;
	&lt;img src="../../assets/images/seriouswork.png" /&gt;
  &lt;em&gt;There we go! Ready for production!&lt;/em&gt;
&lt;/div&gt;
&lt;h2&gt;Resistance&lt;/h2&gt;
&lt;p&gt;In the past, I've seen some companies be hesitant about revealing in depth information about the health of their systems. If you face this kind of opposition then you can reason that the company will benefit for the following reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The company is transparent about it's successes and shortcomings which appeals to people and businesses&lt;/li&gt;
&lt;li&gt;The company is proud of great engineers debugging systems and fulfilling any contractual SLA's&lt;/li&gt;
&lt;li&gt;Developers who consume your application don't have to ring your support line to get help if the system is down&lt;/li&gt;
&lt;li&gt;You're following in the footsteps of some of the largest companies in the world - Netflix, Slack, Stripe, Apple etc.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;I hope you've learnt something and can go out and improve your systems health checks! Please feel free to share with me any of your tips for creating great health checks in the comments below. That's right! My pocky little blog has comments. It's right posh round 'ere now.&lt;/p&gt;</description><author/><pubDate>Fri, 28 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/health-checks/</guid></item><item><title>Mass delete of Gmail emails</title><link>https://anisse.astier.eu/gmail-mass-delete.html</link><description>&lt;p&gt;Gmail used to be the reference for "infinite email storage". Not anymore. The space growth stopped, and then Google started selling storage space.&lt;/p&gt;
&lt;p&gt;It wouldn't be an issue if it were easy to mass delete emails; unfortunately batch delete operations can be quite long, and even lock you out of …&lt;/p&gt;</description><author>Linux Engineer's random thoughts</author><pubDate>Fri, 28 Aug 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://anisse.astier.eu/gmail-mass-delete.html</guid></item><item><title>Yes, computing belongs within social sciences, but...</title><link>https://stop.zona-m.net/2020/08/yes-computing-belongs-within-social-sciences-but.../</link><description>&lt;p&gt;WHO should study WHAT first, exactly?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 27 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/yes-computing-belongs-within-social-sciences-but.../</guid></item><item><title>24 Characteristics That Geniuses Have in Common</title><link>https://www.jimwestergren.com/24-qualities-that-geniuses-have-in-common/</link><description>I am republishing here an excellent article that I first read back in 2002 and that I have read many times since then. I feel I just need to share it, it has worked well for me and might work well for you as well. The worlds greatest geniuses have all had 24 personality characteristics &amp;#91;...&amp;#93;</description><author>Jim Westergren</author><pubDate>Thu, 27 Aug 2020 18:26:00 GMT</pubDate><guid isPermaLink="true">https://www.jimwestergren.com/24-qualities-that-geniuses-have-in-common/</guid></item><item><title>Everyone should learn some programming</title><link>https://voussoir.net/writing/everyone_should_learn_some_programming</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;Everyone should learn some programming&lt;/h1&gt;&lt;ol id="table_of_contents"&gt;Table of contents&lt;li&gt;&lt;a href="#its_easier_than_you_think"&gt;It's easier than you think&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#why"&gt;Why&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="#solve_your_own_problems"&gt;Solve your own problems&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#improve_critical_thinking_problem_solving_and_whatif_skills"&gt;Improve critical thinking, problem solving, and what-if skills&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#increase_your_tech_literacy"&gt;Increase your tech literacy&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#how_to_start"&gt;How to start&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="#javascript"&gt;Javascript&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#python_and_the_command_line"&gt;Python and the command line&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#autohotkey"&gt;AutoHotkey&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#thats_enough_reading"&gt;That's enough reading&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;h2 id="its_easier_than_you_think"&gt;It's easier than you think&lt;a class="header_anchor_link" href="#its_easier_than_you_think"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When people look at programming, they tend to say "That looks so complicated! I could never do that!". But you can. As long as you can describe how to do something step by step, then you have the ability to write a program. That's because writing programs is basically just writing down the steps to solve the problem, and letting the computer do it for you. You could follow the steps yourself and get the exact same result. You could even hire a bunch of schoolchildren for pennies on the dollar under the guise of "enrichment" to carry out your dastardly dictations... if you trust them to be as exacting as the computer, that is. Did you know that the word "computer" &lt;a href="https://en.wikipedia.org/wiki/Computer_(job_description)"&gt;used to refer to people who did computations&lt;/a&gt;?&lt;/p&gt;
&lt;h2 id="why"&gt;Why&lt;a class="header_anchor_link" href="#why"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think that everyone should learn some programming, but I don't think that everyone should become a "programmer". This is like knowing how to put gasoline in your car and air in your tires without being a mechanic; or knowing that protein is good for you and sugar is bad for you without being a nutritionist. Computers and digital files are now involved in just about everything we do, so being comfortable with them automatically improves your ability everywhere else. You will find that knowing a little bit of programming will suddenly be helpful in moments where you didn't expect you'd need it.&lt;/p&gt;
&lt;p&gt;Don't think that programming is only for programmers. That's like thinking that reading is only for Literature majors. Capability with computers is the new literacy.&lt;/p&gt;
&lt;h3 id="solve_your_own_problems"&gt;Solve your own problems&lt;a class="header_anchor_link" href="#solve_your_own_problems"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most software we use today is designed to be used by hundreds, thousands, or millions of people. The creators of the software will try to solve the most common problems of the most common users. They'll make something that works "good enough" for almost everybody, though it won't be totally perfect for almost anybody. There will be something you want to do that the software doesn't have a button for. That's your problem, and it's up to you to solve it.&lt;/p&gt;
&lt;p&gt;If you use computers at all for work, I'm sure you'll find cases where you wish you could improve the tools you have to work with. Recently, at my workplace, I've been writing javascript bookmarklets to add feature improvements to the web-based tools we have to use, so I get things done faster and more easily. And a lot of office jobs will have you working with a slew of document files, making small changes to each or converting them to some other format. This kind of repetitive task is perfect for programming. I recently wrote about &lt;a href="/writing/inkscape_batch_png_pdf"&gt;one such example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you don't use computers for work, don't think you're off the hook. Programming will help you become disciplined in efficiency and planning ahead, and will give you a new vocabulary to express concepts you've probably already thought of. Vocabulary like latency versus throughput or bandwidth, parallel versus sequential tasks, the batching of similar tasks, and bringing down overhead. You'll notice real-life examples of abstractions and interfaces in the design and engineering of physical objects and structures.&lt;/p&gt;
&lt;p&gt;This is not to guarantee that people will congratulate you on automating something, or promote you for doing it. But if you're working at a job you're not satisfied with, programming can turn a boring, rote, why-dont-they-replace-me-with-a-robot task into a fun puzzle that still winds up saving you time in the end. At any rate, I feel that being a strong critical thinker is its own reward while looking for something better.&lt;/p&gt;
&lt;p&gt;I'll give some more of these down below.&lt;/p&gt;
&lt;h3 id="improve_critical_thinking_problem_solving_and_whatif_skills"&gt;Improve critical thinking, problem solving, and what-if skills&lt;a class="header_anchor_link" href="#improve_critical_thinking_problem_solving_and_whatif_skills"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you give instructions to a computer, you have to be pretty specific. They don't exactly think by themselves, and they won't try to figure out what you really mean if your instructions are unclear. You can make a program called &lt;code&gt;add&lt;/code&gt; that actually subtracts, and the computer won't notice or care. If you feel that computers are becoming smarter than people, and you're worried about a cyberpocalyptic android takeover of Earth, just trick your computer into saying 7+3=4 and everything will seem okay again. For a while.&lt;/p&gt;
&lt;p&gt;This means you'll be the one responsible for deciding if the results of your program actually make sense. You'll be the one ensuring that measurements of distance don't become negative, the clock doesn't show a 61&lt;sup&gt;st&lt;/sup&gt; minute, and 7+3=10. You will encounter many unexpected problems while programming, and you will have to solve them. You will accidentally save a new version of the program while continuing to run the old one and wonder why your changes aren't making a difference. You will inadvertently swap left/right with up/down and see the world from a new, more horizontal perspective. You will gain practice in double checking not only your own work but the work of others, to figure out the exact step, possibly one of dozens, where an error was made. If you can combine these troubleshooting habits with good communications skills, you've got the makings to become a teacher, trainer, leader, or manager, wherever you are now.&lt;/p&gt;
&lt;p&gt;As you spend more time programming, you'll find your ability to ask "what if" questions improving. In fact, it's very similar to arguing with someone and trying to poke holes in everything they say. Look for the weaknesses: This program divides two numbers; what if I type in zeroes? This program asks me for my birth year; what if I type in 9999 or HAHA? This program opens multiple urls as browser tabs; what if I give it a billion of them?&lt;/p&gt;
&lt;p&gt;When you're the one writing the program, that means you need to predict the what-ifs that someone else &lt;a class="footnote_link" href="#footnote_text_1" id="footnote_link_1" title="[1] You might think that if you're only writing programs for yourself to use, it doesn't matter because there is no &amp;quot;someone else&amp;quot;. But just know that in six months you will totally forget how you made everything work, and you'll hope for your own sake that you made it idiot-proof."&gt;[1]&lt;/a&gt; might try on your code, and armor up. Are you prepared to divide by zero, or deal with time travelers from the tenth millennium? This will be an exercise in recognizing your own assumptions and challenging them. This skillset will extend to your real life in the way you interpret arguments, politics, news stories, opinion pieces, advertising, and more.&lt;/p&gt;
&lt;p&gt;This is why I have a hard time writing articles about my opinions. I am forever poised to either debunk my own claims or what-if my own thoughts, or else slather the whole article with enough disclaimers and qualifiers as to make the original point unintelligible. But this article is supposed to make you &lt;em&gt;want&lt;/em&gt; to learn programming, so let's move on.&lt;/p&gt;
&lt;p&gt;&lt;a class="footnote_text" href="#footnote_link_1" id="footnote_text_1"&gt;[1]&lt;/a&gt; You might think that if you're only writing programs for yourself to use, it doesn't matter because there is no "someone else". But just know that in six months you will totally forget how you made everything work, and you'll hope for your own sake that you made it idiot-proof.&lt;/p&gt;
&lt;h3 id="increase_your_tech_literacy"&gt;Increase your tech literacy&lt;a class="header_anchor_link" href="#increase_your_tech_literacy"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let's talk about literacy a little more. We are in a transitional period of history. When I was younger, everyone seemed to believe that my generation and all future generations would be naturally good with computers because we've grown up with them in our lives. But, in fact, that book is now shutting as fast as it opened. More and more kids are growing up with &lt;em&gt;smartphones&lt;/em&gt; in their lives, but not &lt;em&gt;computers&lt;/em&gt;. That shouldn't make a difference, because smartphones are just small computers. The thing is that smartphones were invented and developed from start to finish by corporations who have realized how much money there is to be made in an industry of locked-down devices, walled gardens, and advertising-driven-algorithmically-curated experiences. To continue the literacy metaphor, today's children are growing up with nothing but picture books. Desktop computers, on the other hand, are still carrying their heritage from the before days — the days of inspectibility, customizablilty, and programmability — because they were designed as a tool for solving your problems rather than dominating your attention. And when I say carrying their heritage, I mean reluctantly. Microsoft, Apple, and Google would love to drop desktop programmability in favor of locked-down devices if they could get away with it. They can't, though, because of all the existing software in the world relying on existing systems. Smartphones didn't have that burden, and look where they've ended up.&lt;/p&gt;
&lt;p&gt;Learning a little bit of programming can be a breakthrough into realizing that the world of computers is not meant to be a theme park that you just wander around in. Computers and software are made by people just like you, and you are on equal ground with them. You can be an active participant in this world and mold your tools to work the way you want. Computers were designed to do work &lt;em&gt;for you&lt;/em&gt;, though corporations will gladly continue to take that power away so they can show you more ads and sell you more junk.&lt;/p&gt;
&lt;p&gt;It is liberating to say "This program/website doesn't let me do exactly what I'd like, but that's ok, I'll just fix it myself". You'll start to notice the ways software and publishers want to disempower you, and how you can reclaim the upper hand. Oh, you won't let me right-click the image to download it? That's ok, I've got Inspect Element. Won't let me read the whole article? Let's try spoofing googlebot's useragent. This program doesn't let me choose where it gets installed or stores its files? A few filesystem junctions will put that back in its place. No more waiting around for the software gods at the temple of Goog to eventually fix what's wrong, like you have to do on your smartphone, because you can fix it now.&lt;/p&gt;
&lt;p&gt;Throughout history, corrupted leaders have used the illiteracy of their constituents to take advantage of them. This will happen to us digitally, too, if we do not cultivate tech literacy. I do rely on the tech leaders, after all. I'm not able to manufacture my own processors or write my own operating systems, so I need your help in defending what we've got from the current trend of eroding control.&lt;/p&gt;
&lt;h2 id="how_to_start"&gt;How to start&lt;a class="header_anchor_link" href="#how_to_start"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many aspects of computing and programming are interlinked, and it won't be possible to fully understand one part before you know many other parts too. That's okay. Become comfortable with the feeling that you don't understand everything that's going on, because it will be happening a lot. The important thing is to keep growing your web of knowledge and you'll discover how each piece links with the others.&lt;/p&gt;
&lt;p&gt;In the beginning, don't buy textbooks. Don't enroll in courses or watch an entire video series. Don't look for a tutor. The first step is to develop your interest and a sense of accomplishment that gives you the motivation to continue. Motivation will be very important, and it comes from achievement. Solving real life problems that are relevant to you, no matter how small, are the perfect way of doing this. I guarantee that writing tiny, simple programs will feel amazing when the result is something that's actually useful and important to you. I am not saying to avoid textbooks forever, but they tend to make you do things that don't feel important yet. Save them for after you've found your footing and want to get a more rounded knowledge of programming as a subject.&lt;/p&gt;
&lt;p&gt;Any time you find yourself thinking "doing the same thing over and over again is so boring, I wish I could do it all automatically", this is an immediate sign that you can program it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Moving all these jpegs into the jpeg folder is so boring, ...&lt;/li&gt;
&lt;li&gt;Copying all these names from emails into spreadsheets is so boring, ...&lt;/li&gt;
&lt;li&gt;Refreshing this store page to see when the product goes on sale is so boring, ...&lt;/li&gt;
&lt;li&gt;Cross-referencing the deadlines on this page with the details on this other page is so boring, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But don't forget to have fun. If you find yourself saying "I wish I had a way to..."&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;... count all the swear words in Tarantino's movies.&lt;/li&gt;
&lt;li&gt;... put my face on every movie poster I can get my hands on.&lt;/li&gt;
&lt;li&gt;... practice typing with my own sample text.&lt;/li&gt;
&lt;li&gt;... get an alert whenever a new post is made on this forum / subreddit.&lt;/li&gt;
&lt;li&gt;... make all the text on this page look like Runescape's &lt;code&gt;wave&lt;/code&gt; or Comic Sans.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;that's something else you can program for.&lt;/p&gt;
&lt;p&gt;As I said earlier, you can write a program for anything &lt;em&gt;as long as you can describe how to do it step by step&lt;/em&gt;. That means that whenever you want to write a program, the first thing you have to do is actually walk &lt;em&gt;away&lt;/em&gt; from the computer and think about the problem. Talk through the steps, draw them out on paper, practice them physically, or instruct someone else to perform them as if they were your computer. Don't trick yourself into thinking you can make the computer do things that you yourself don't understand or can't describe. If you get into this mindset, you won't be able to live up to your own expectations which will kill your motivation.&lt;/p&gt;
&lt;p&gt;As you try to describe the steps of your program, you will have to figure out how to make the computer understand what you want. You will find yourself searching the internet for "how to count words", "how to read webpage text", "how to only count each thing once", "how to save data to file", "difference between strings and ints and floats", "how to play video/audio file". You should never feel bad about looking these things up. Your job is not to become a memorization machine, but to know your problem and where to find the solution.&lt;/p&gt;
&lt;p&gt;You will want a good text editor. I use Sublime Text 2, but I have heard good things about Microsoft's &lt;a href="https://code.visualstudio.com/"&gt;VS Code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you don't have access to a PC, but you do have an Android smartphone, try &lt;a href="https://termux.com/"&gt;Termux&lt;/a&gt;. Though, I think you'll want to plug in a real keyboard.&lt;/p&gt;
&lt;p&gt;Programs are written in a variety of programming languages. If you want to get started with programming, I recommend the following.&lt;/p&gt;
&lt;h3 id="javascript"&gt;Javascript&lt;a class="header_anchor_link" href="#javascript"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Javascript is the language that your web browser uses to make the page interactive. There is also HTML which contains the page content, and CSS which controls how it looks.&lt;/p&gt;
&lt;p&gt;When you first start programming, it will be difficult to write a program from scratch. Instead, it will be easier to take an existing program, make a little change, and see what happens. Keep doing that over and over again with bigger and bigger changes, and pretty soon you're writing your own program. This is how I started too.&lt;/p&gt;
&lt;p&gt;Well, the great thing about Javascript is that every website you visit already has a program that you can modify and play with! Just right click and choose "Inspect Element", or press F12, and check out the elements, console, network, and more.&lt;/p&gt;
&lt;p&gt;Try making &lt;a href="https://en.wikipedia.org/wiki/Bookmarklet"&gt;bookmarklets&lt;/a&gt;, which are pieces of Javascript code that you can save on your browser's bookmark bar, and then you just click them to activate it. The code goes in the place where you'd normally put the URL. For example, &lt;a href="https://git.voussoir.net/voussoir/else/src/branch/master/Javascript/loopplayall.js"&gt;this bookmarklet&lt;/a&gt; automatically plays any video element on the page, which is great for forums with a lot of webms, and &lt;a href="https://git.voussoir.net/voussoir/else/src/branch/master/Javascript/tab_renamer.js"&gt;this one&lt;/a&gt; can rename the current tab, which is great when several tabs have the same name.&lt;/p&gt;
&lt;p&gt;Also try making .html files on your computer and opening them in your browser. It's like creating a website without actually having to create a website. For example, &lt;a href="https://git.voussoir.net/voussoir/else/src/branch/master/Javascript/reddit_live_new.html"&gt;this page I wrote&lt;/a&gt; shows new posts on a subreddit when they're made. You'll be amazed how simple it is to create something that could be described as a "web app".&lt;/p&gt;
&lt;p&gt;A word of warning, though. The Javascript community has created dozens and dozens of frameworks and libraries and packages that they say you should use. Don't. For the time being, don't download anything, don't import anything, don't &lt;code&gt;require&lt;/code&gt; anything. No jQuery, no React, no nothing. The default javascript tools in your browser are enough to do what you want to do. The low barrier of entry to working with javascript is a great boon, but it also means the internet is overflowing with stuff people have made and shared, and it will be too confusing to navigate it all right now. Just have fun writing what achieves your goal. Stick to the standard stuff, and search &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript"&gt;MDN&lt;/a&gt; for how to use it. For example, here's the page on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText"&gt;element.innerText&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="python_and_the_command_line"&gt;Python and the command line&lt;a class="header_anchor_link" href="#python_and_the_command_line"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://python.org"&gt;Python&lt;/a&gt; has been my favorite programming language since I discovered it in 2014. I mentioned Javascript first because the accessibility of getting started is so much higher, but Python is where it's at if you need to write anything that isn't web browser based.&lt;/p&gt;
&lt;p&gt;The standard library (modules and tools included with Python when you download it) are very capable so, like Javascript, you shouldn't have to worry about downloading other people's stuff to get started with the very basics.&lt;/p&gt;
&lt;p&gt;I use Python for just about every facet of file management on my computer, like &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/brename.py"&gt;renaming all files in a folder&lt;/a&gt;, &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/recycle.py"&gt;sending files to the recycle bin&lt;/a&gt;, &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/prune_dirs.py"&gt;clearing out empty folders&lt;/a&gt;, &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/extension_summary.py"&gt;counting file extensions&lt;/a&gt;, and putting together &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/ffstreams.py"&gt;ffmpeg commands&lt;/a&gt; that I wouldn't want to write by hand. I also &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/crop.py"&gt;crop&lt;/a&gt;, &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/resize.py"&gt;resize&lt;/a&gt;, and convert images to &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/grayscale.py"&gt;grayscale&lt;/a&gt; or the &lt;a href="https://git.voussoir.net/voussoir/cmd/src/branch/master/icoconvert.py"&gt;Windows .ico format&lt;/a&gt;. I love writing in Python and I hope you will too.&lt;/p&gt;
&lt;p&gt;Once again, you can start by downloading somebody else's program and making small tweaks to it to see what happens. I find this more approachable than starting from a blank screen.&lt;/p&gt;
&lt;p&gt;Although text editors and IDEs may let you run Python code within the editor, you will need to get comfortable with the command line to be most effective, so take the time to understand it.&lt;/p&gt;
&lt;h3 id="autohotkey"&gt;AutoHotkey&lt;a class="header_anchor_link" href="#autohotkey"&gt; (§)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://autohotkey.com"&gt;AutoHotkey&lt;/a&gt; is in a different category than most programming languages, but I think it's excellent for programming learners to play around with because it's quite exciting to watch your mouse cursor fly around and do things by itself. For example, I once made &lt;a href="https://git.voussoir.net/voussoir/ahk/src/branch/master/clickerheroes.ahk"&gt;an AHK script&lt;/a&gt; that would automatically click on the bonus items in Clicker Heroes, and a similar one for emptying my entire backpack into a chest in Minecraft.&lt;/p&gt;
&lt;p&gt;The ability to create custom hotkeys really puts the Personal in Personal Computer. I have &lt;a href="https://git.voussoir.net/voussoir/ahk/src/branch/master/volumecontrol.ahk"&gt;custom volume buttons&lt;/a&gt;, custom &lt;a href="https://git.voussoir.net/voussoir/ahk/src/branch/master/custom_hangul.ahk"&gt;English/Korean keyboard swap buttons&lt;/a&gt;, and a button for keeping the current window &lt;a href="https://git.voussoir.net/voussoir/ahk/src/branch/master/alwaysontop.ahk"&gt;always on top&lt;/a&gt;, which makes me feel like a wizard.&lt;/p&gt;
&lt;p&gt;Also, AHK scripts tend to be short and sweet, so you don't get stuck on a particular project for too long, which is a good thing for learners. You can learn something, enjoy it, and move on.&lt;/p&gt;
&lt;p&gt;The AHK syntax is a bit confusing, and I can never remember which of &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;^&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;, etc. I need to make my hotkey. But that's why there are &lt;a href="https://www.autohotkey.com/docs/Hotkeys.htm#Symbols"&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="thats_enough_reading"&gt;That's enough reading&lt;a class="header_anchor_link" href="#thats_enough_reading"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Go get started. Have fun.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/everyone_should_learn_some_programming/everyone_should_learn_some_programming.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/3475cb0abf63172e6392487ffaf41755f71a18e3"&gt;&lt;time datetime="2023-09-18T21:01:09-07:00"&gt;2023-09-18&lt;/time&gt; Replace github links with git.voussoir.net.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/8224052c8cc9d79a3acf832f69fcd46a4d045552"&gt;&lt;time datetime="2022-04-07T11:37:43-07:00"&gt;2022-04-07&lt;/time&gt; Move AHK links to my new repository.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/d0a0bc2227b399bd1f118d056c5024c7e06e733a"&gt;&lt;time datetime="2020-08-26T16:25:47-07:00"&gt;2020-08-26&lt;/time&gt; Add everyone_should_learn_some_programming.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Thu, 27 Aug 2020 02:25:47 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/everyone_should_learn_some_programming</guid></item><item><title>A critique of data unions</title><link>https://stop.zona-m.net/2020/08/a-critique-of-data-unions/</link><description>&lt;p&gt;Are YOU ready to &amp;ldquo;retail your data&amp;rdquo;?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 26 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/a-critique-of-data-unions/</guid></item><item><title>The Undocumented SWIG</title><link>https://blog.vito.nyc/posts/swig-part1/</link><description>&lt;p&gt;For those who have never ventured into the dark underworld of the Python
C‑Extension API, you may believe that it is as fluid and rewarding as
the rest of the Python ecosystem. I regret to inform you that this is not the
case. Line 13 of &lt;a href="https://www.python.org/dev/peps/pep-0020/"&gt;&lt;em&gt;The Zen of Python&lt;/em&gt;&lt;/a&gt;
says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There should be one &amp;ndash; and preferably only one &amp;ndash; obvious way to do it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The C‑Extension API is an excellent example of what happens when one
completely ignores that advice. There are two (incompatible) ways to export a
module, a half-dozen &lt;em&gt;documented&lt;/em&gt; ways to parse an argument list, and no less
than nine options for calling a method. The documentation for this mess is
excellent by C Library standards, but falls woefully short of the gold standard
set by the rest of the Python docs.&lt;/p&gt;</description><author>vito.nyc</author><pubDate>Wed, 26 Aug 2020 20:46:15 GMT</pubDate><guid isPermaLink="true">https://blog.vito.nyc/posts/swig-part1/</guid></item><item><title>ExoTracker Newsletter #1</title><link>https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/</link><description>&lt;p&gt;I just finished implementing timeline entry editing. Since I have school coming up, I decided to release a demo of its current state. Since my summary was getting a bit too long to post in Discord, I decided to write a blog post / newsletter.&lt;/p&gt;
&lt;h2 id="demo-download"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/#demo-download"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
Demo download&lt;/h2&gt;
&lt;p&gt;Windows 64-bit: &lt;a href="https://ci.appveyor.com/api/buildjobs/3e0uv6sxov74g50d/artifacts/exotracker-v1.0.60-dev.7z" rel="external"&gt;https://ci.appveyor.com/api/buildjobs/3e0uv6sxov74g50d/artifacts/exotracker-v1.0.60-dev.7z&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Source: &lt;a href="https://gitlab.com/nyanpasu64/exotracker-cpp/-/tree/timeline-editor" rel="external"&gt;https://gitlab.com/nyanpasu64/exotracker-cpp/-/tree/timeline-editor&lt;/a&gt; (currently commit d5386ea0). It only compiles in recent GCC and Clang (only tested Clang 10), due to using statement expressions.&lt;/p&gt;
&lt;h2 id="demo-notes"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/#demo-notes"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
Demo notes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Press Space to enable note entry, and Enter to play.&lt;/strong&gt; Unfortunately, note preview is not supported yet.&lt;/li&gt;
&lt;li&gt;ExoTracker uses a FamiTracker-style piano layout.&lt;/li&gt;
&lt;li&gt;Only Famicom/NES APU1 is supported. Some demo songs have dual APU1 which can be used for composing.&lt;/li&gt;
&lt;li&gt;Notes, instruments, and volumes are supported. Effects are not.&lt;/li&gt;
&lt;li&gt;Try passing in names of sample documents as command-line arguments. Listed in order from most to least useful:
&lt;ul&gt;
&lt;li&gt;Partial songs: &lt;code&gt;dream-fragments&lt;/code&gt;, &lt;code&gt;world-revolution&lt;/code&gt; (default song)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;empty&lt;/code&gt; (add your own notes)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;audio-test&lt;/code&gt; (dual APU1) (sounds bad, but useful for finding audio stuttering)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;block-test&lt;/code&gt; (dual APU1) (rendering test for block system, no notes or events)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;render-test&lt;/code&gt; (sounds bad, negative octave text is too wide for the screen)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some sample documents have short and/or looped blocks (the gray rectangles to the left of each channel), which are not possible in most other trackers (I don't know if LSDj and C64 trackers support this). But right now, users can only create full-grid blocks, and cannot delete blocks.
&lt;ul&gt;
&lt;li&gt;The block system is powerful, but unfortunately not editable through the UI yet, so you can't try it out to see useful it is.&lt;/li&gt;
&lt;li&gt;Pattern reuse is not implemented.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;All edits are undoable. Some but not all timeline edits save cursor position.&lt;/li&gt;
&lt;li&gt;There are buttons for reordering timeline entries. They're supposed to have icons instead of text, but icons are only available on my machine.&lt;/li&gt;
&lt;li&gt;The actual timeline widget (list of rows) is unfinished and will be replaced with a custom-drawn widget.&lt;/li&gt;
&lt;li&gt;The audio code will lock up if you decrease the timeline row length until a block has a negative length 😉&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="timeline-system-overview"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/#timeline-system-overview"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
Timeline system overview&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;tl;dr skip forward to "Demo feedback" if you want to just play with the program instead of reading documentation.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The frame/order editor is replaced with a timeline editor, and its functionality is changed significantly.&lt;/p&gt;
&lt;p&gt;The pattern grid structure from existing trackers is carried over (under the name of timeline rows and grid cells). Each timeline row has its own length which can vary between rows (like OpenMPT, unlike FamiTracker). Each timeline row holds one timeline cell (or grid cell) per channel. However, unlike patterns, timeline cells do not contain events directly, but through several layers of indirection.&lt;/p&gt;
&lt;p&gt;A timeline cell can hold zero or more blocks, which carry a start and end time (in integer beats) and a pattern. These blocks have nonzero length, do not overlap in time, occur in increasing time order, and lie between 0 and the timeline cell's length (the last block's end time can take on a special value corresponding to "end of cell")[1].&lt;/p&gt;
&lt;p&gt;Each block contains a single pattern, consisting of a list of events and an optional loop duration (in integer beats). The pattern starts playing when absolute time reaches the block's start time, and stops playing when absolute time reaches the block's end time. If the loop duration is set, whenever relative time (within the pattern) reaches the loop duration, playback jumps back to the pattern's begin. A block can cut off a pattern's events early when time reaches the block's end time (either the pattern's initial play or during a loop). However a block cannot start playback partway into a pattern (no plans to add support yet).&lt;/p&gt;
&lt;p&gt;Eventually, patterns can be reused in multiple blocks at different times (and possibly different channels).&lt;/p&gt;
&lt;p&gt;[1] I'm not sure what to do if a user shrinks a timeline row, which causes an numeric-end block to end past the cell, or an "end of cell" block to have a size ≤ 0, etc.&lt;/p&gt;
&lt;h3 id="motivation"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/#motivation"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
Motivation&lt;/h3&gt;
&lt;p&gt;The timeline system is intended to allow treating the program like FamiStudio or a tracker, with timestamps encoded relative to current pattern/frame begin, and reuse at pattern-level granularity. If you try to enter a note/volume/effect in a region without a block in place, a block is automatically created in the current channel, filling all empty space available (up to an entire grid cell) (not implemented yet).&lt;/p&gt;
&lt;p&gt;It is also intended to have a similar degree of flexibility as a DAW like Reaper (fine-grained block splitting and looping). The tradeoff is that because global timestamps are relative to grid cell begin, blocks are not allowed to cross grid cell boundaries (otherwise it would be painful to convert between block/pattern-relative and global timestamps).&lt;/p&gt;
&lt;h2 id="unresolved-questions"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/#unresolved-questions"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
Unresolved questions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Are the gray block rectangles (to the left of each channel) ugly? I'm planning to use those to allow dragging patterns around, resizing them, and distinguishing reused patterns through color.&lt;/li&gt;
&lt;li&gt;Should I rename the timeline to something else?
&lt;ul&gt;
&lt;li&gt;Sequence?&lt;/li&gt;
&lt;li&gt;Order? (I feel it's bad because "order" implies every entry is merely the ID of a single pattern, but in reality is a container for 0 or more loopable patterns.)&lt;/li&gt;
&lt;li&gt;OpenMPT has an "order list" widget to edit a "sequence" of patterns; it uses two names for similar concepts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What should I call a row/unit in the timeline editor? It's treated as a coarse unit of time and a container for blocks/patterns, but is not a pattern.
&lt;ul&gt;
&lt;li&gt;Grid row? Timeline/sequence row? (I keep confusing "timeline row" with "pattern row". "Grid" is concise, but I don't know if it's an unintuitive name.)&lt;/li&gt;
&lt;li&gt;Segment?&lt;/li&gt;
&lt;li&gt;(Timeline/sequence) entry?&lt;/li&gt;
&lt;li&gt;Cell? (currently used for "one row, one channel")&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How should I improve my current behavior when adding and deleting timeline entries?
&lt;ul&gt;
&lt;li&gt;Should adding a new timeline entry move the cursor to the new entry's row 0? Should undoing move the cursor to the same spot, move it to the old location, or leave the cursor in place?&lt;/li&gt;
&lt;li&gt;Should deleting an timeline entry move the cursor to the former entry's row 0? Should undoing move the cursor to the same spot, move it to the old location, or leave the cursor in place?&lt;/li&gt;
&lt;li&gt;Eventually I'll add the ability to right-click and add/delete timeline entries other than the one the cursor is in. Should the cursor move to the right-clicked entry, and stay there after undoing?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Once the timeline widget is implemented, what should it show?
&lt;ul&gt;
&lt;li&gt;Titles for each sequence entry?&lt;/li&gt;
&lt;li&gt;"Pattern overview" with coarse-grained visualizations of blocks (gray for unique blocks, colored for shared)? Should shared patterns have numbers? Names? Should all patterns have numbers (an idea I'm not a fan of)?&lt;/li&gt;
&lt;li&gt;Draw both (and somehow try to find enough room for both)?&lt;/li&gt;
&lt;li&gt;0CC has bookmarks and highlights, but doesn't show all names.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="feedback"&gt;&lt;a class="zola-anchor" href="https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/#feedback"&gt;&lt;span&gt;🔗&lt;/span&gt;&lt;/a&gt;
Feedback&lt;/h2&gt;
&lt;p&gt;If you find any crash bugs, let me know. (Some tricky-to-get-right areas were deleting the last row in the timeline, or deleting a long row and the cursor moves into the next, shorter, row.)&lt;/p&gt;
&lt;p&gt;If you have any UI or behavior suggestions, tell me too. (I personally think I got the code reasonably watertight, but the UI behavior is a toss-up and I have no clue how people will react.)&lt;/p&gt;
&lt;p&gt;You can report issues at &lt;a href="https://gitlab.com/nyanpasu64/exotracker-cpp/-/issues" rel="external"&gt;https://gitlab.com/nyanpasu64/exotracker-cpp/-/issues&lt;/a&gt;.&lt;/p&gt;</description><author>nyanpasu64's blog</author><pubDate>Wed, 26 Aug 2020 11:46:00 GMT</pubDate><guid isPermaLink="true">https://nyanpasu64.gitlab.io/blog/exotracker-newsletter-1/</guid></item><item><title>I Am the Reactor Operator</title><link>https://blog.vito.nyc/posts/i-am-the-reactor-operator/</link><description>&lt;p&gt;What follows is the personal statement that I submitted to Columbia and NYU as
part of my college applications. I was always going to end up talking about the
Navy, submarines, and the nuclear pipeline. It was my life for the past six
years, there was no avoiding it. I needed to pick a single experience that
could relate to all of that and also myself as an individual, inside
six-hundred fifty words. Ultimately the essay needed to highlight why I was a
good choice to admit to these prestigious institutions, not educate the reader
about submarines.&lt;/p&gt;</description><author>vito.nyc</author><pubDate>Wed, 26 Aug 2020 05:58:23 GMT</pubDate><guid isPermaLink="true">https://blog.vito.nyc/posts/i-am-the-reactor-operator/</guid></item><item><title>Final Report - GSoC 2020</title><link>https://wantguns.dev/blog/final-report/</link><description>&lt;p&gt;Its almost 3 months since I have been officially working with the
SharkBait team at Gentoo. A lot of ground has been covered, a lot is
still left. In this blog, I will explain the scope of SharkBait right
now and how I plan its future.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="work-covered"&gt;Work Covered&lt;/h2&gt;
&lt;h3 id="porting-sharkbaitos"&gt;Porting SharkBaitOS&lt;/h3&gt;
&lt;p&gt;When KireinaHoro started working on SharkBait, the latest Android
version of that time was 8 or Android Oreo. Sharkbait at that time,
supported all the Android devices because it targeted only a specific
boot order, which was common till Android 8.
Then came Android 9, with its System-As-Root configuration, which
rendered SharkBait's original boot order non functional for all devices
shipping with Android 9. &lt;br /&gt;
The first month of my work revolved around porting SharkBait to SAR
based devices. I succeeded in doing so, and wrote blogs about it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wantguns.dev/blog/android-boot-high-jinks/"&gt;&lt;strong&gt;Android Boot High Jinks&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
In this blog we discuss the different approaches at booting
Android, Google has experimented with.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wantguns.dev/blog/booting-gentoo-using-preinit/"&gt;&lt;strong&gt;Booting Gentoo from SAR-Preinit&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
This blog showcases how I patched my phone's kernel in order to
boot Gentoo on my phone.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wantguns.dev/blog/starting-android-in-gentoo/"&gt;&lt;strong&gt;Starting System-as-Root Android in a LXC container&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
This blog is the first class guide for launching SharkBait in
System-As-Root devices.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The projects made in efforts to port SharkBait for SAR were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit" rel="external"&gt;&lt;strong&gt;SAR-Preinit&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
This repository acts as the setup which patches your custom kernel
and makes it boot a GNU/Linux distro, instead of Android on your
phone.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/WantGuns/bootstrap-init" rel="external"&gt;&lt;strong&gt;Bootstrap-init&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
This repository hosts the source of the init binary executed inside
the LXC container which launches System-As-Root Android on top of
Gentoo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="introducing-android-builds-on-aarch64-hosts"&gt;Introducing Android builds on AArch64 Hosts&lt;/h3&gt;
&lt;p&gt;As simple as it sounds, this part of my GSoC tenure turned out to be the
exact opposite. &lt;br /&gt;
My first task was to provide a AArch64 native port of the LLVM toolchain
AOSP uses. I was stuck on compiling and testing my modified scripts till
the second month, when my mentor generously set up a beefy AArch64
server for me. I succeeded in delivering that toolchain. Related sources
are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wantguns.dev/blog/build-android/"&gt;&lt;strong&gt;Building Android: BTS&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
In this blog, I look what events get triggered under the hood when
we build Android, as to seek insight on breaking down Android later.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WantGuns/toolchain_llvm_android" rel="external"&gt;&lt;strong&gt;Toolchain_LLVM_Android&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
This repository hosts the build scripts and instructions on building
AOSP's LLVM distribution on AArch64 Host, which targets AArch64 and
Arm platforms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once I dealt with the toolchains, I could focus on building Android.
Unfortunately this part is still unfinished due to the massive scale of
thought-process and work it requires. Still, I will report on whatever I
have been doing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/WantGuns/manifest/" rel="external"&gt;&lt;strong&gt;Manifest&lt;/strong&gt;&lt;/a&gt; &lt;br /&gt;
This is the (yet-to-be) SharkBait Manifest. It houses the different
AOSP components SharkBait pulls in order to build Android. Some of
which I have been working on:
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/WantGuns/android_build_soong/commits?author=WantGuns" rel="external"&gt;android_build_blueprint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WantGuns/android_build_soong/commits?author=WantGuns" rel="external"&gt;android_build_soong&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/WantGuns/android_build/commits?author=WantGuns" rel="external"&gt;android_build&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="future-work"&gt;Future Work&lt;/h2&gt;
&lt;p&gt;There are many things to be concerned with such as the flow of project
development to follow, how exactly we should aim introducing
arm64 as an host. &lt;br /&gt;
Plus the final goal of SharkBait is the ability to
upgrade its Android container with the use of Portage, thus providing
granular, GNU like updates to Android, quite possibly the first time
ever. Keeping all this in mind we needed a proper roadmap on how to
achieve this. My vision for it resembles somewhat like the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build Android as an whole separate entity on AArch64.&lt;/li&gt;
&lt;li&gt;Then compose a monolithic ebuild for the exact same thing.&lt;/li&gt;
&lt;li&gt;Start breaking parts from Android:
&lt;ul&gt;
&lt;li&gt;Ship the toolchains used by AOSP separately using Portage and
possibly integrate it with crossdev.&lt;/li&gt;
&lt;li&gt;Ship the necessary prebuilt &lt;a href="https://github.com/LineageOS/android_prebuilts_build-tools" rel="external"&gt;build-tools&lt;/a&gt; AOSP bundles as
packages with Portage on arm64.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Capitalizing on the fact that AOSP code is highly modular, separate
those modules into different packages under a common overlay.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And since I consider myself apt in bringing this for SharkBait, I would
love to work on it even after GSoC finishes.&lt;/p&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;I immensely appreciate the patience of my mentor, Benda Xu. He has
always given me the helm when it comes to SharkBait, while still
actively monitoring my work and helping me out. Without his generous
efforts of providing me with an industry-standard arm64 server, I dont
think I could consider this GSoC a success.&lt;/p&gt;
&lt;p&gt;My co-mentors - Pengcheng Xu, Lucas Ramage and Stephen Christie helped
me whenever I got stuck in my work. Pengcheng offered me assistance in
getting UART work for my Phone, Lucas actively kept a lookout on my work
and Stephen would offer me assistance in getting better hardware without
two thoughts.&lt;/p&gt;
&lt;p&gt;All of them offered crucial personal help whenever I was stuck, be it my
work, understanding the project or even my proposal writing, something
which I can never overlook.&lt;/p&gt;
&lt;p&gt;The least I can do to return their favours is to bring SharkBait to all
its glory, which I eagerly wait for.&lt;/p&gt;</description><author>Gunwant Jain - @wantguns</author><pubDate>Wed, 26 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://wantguns.dev/blog/final-report/</guid></item><item><title>Fixing crackling audio on USB powered speakers and Raspberry Pi</title><link>https://gaganpreet.in/posts/audio-crackling-raspberry-pi-usb-speakers/</link><description>&lt;h3 class="relative group" id="powering-usb-speakers-from-raspberry-pi"&gt;Powering USB speakers from Raspberry Pi &lt;span class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100"&gt;&lt;a class="group-hover:text-primary-300 dark:group-hover:text-neutral-700" href="#powering-usb-speakers-from-raspberry-pi"&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h3&gt;&lt;p&gt;I recently set up Mycroft (an open source personal assistant) on my Raspberry Pi. I bought a set of cheap speakers which run on USB power and plugged them into the 3.5mm output and the power cable to a USB port on the Pi itself. Right away I heard constant crackling noises coming out of the speakers. I figured I had a set of defective speakers but I could not reproduce this when I tried the same setup with my laptop.&lt;/p&gt;</description><author>Gaganpreet Arora</author><pubDate>Wed, 26 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://gaganpreet.in/posts/audio-crackling-raspberry-pi-usb-speakers/</guid></item><item><title>Roaming</title><link>https://adriano.fyi/posts/2020-08-26-roaming/</link><description>&lt;h2 id="where-am-i"&gt;Where am I?&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve been wanting to write about what I&amp;rsquo;ve been up to the past couple of months and keep putting it off because I convinced myself that I need to write a long and protracted post about &lt;em&gt;why&lt;/em&gt; I&amp;rsquo;m living in a travel trailer. Oh yeah, I live in a travel trailer now. But I don&amp;rsquo;t think I&amp;rsquo;ll delve into &lt;em&gt;why&lt;/em&gt; I felt compelled to leave NYC and become trailerfolk because it&amp;rsquo;s really not that profound or interesting. Before anyone asks &amp;ndash; it had nothing to do with COVID-19. In fact, this has been my plan for well over a year.&lt;/p&gt;
&lt;p&gt;My new home

&lt;input hidden="hidden" id="zoomCheck-3e817" type="checkbox" /&gt;
&lt;label for="zoomCheck-3e817"&gt;
  &lt;img alt="The rig in Grand Teton" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/yxNEJzKC2ficqFq/preview" title="The rig in Grand Teton" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re curious about keeping up with where I am. Check out &lt;a href="https://adriano.fyi/whereami"&gt;WHERE AM I&lt;/a&gt; at the top-right of the screen any time. That&amp;rsquo;s hooked into my router&amp;rsquo;s GPS system and gets updated any time I&amp;rsquo;m online. It&amp;rsquo;ll show my last-known location any time I&amp;rsquo;m off-grid.&lt;/p&gt;
&lt;h2 id="lets-get-these-out-of-the-way"&gt;Let&amp;rsquo;s get these out of the way&lt;/h2&gt;
&lt;p&gt;The three most common questions people have asked about this new and somewhat unorthodox lifestyle are&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Where are you headed?!&lt;/li&gt;
&lt;li&gt;How long are you planning to do this for?!&lt;/li&gt;
&lt;li&gt;What are you doing?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So let&amp;rsquo;s go ahead and tackle each one of these&amp;hellip;&lt;/p&gt;
&lt;h3 id="where-are-you-headed"&gt;Where are you headed?!&lt;/h3&gt;
&lt;p&gt;Nowhere and everywhere. Everyone who knows me knows that I love the mountains and outdoors, so I&amp;rsquo;ll be spending the majority of my time either in the Rockies or Cascades, depending on the time of year. My original plan for this year was to spend a considerable amount of time in the Canadian Rockies, but the border shutdown has put the brakes on that plan for the foreseeable future.&lt;/p&gt;
&lt;h3 id="how-long-are-you-planning-to-do-this-for"&gt;How long are you planning to do this for?!&lt;/h3&gt;
&lt;p&gt;I don&amp;rsquo;t know; this whole ordeal has been pretty sweet. A long time. At least a year, but I&amp;rsquo;d like to hit the 2-year mark if I don&amp;rsquo;t tire of ultra-confined living too quickly. I&amp;rsquo;ll be living in a mix of both on- and off-grid camp settings; wherever there is good LTE signal is a possible base camp. I may do a write up on my wireless setup and all the research that went into it. And how it all fails catastrophically in the more-often-than-you&amp;rsquo;d-think event of entire cell towers going down. Fun fact: &lt;em&gt;most of Grand Teton valley loses cell data service entirely every day at 11:30 local time&lt;/em&gt;. All. Three. Major. Providers. So much for redundant service plans.&lt;/p&gt;
&lt;h3 id="what-are-you-doing"&gt;What are you doing?&lt;/h3&gt;
&lt;p&gt;Mostly working. I haven&amp;rsquo;t taken a vacation almost all year. I work East Coast hours and then run, rock climb, or mountain bike in the afternoon. Granted my mountain bike is currently out of commission with a bum bushing in the rear suspension. Although I just put an order in for a Specialized Diverge, so I&amp;rsquo;ll be gravel biking like crazy soon.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve also been fiddling with a lot of my side projects&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Setting up Nextcloud for all my documents, pictures, etc. It&amp;rsquo;s been a great time.&lt;/li&gt;
&lt;li&gt;Setting up my Linode server which hosts this site and Nextcloud. &lt;a href="https://github.com/acaloiaro/adriano.fyi"&gt;This site&lt;/a&gt; and &lt;a href="https://github.com/acaloiaro/roam-location"&gt;the code that powers &amp;ldquo;Where Am I?&amp;rdquo;&lt;/a&gt; are both open source. Not that I&amp;rsquo;m proud of any of that source, but I do prefer to build things openly.&lt;/li&gt;
&lt;li&gt;Wiring my router and drilling holes through the cabinetry of my brand new trailer. I don&amp;rsquo;t know if that project is worth a write up, but I&amp;rsquo;m proud to have only blown a single fuse.&lt;/li&gt;
&lt;li&gt;One that has been on pause, but will be resumed when COVID starts petering out: &lt;a href="https://soledrop.in"&gt;https://soledrop.in&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-few-loose-ends-to-wrap-up"&gt;A few loose ends to wrap up&lt;/h2&gt;
&lt;p&gt;I figured I should add a quick note about where I&amp;rsquo;ve been, where I am, and what&amp;rsquo;s on the horizon.&lt;/p&gt;
&lt;h3 id="past-locations"&gt;Past locations&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;d love to write something positive about each one of these places, but I&amp;rsquo;m afraid it&amp;rsquo;d be too difficult to wrack my brain for good things to say about Boulder, WY. It&amp;rsquo;s simply not possible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Salida, CO&lt;/li&gt;
&lt;li&gt;Grand Lake, CO&lt;/li&gt;
&lt;li&gt;Ten Sleep, WY&lt;/li&gt;
&lt;li&gt;Grand Teton Valley &amp;amp; Jackson, WY&lt;/li&gt;
&lt;li&gt;Boulder, WY&lt;/li&gt;
&lt;li&gt;Estes Park, CO&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="some-pictures"&gt;Some Pictures&lt;/h3&gt;
&lt;p&gt;The full rig in all her glory on national forest land (read: free) outside Jackson, WY.

&lt;input hidden="hidden" id="zoomCheck-17405" type="checkbox" /&gt;
&lt;label for="zoomCheck-17405"&gt;
  &lt;img alt="The full rig" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/jixwnq34Qg6DX3M/preview" title="The Full Rig" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;p&gt;Ran into Matt and Ali in the middle of nowhere Wyoming (a.k.a. Boulder)

&lt;input hidden="hidden" id="zoomCheck-b8c7c" type="checkbox" /&gt;
&lt;label for="zoomCheck-b8c7c"&gt;
  &lt;img alt="Matt and Ali" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/nzLyKwj6bpT5oHg/preview" title="matt and ali" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;p&gt;Kat Crushing as always in Ten Sleep

&lt;input hidden="hidden" id="zoomCheck-08af0" type="checkbox" /&gt;
&lt;label for="zoomCheck-08af0"&gt;
  &lt;img alt="Kat crush" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/NpgzXeGz2yJHLCr/preview" title="Kat crush" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;p&gt;Ten Sleep brewery lets you camp over night for $5, pretty sweet deal!

&lt;input hidden="hidden" id="zoomCheck-6922f" type="checkbox" /&gt;
&lt;label for="zoomCheck-6922f"&gt;
  &lt;img alt="Ten Sleep Brewery" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/r3ZLxedZnDxTGe9/preview" title="Ten Sleep Brewery" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;p&gt;From the summit of Cloud Peak in the Cloud Peak Wilderness, WY. A pretty great overnighter.

&lt;input hidden="hidden" id="zoomCheck-9cc6b" type="checkbox" /&gt;
&lt;label for="zoomCheck-9cc6b"&gt;
  &lt;img alt="Cloud Peak Summit" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/BQ7WpAY28CJqWGH/preview" title="Cloud peak summit" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;p&gt;Long hike days are always best with frans

&lt;input hidden="hidden" id="zoomCheck-b78fb" type="checkbox" /&gt;
&lt;label for="zoomCheck-b78fb"&gt;
  &lt;img alt="Cloud Peak Hike" class="zoomCheck" src="https://nextcloud.adriano.fyi/s/ET6CgdFBLMyQWGA/preview" title="cloud peak hike" /&gt;
&lt;/label&gt;
&lt;/p&gt;
&lt;h3 id="upcoming-locations"&gt;Upcoming locations&lt;/h3&gt;
&lt;p&gt;More of Estes! I love this place. And then off to Flagstaff, AZ and most likely Las Vegas for climbing. That&amp;rsquo;s all I&amp;rsquo;ve got for now.&lt;/p&gt;
&lt;p&gt;Cheers&lt;/p&gt;</description><author>Adriano Caloiaro's personal blog</author><pubDate>Wed, 26 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://adriano.fyi/posts/2020-08-26-roaming/</guid></item><item><title>Book Review: Technopoly</title><link>https://lambdaland.org/posts/2020-08-16-book-review-technopoly-v2/</link><description>&lt;!-- Introduction --&gt;
&lt;p&gt;In &lt;em&gt;Technopoly: The Surrender of Culture to Technology&lt;/em&gt;, Neil Postman argues that our infatuation with technology has insidiously eroded our culture. We gain much through technology, but it comes at a price; all too often we are blind to that price. This book seeks to call attention to the costs of a technology-focused society. I felt this poignantly because I, as a technology worker, know what that infatuation feels like.&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Wed, 26 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-08-16-book-review-technopoly-v2/</guid></item><item><title>First Look at AWS Amplify Flutter (Developer Preview)</title><link>https://www.swyx.io/amplify-flutter</link><description>AWS Amplify launched a Flutter Integration, so I thought I would record a quick video and blogpost</description><author>swyx's site RSS Feed</author><pubDate>Tue, 25 Aug 2020 21:25:14 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/amplify-flutter</guid></item><item><title>Smartphones destroying a generation? No, but...</title><link>https://stop.zona-m.net/2020/08/smartphones-destroying-a-generation-no-but.../</link><description>&lt;p&gt;Nothing new, really. But well said.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 25 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/smartphones-destroying-a-generation-no-but.../</guid></item><item><title>Build Systems, and Habits</title><link>https://zacs.site/blog/build-systems-and-habits.html</link><description>&lt;p&gt;If I like an article, I look into its author. Most good writers write well and often. This helps me find &lt;a href="https://zacs.site/blog/my-evening-reads.html"&gt;independent websites&lt;/a&gt;, like &lt;a href="https://www.benkuhn.net/"&gt;Ben Kuhn&amp;#8217;s&lt;/a&gt; blog. In his 2018 piece, &lt;a href="https://www.benkuhn.net/zero"&gt;&lt;em&gt;Stop Trying&lt;/em&gt;&lt;/a&gt;, Ben talks about steps he took to better his life: tracking time with RescueTime, and waking up with automatic lights. His productivity went up, and he gets out of bed on time now&amp;#160;&amp;#8212;&amp;#160;because these changes required &amp;#8220;literally zero maintenance&amp;#8221;. He tried to make productivity and wakefulness a habit, but did not succeed until he built systems around those two goals. From &lt;a href="https://www.benkuhn.net/zero"&gt;&lt;em&gt;Stop Trying&lt;/em&gt;&lt;/a&gt;: &lt;/p&gt;
                &lt;p&gt;&lt;a href="https://zacs.site/blog/build-systems-and-habits.html"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Tue, 25 Aug 2020 20:50:25 GMT</pubDate><guid isPermaLink="true">https://zacs.site/blog/build-systems-and-habits.html</guid></item><item><title>Understanding useState's initial value</title><link>https://maxrozen.com/how-to-use-react-usestate-hook-initial-value</link><description>If you're used to class components and setState, the useState Hook might be confusing at first. Let's learn more about it in this article.</description><author>Max Rozen</author><pubDate>Tue, 25 Aug 2020 11:42:05 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/how-to-use-react-usestate-hook-initial-value</guid></item><item><title>The Picture of Dorian Gray</title><link>https://apurva-shukla.me/bookshelf/the-picture-of-dorian-gray/</link><description>⭐ ⭐ ⭐ ⭐ ⭐ This novel had an immediate impact on me, and after reading through the introduction I was entranced by the themes in the book I…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Tue, 25 Aug 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/bookshelf/the-picture-of-dorian-gray/</guid></item><item><title>South African COVID-19 deaths in context</title><link>http://negfeedback.blogspot.com/2020/08/south-african-covid-19-deaths-in-context.html</link><description>&lt;p&gt;&amp;nbsp;I was curious this morning, so I spent some time digging for context to the numbers we're constantly seeing ticking up on our reports these days.&lt;/p&gt;&lt;p&gt;The following chart shows this context.&lt;/p&gt;&lt;p&gt;As always, it's hard to get recent statistics for South Africa. I started with the top 10 natural causes of death in South Africa from StatsSA [1]. I've used their attribution of the underlying causes&lt;sup&gt;†&lt;/sup&gt;, Table 4.16 on p58 and also show the lumped "All non-natural causes" from the same report. Although this document was published in 2020, it only goes up to 2017. Viewing COVID-19 deaths [2] in this light shows it is considerable, even though it is at the bottom of the list. Note that the COVID-19 figures don't distinguish between underlying or immediate cause and include significant interventions to mitigate their effects when compared to for example the Influenza and pneumonia figure in the chart.&lt;/p&gt;&lt;p&gt;Road fatalities are always quite worrying to me - I don't think the average South African is worried enough about them. I used the official Dept of Transport report for 2018 [3]. I find it interesting that these numbers are comparable.&lt;/p&gt;&lt;p&gt;I know that people in South Africa are particularly worried about the murder rate, so I added the Africa Check reported numbers for 2019 [4]. Murder occupies a sobering position in the chart.&lt;/p&gt;&lt;p&gt;Some additional notes are in order to establish more context.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;I haven't normalised by population, mainly because these numbers involve yet another dive into the data sets for South Africa.&lt;/li&gt;&lt;li&gt;The COVID-19 numbers are for a partial year, not for a whole year&lt;/li&gt;&lt;li&gt;The influenza and pneumonia numbers do not include any active measures like lockdown or mask wearing.&lt;/li&gt;&lt;li&gt;Many of these numbers are not directly comparable in terms of mechanism, and the number for murder for instance would be included in the "All non-natural causes" number if I were designing this correctly.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;My personal conclusion from this is that COVID-19 deaths are significant when compared to these other causes of death.&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;h2 style="text-align: left;"&gt;Sources&lt;/h2&gt;&lt;div&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;StatSA &lt;a href="http://www.statssa.gov.za/?page_id=1854&amp;amp;PPN=P0309.3&amp;amp;SCH=7914" target="_blank"&gt;P0309.3 - Mortality and causes of death in South Africa: Findings from death notification, 2017&lt;/a&gt; (Published March 2020)&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.worldometers.info/coronavirus/country/south-africa/"&gt;Worldometer corona tracker&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Dept of Transport &lt;a href="https://www.arrivealive.co.za/documents/State%20of%20Road%20Safety%20Report%202019.pdf"&gt;State of Road Safety Report: Calendar January - December 2018&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Africa Check &lt;a href="https://africacheck.org/factsheets/factsheet-south-africas-crime-statistics-for-2019-20/"&gt;FACTSHEET: South Africa's Crime Statistics for 2019/20&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 style="text-align: left;"&gt;Footnotes&lt;/h2&gt;&lt;/div&gt;&lt;div&gt;†&amp;nbsp;&lt;span style="font-family: Arial; font-style: italic; font-weight: 700;"&gt;Underlying cause of death&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: ArialMT;"&gt;(previously known as primary cause) is the disease or injury that initiated the sequence of events leading directly to death; or the circumstances of the accident or violence which produced the fatal injury. [1]&lt;/span&gt;&lt;/div&gt;</description><author>Negative Feedback</author><pubDate>Tue, 25 Aug 2020 09:30:45 GMT</pubDate><guid isPermaLink="true">http://negfeedback.blogspot.com/2020/08/south-african-covid-19-deaths-in-context.html</guid></item><item><title>Smarter Swift snippets</title><link>https://xenodium.com/smarter-snippets</link><description>&lt;p&gt;&lt;a href="https://twitter.com/safijari"&gt;Jari Safi&lt;/a&gt; published a wonderful Emacs video &lt;a href="https://youtu.be/xmBovJvQ3KU"&gt;demoing python yasnippets in action&lt;/a&gt;. The constructor snippet, automatically setting ivars, is just magical. I wanted it for Swift!&lt;/p&gt;
&lt;p&gt;I took a look at the &lt;a href="https://github.com/jorgenschaefer/elpy/blob/060a4eb78ec8eba9c8fe3466c40a414d84b3dc81/snippets/python-mode/__init__"&gt;[[init]{.underline}]{.underline} snippet&lt;/a&gt; from &lt;a href="https://github.com/jorgenschaefer"&gt;Jorgen Schäfer&lt;/a&gt;'s &lt;a href="https://github.com/jorgenschaefer/elpy"&gt;elpy&lt;/a&gt;. It uses &lt;a href="https://github.com/jorgenschaefer/elpy/blob/060a4eb78ec8eba9c8fe3466c40a414d84b3dc81/snippets/python-mode/.yas-setup.el#L33"&gt;elpy-snippet-init-assignments&lt;/a&gt; to generate the assignments.&lt;/p&gt;
&lt;p&gt;With small tweaks, we can get the same action going on for Swift ø/&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/smarter-snippets/snippet.gif" /&gt;&lt;/p&gt;
&lt;p&gt;init.yasnippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-snippet"&gt;# -*- mode: snippet -*-
# name: init with assignments
# key: init
# --
init(${1:, args}) {
  ${1:$(swift-snippet-init-assignments yas-text)}
}
$0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;.yas-setup.el:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(defun swift-snippet-init-assignments (arg-string)
  (let ((indentation (make-string (save-excursion
                                    (goto-char start-point)
                                    (current-indentation))
                                  ?\s)))
    (string-trim (mapconcat (lambda (arg)
                              (if (string-match &amp;quot;^\\*&amp;quot; arg)
                                  &amp;quot;&amp;quot;
                                (format &amp;quot;self.%s = %s\n%s&amp;quot;
                                        arg arg indentation)))
                            (swift-snippet-split-args arg-string)
                            &amp;quot;&amp;quot;))))

(defun swift-snippet-split-args (arg-string)
  (mapcar (lambda (x)
            (if (and x (string-match &amp;quot;\\([[:alnum:]]*\\):&amp;quot; x))
                (match-string-no-properties 1 x)
              x))
          (split-string arg-string &amp;quot;[[:blank:]]*,[[:blank:]]*&amp;quot; t)))
&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Tue, 25 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/smarter-snippets</guid></item><item><title>Always-Free Managed PostgreSQL Databases Reviewed</title><link>https://aknapen.nl/blog/always-free-managed-postgresql-databases/</link><description>Edit: This content in this post is already a couple of years stale. Heroku Postgres is not free anymore. However, in the mean time Fly.io now features Fly Postgres. It&amp;rsquo;s a bit more hands-on than many managed Postgres services. However, it does fit within your free-tier and does not oversell your shared database.
So, if you don&amp;rsquo;t mind getting your hands dirty, then it&amp;rsquo;s a very solid option.</description><author>Adriaan Knapen</author><pubDate>Tue, 25 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://aknapen.nl/blog/always-free-managed-postgresql-databases/</guid></item><item><title>Fuzzing in Go</title><link>https://lwn.net/Articles/829242/</link><description>An overview of fuzz testing and the go-fuzz tool, as well as a look at the recent draft design for including fuzz testing in the `go` tool (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Mon, 24 Aug 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/829242/</guid></item><item><title>On Work, Money and PURPOSE, Part 4</title><link>https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-4/</link><description>&lt;p&gt;What next, when ANY theory of &amp;ldquo;work&amp;rdquo; becomes less relevant and applicable every year?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 24 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-4/</guid></item><item><title>USB Car Audio in a Civic</title><link>https://purpleidea.com/blog/2020/08/11/usb-car-audio-in-a-civic/</link><description>&lt;p&gt;Transportation is very important to me. My whole life I&amp;rsquo;ve never owned a car. I
have gotten by with biking, public transit, and various car sharing services.
Sadly, biking is incredibly dangerous and stressful, because most cars don&amp;rsquo;t
respect bicycles, and in the winter it&amp;rsquo;s not very practical, the
&lt;a href="https://www.stm.info/en"&gt;STM&lt;/a&gt; (public transit) offers an incredibly unreliable
and unpleasant service, and &lt;a href="https://www.car2go.com/"&gt;Car2Go&lt;/a&gt; (car sharing) now
requires that you use their proprietary smart phone app (you used to be able to
just swipe the membership card) so I finally gave up and decided to buy a used
car.&lt;/p&gt;</description><author>The Technical Blog of James on purpleidea.com</author><pubDate>Mon, 24 Aug 2020 08:30:00 GMT</pubDate><guid isPermaLink="true">https://purpleidea.com/blog/2020/08/11/usb-car-audio-in-a-civic/</guid></item><item><title>Understanding Manual Retain Release in Objective-C</title><link>https://whackylabs.com/objc/2020/08/24/mrr-objc/</link><description>&lt;p&gt;You might often hear programmers claiming &lt;strong&gt;Automatic Reference Counting (ARC)&lt;/strong&gt; is one of the best things that happened to Objective-C. It relieves you, the programmer, from typing out redundant code. It’s a convenience if you’ve ever written any &lt;strong&gt;Manual Retain Release (MRR)&lt;/strong&gt; code. But if you joined the club later and haven’t actually every written any MRR code, you might get a wrong impression that MRR is verbosely spammed with calls to &lt;code class="language-plaintext highlighter-rouge"&gt;retain&lt;/code&gt; and &lt;code class="language-plaintext highlighter-rouge"&gt;release&lt;/code&gt;. One factor could be that people assume MRR code is equivalent to C style memory management, where you need to call &lt;code class="language-plaintext highlighter-rouge"&gt;malloc&lt;/code&gt; and &lt;code class="language-plaintext highlighter-rouge"&gt;free&lt;/code&gt; and then figure out complex ways to manage the ownership. Another factor could be because a lot of ARC vs MRR discussion overlook the fact that MRR already has reference counting, something equivalent of what was finally introduced in C++11 with smart pointers. Another confusion might have to do with the fact that ARC is not really clear on memory ownership rules. So some people might assume every assignment operation is either a transfer of ownership or claiming ownership, which isn’t entirely false, but not in the sense of how &lt;code class="language-plaintext highlighter-rouge"&gt;retain&lt;/code&gt; and &lt;code class="language-plaintext highlighter-rouge"&gt;release&lt;/code&gt; is designed to work.&lt;/p&gt;

&lt;p&gt;I think every new Objective-C programmer should at least write some MRR code to understand what are the redundancies that ARC is trying to get rid of. Also if you look beyond ARC, you might realize the clear pattern of memory ownership, which honestly isn’t that complicated. The data isn’t randomly allocated or randomly transferred from an instance to another. There’s a very clear pattern of when that happens and MRR highlights them clearly.&lt;/p&gt;

&lt;p&gt;In real life, a well architected code has a clean vision of memory ownership. There’s a concept of object graph which should ideally be an acyclic directed graph with clear parent child relationships. When, a parent claims the ownership then any reference to the data passed to the children can almost always assume that the data won’t get deallocated out of nowhere, since parent should always outlive the children. In all of these cases there’s no transfer of ownership, so all those reference could be a &lt;code class="language-plaintext highlighter-rouge"&gt;weak&lt;/code&gt; reference. In other cases where there’s a temporary factory class involved who’s only job is to allocated the data, the ownership has to be transferred at some point.&lt;/p&gt;

&lt;p&gt;Then there is the amazing idea of autorelease pool, where the ownership of data is temporary transferred to the run loop, for data that can be disposed at the end of the run loop cycle or should be claimed by somebody before the end of the loop cycle.&lt;/p&gt;

&lt;p&gt;And finally there are rules around transfer of ownership when working with an external library.&lt;/p&gt;

&lt;p&gt;In almost all cases there are only a finite set of scenarios possible:&lt;/p&gt;

&lt;h2 id="1-transfer-of-ownership-from-client-to-library"&gt;1. Transfer of ownership from client to library&lt;/h2&gt;

&lt;p&gt;In library calls, it might happen quite often that the library is designed such that it delegates the responsibility of memory allocation to the client and then transfer the ownership back to library. An example is &lt;code class="language-plaintext highlighter-rouge"&gt;NSArray&lt;/code&gt;&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;Foo&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;Foo&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="nf"&gt;addObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// transfer of ownership&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id="2-transfer-of-ownership-from-library-to-client"&gt;2. Transfer of ownership from library to client&lt;/h2&gt;

&lt;p&gt;In other scenarios the library might transfer the ownership to the client. Most of the class factory methods that wrap initializer with &lt;code class="language-plaintext highlighter-rouge"&gt;autorelease&lt;/code&gt; do this&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;

&lt;span class="k"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;personWithName&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[[[&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;alloc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;initWithName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;autorelease&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// transfer ownership to autorelease pool&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;initWithName&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;NSString&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which is a way to say that for the time being the ownership has been transferred to the autorelease pool. Now it’s up to the client on how they wish to manage the memory. And depending on the usage, the clients can call &lt;code class="language-plaintext highlighter-rouge"&gt;[person retain]&lt;/code&gt; to claim the ownership otherwise the data would be deallocated at the end of the run loop cycle.&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tmpPerson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;personWithName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;@"John"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;_person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="nf"&gt;personWithName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;@"John"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nf"&gt;retain&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// transfer of ownership&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id="3-dealing-with-asynchronous-callbacks"&gt;3. Dealing with asynchronous callbacks&lt;/h2&gt;

&lt;p&gt;In cases where an asynchronous calls are being made, there’s a chance that caller might get disposed by the time the callback happens. These scenarios have to be carefully designed for. Again, there’s no magic trick here, just make sure the listener object lives long enough to handle the callback.&lt;/p&gt;

&lt;h2 id="4-multiple-owners-of-the-data"&gt;4. Multiple owners of the data&lt;/h2&gt;

&lt;p&gt;Another situation is when multiple instanced deliberately want to acquire ownership of the same data. For example say multiple children want to work with same image data and the parent doesn’t want to claim ownership of the image data. In these scenarios, we can rely on the reference counting and every child can claim ownership. Later when the last child relinquishes the ownership the shared data would get deallocated.&lt;/p&gt;

&lt;div class="language-objc highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="k"&gt;@implementation&lt;/span&gt; &lt;span class="nc"&gt;Child&lt;/span&gt;

&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instancetype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;initWithImage&lt;/span&gt;&lt;span class="p"&gt;:(&lt;/span&gt;&lt;span class="n"&gt;UIImage&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nv"&gt;image&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="nf"&gt;retain&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;dealloc&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_image&lt;/span&gt; &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="nf"&gt;dealloc&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once you understand these basic rules and the complexities around them, you might think for yourself if you like ARC or not. Maybe you don’t like the magical aspect of ARC, or you don’t like how ARC interacts with plain C &lt;code class="language-plaintext highlighter-rouge"&gt;struct&lt;/code&gt; types which also relates to how ARC interacts with &lt;strong&gt;CoreFoundation&lt;/strong&gt;. Also since ARC can be enabled and disabled per file basis, one might have it enabled for parts of code that are simpler and disabled for complex ones.&lt;/p&gt;

&lt;h2 id="further-reading"&gt;Further reading&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html#//apple_ref/doc/uid/10000011-SW1"&gt;Advanced Memory Management Programming Guide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/CFMemoryMgmt.html#//apple_ref/doc/uid/10000127i"&gt;Memory Management Programming Guide for Core Foundation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://developer.apple.com/library/archive/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226"&gt;Transitioning to ARC Release Notes&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description><author>Whacky Labs</author><pubDate>Mon, 24 Aug 2020 08:00:00 GMT</pubDate><guid isPermaLink="true">https://whackylabs.com/objc/2020/08/24/mrr-objc/</guid></item><item><title>The Making of a Manager, a short review</title><link>https://faingezicht.com/articles/2020/08/24/making-a-manager/</link><description>&lt;small&gt;&lt;em&gt;Este ensayo también está disponible &lt;a href="/articles/2020/08/24/making-a-manager-es/"&gt;en español&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;

A few months ago, as the prospect of replacing my individual contributor (IC) hat with that of an engineering manager started to become real, I did what anyone who knows me would expect me to do: I dug up management books from my to-read list, and asked friends for recommendations of what to read first. Opinions varied, but Julie Zhuo's _The Making of a Manager_ kept popping up as a practical one to start with. Unlike most other books I was considering, Zhuo's was praised for aiming her suggestions at first-time managers, instead of addressing high level executives and experienced managers. Further, I knew Zhuo would bring the perspective of a young leader in a Silicon Valley software company, not an old school industrial blue chip. It seemed aligned with what I was looking for in a management book, so after hearing about it from several people, I followed their advice and picked it up.

Individuals can build amazing things on our own, but we can be more ambitious and can achieve more when working in teams. Things happen because people make them happen, but most remarkable things happen because we build on top of each other's work in creative ways. In Zhuo's view, this is the crux of management. A manager's job is to get better outcomes for a given set of resources. By finding and removing bottlenecks, greasing wheels, and acting as a part-time therapist, a manager can get ICs working more efficiently, together.

Throughout the book, Zhuo discusses routine day to day aspects of management: running meetings, setting roadmaps, giving actionable feedback, growing the team, etc. Ultimately, most of the topics she brings up tie back to the same challenge: People. Running a team is hard because people are complex. At times we don't understand ourselves, and even when we do we might not understand how the roles we fill fit in a broader context. Managing a team is about building a shared vision that serves both individual and common goals. A good manager strives for alignment across time-scales (What needs to happen by next week? How about by the end of the year?) and across subjects (What is the organizational goal? What are each individual's career goals? How does a given project fit in that context?). A good manager defines processes to gather knowledge from their team, and makes decisions based on that information, pulling levers to line up goals as much as possible. A well-managed team has a deep understanding of what success looks like, and how each of its members' personal stories fits in the broader organization's objectives.

A manager's day to day small decisions add up to a bigger whole, setting the team's expectations and shaping individual experiences of the company and its culture. _The Making of a Manager_ is packed with specific questions managers should ask and actions they should take when common problems arise. It provides a useful lens to evaluate and course correct one's decisions as a manager. Zhuo does a good job of guiding new managers to improve on awkward 1-1 conversations, and to avoid aimless meetings, for example. Beyond that, she demonstrates how one can translate feedback into solid actionable next steps, and showcases how a manager's role can be multiplicative instead of additive, helping the team deliver on it's commitments.

While at times the tone felt fluffy, and many of the examples too cherry-picked, the underlying ideas presented by Zhuo are valuable. Her approach to management is not revolutionary, but the book serves as a pragmatic guide for someone transitioning from the IC track to the M path. As I embark on the management adventure, I'll try to take her advice and have a growth mindset, keeping an eye out for coordination problems, and focusing on what matters most - the people I'll be working with.

--

PS, for context, after years working on analytics and data engineering problems in Siri Search, I’m now leading a broader effort as the Engineering Manager of the Siri Metrics Platform team at Apple. If this sounds interesting, and you want to learn more, please &lt;a href="/contact"&gt;reach out&lt;/a&gt;. Yes, we're hiring.

&lt;hr /&gt;

&lt;small&gt;&lt;em&gt;Photo: Financial District, San Francisco, California, by me. Previously posted on &lt;a href="/photos/2018/03/30/cityscapes/"&gt;SF Cityscapes&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;</description><author>Avy Faingezicht</author><pubDate>Mon, 24 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/articles/2020/08/24/making-a-manager/</guid></item><item><title>The X in MDX</title><link>https://egghead.io/lessons/mdx-the-x-in-mdx</link><description>— at MDX Conf 2020</description><author>Rodrigo Pombo</author><pubDate>Mon, 24 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://egghead.io/lessons/mdx-the-x-in-mdx</guid></item><item><title>Minimal code editor in JavaScript</title><link>https://zserge.com/posts/js-editor/</link><description>How would one write a code editor in JavaScript? A long time ago one would take a regular textarea to handle user input and would create another div that would do syntax highlighting etc. However, this approach quickly becomes unusable when someone opens it on mobile. That&amp;rsquo;s why CodeMirror has been rewritten to use contenteditable and many other editors followed this approach.
contenteditable Contenteditable, as the name suggests, allows users to edit the contents of the element using the browser-native techniques - all shortcuts for text selection and navigation work as expected, so does the clipboard and other minor editing features.</description><author>zserge's blog</author><pubDate>Mon, 24 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/js-editor/</guid></item><item><title>ATS Resiliency</title><link>/ats-resiliency/</link><description>&lt;p&gt;As with all modern enterprise SaaS platforms, Koru has a mechanism to send data about a candidates results back to a clients ATS (Application Tracking system) or CRM (Customer Relationship Management) system. Since Koru was event driven and the traffic is not consistent, the decision (which pre-dates myself) was made to make these &amp;quot;ATS Integrations&amp;quot; lambda's triggered from DynamoDB.&lt;/p&gt;
&lt;p&gt;So the set up is this, when a candidate completes an assessment on our platform, it goes through all the pipes and tubes, passed Gerald the field mouse that generates the scores and then finally back into our API when the completion of the scoring is recorded. Now we want to get this completed candidate data to our clients system, so our API creates a new record in the DynamoDB table for that client's ATS with all the information it needs. This then triggers the lambda that sends the data to the ATS of choice. Sounds easy right?&lt;/p&gt;
&lt;p&gt;I thought as much, but found there were a number of holes that the original developers fell into when developing this software that caused huge resiliency issues. I thought I would share my findings to all those trying to do the very common task of &amp;quot;submit data via HTTP to a 3rd party&amp;quot;. In our case, the third party API is the Cappfinity external scoring mechanism which is built by another team at the company which allowed us to work closely with them. However, most fixes were addressed on the Koru side.&lt;/p&gt;
&lt;h3&gt;1. Lambda was suffering from &amp;quot;socket exhaustion&amp;quot;&lt;/h3&gt;
&lt;p&gt;This was the biggest problem we had &amp;quot;socket exhaustion&amp;quot;. I hadn't stumbled across the term apart from a joke I'd seen on IRC, so it took me a while to discover what the problem actually was and why it was happening in our system.
What we observed was that the Lambda function would fire a request for each record that we hadn't marked as &amp;quot;processed&amp;quot; in our system (It is considered &amp;quot;processed&amp;quot; when we get a 200 response from the 3rd Party API). Often this could just be one request, which would succeed. But sometimes, if records had failed over time, then we would build up this backlog of pending records to be sent to the third party. In these cases, the first few would succeed but quickly we'd get the error &amp;quot;ETIMEDOUT&amp;quot; or &amp;quot;ESOCKETTIMEDOUT&amp;quot;.&lt;/p&gt;
&lt;p&gt;A quick google of these errors lead me to discover that Node goes to look up the DNS the URL for each request it makes. After this, it makes the request to the URL you've specified. Often if you have multiple requests trying to process in parallel, and the DNS lookup for a few of them takes a bit too long then the program can't keep up with trying to issue new sockets to make requests on. Uber talks more about why it occurs over &lt;a href="https://eng.uber.com/denial-by-dns/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So we knew the the problem was that it was trying to process too many requests in parallel. To the code!
Immediately, I spotted the problem.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;return new Promise((resolve) =&amp;gt; {
  Promise.all(
    records.map(async (record) =&amp;gt; {
      const payload = buildPayload(record);
      try {
        const response = await processPayload(payload);
      } catch (e) {
        await markRecordAsFailed(record);
      }
      return Promise.resolve(payload);
    })
  ).then((result) =&amp;gt; resolve(result));
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See the problem? Well there are a couple...&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;processPayload&lt;/code&gt; is an async function but an &lt;code&gt;Array.map&lt;/code&gt; with an async callback will appear as valid javascript but will in fact not truly &lt;code&gt;await&lt;/code&gt; functions contained within it&lt;/li&gt;
&lt;li&gt;Because of not being awaited successfully, the array will quickly loop through and call the &lt;code&gt;processPayload&lt;/code&gt; but not listen for the result and therefore max out the sockets&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It's worth noting that this code was used in production for many months before we got these kinds of issues, in response to increased load.&lt;/p&gt;
&lt;p&gt;What was the solution here? It turns out to be fairly simple, rewrite it as a regular &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;for (let i = 0; i &amp;lt; records.length; i += 1) {
  const payload = buildPayload(records[i]);
  try {
    const response = await processPayload(payload);
  } catch (e) {
    await markRecordAsFailed(records[i]);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above means that we submit a request to send the data to the 3rd party one at a time.&lt;/p&gt;
&lt;h3&gt;2. The 3rd party was getting overwhelmed with requests&lt;/h3&gt;
&lt;p&gt;After we deployed the code above, we now found that the 3rd Party API was getting hammered with the amount of requests we had to process (even though they were one at a time). Although this sort of seems like &amp;quot;not my problem&amp;quot;, I chose to issue a fix for this.
The solution was to simply limit the number of requests that we sent too 100 per &amp;quot;run&amp;quot; of the lambda (i.e., we would only process a maximum of 100 records each time the lambda got triggered which was for all DynamoDB inserts into the table)&lt;/p&gt;
&lt;h3&gt;3. Use Https agent with a pool&lt;/h3&gt;
&lt;p&gt;We added a further fix to the problem above by creating our own Https Agent and passing that into the &lt;code&gt;request-promise&lt;/code&gt; libraries options.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;const agent = new https.Agent({ maxSockets: 25, keepAlive: true });
await request({
  options: {},
  agent: agent, // use the global agent
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This meant that we would share the agent across all requests that were made from the program rather than creating a new one per request. This again prevented socket timeout issues as well as slowing the rate that we sent requests to the API.&lt;/p&gt;
&lt;h3&gt;4. Cache JWT tokens (or any other authentication tokens you are using for the life time of the request)&lt;/h3&gt;
&lt;p&gt;A few months after we deployed the service, the Cappfinity team called us up to say that we had maxed out their M2M Auth0 Tokens. Oops.
When digging into the code, I found that the token was not only generated each time we processed records, but for each individual record itself. Double Oops.
I was hesitant to cache JWT token's because it just feels a bit wrong and has the potential to become invalid in the case of rotated secrets and so forth, but we went ahead with it anyway. We cached the token by storing it in another DynamoDB table - the mix of cheap storage combined with quick and easy access was hard to compete with. In the program, each time it boots, we check the table for a token. We then check if that token is valid. If it is then we can proceed as normal. Alternatively, if it's not valid then we can regenerate it, and update it in the table.&lt;/p&gt;
&lt;h3&gt;5. Don't submit data to the 3rd party when it is down&lt;/h3&gt;
&lt;p&gt;Systems go down, that's a fact. Or maybe a deployment breaks everything. Either way, we should have some mechanism so that if we mark a candidate records as failed to be processed, then we can be sure this is a data issue rather than an issue with any part of the underlying system. There are many ways to do this, but without working too heavily with the third-party API, we were able to implement a basic sanity check. I asked if they had a health check mechanism, which they did. I asked to look at the code and this is what I saw (roughly)&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;const router = express.Router();
router.all(&amp;quot;/health&amp;quot;, (req, res, next) =&amp;gt; {
  return res.send(200);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yup, that's it! I'll dive into how to build great health check mechanisms in another post, but suffice to say, this doesn't give an accurate representation of a systems health. Nonetheless, we implemented a system that would first ping the health check system to see if we got a good response back. We created tickets to get this health check improved so that we can have more confidence in this check going forward but this is a good first start. Additionally, this basic check would have saved us in the case of an outage the Cappfinity API had for 2 days. In that time, Koru was firing requests at the Cappfinity API, getting no response and failing them accordingly. This is correct behaviour but was such a headache to get them to submit again when the API was backup so this health check will prevent those sorts of situations.&lt;/p&gt;
&lt;h3&gt;6. Filtered out DynamoDB update, delete and modify triggers to reduce retries&lt;/h3&gt;
&lt;p&gt;I said earlier that the Lambda was triggered for DynamoDB inserts, but as of August 2020, there is no way within AWS itself to be this specific. So how did we do it and why?
We implemented this by looking at the &lt;code&gt;eventName&lt;/code&gt; property on the &lt;code&gt;event&lt;/code&gt; that is passed as the first argument to the Lambda function. This event name property, for DynamoDB events, signifies what type of event it was. When a record is updated, it's &lt;code&gt;MODIFY&lt;/code&gt;, when a record is deleted it's &lt;code&gt;DELETE&lt;/code&gt; and so on. The one we are interested in is &lt;code&gt;INSERT&lt;/code&gt;, which occurs, logically, when a record is inserted.
It was then a matter of checking the first records &lt;code&gt;eventName&lt;/code&gt; like this&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;const triggerType = event.Records[0].eventName;
const acceptedTriggers = [&amp;quot;INSERT&amp;quot;];
if (!acceptTypes.includes(triggerType)) {
  return {
    message: &amp;quot;Invalid trigger for this lambda&amp;quot;,
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But why did we do this?&lt;/p&gt;
&lt;p&gt;What was happening was that as part of our system, we update the dynamo table to indicate how many &amp;quot;retries&amp;quot; a record has attempted or if it's been processed or not. This updating meant that each time we processed a record it also triggered the lambda, so it just spun in a circle continuing to retry, over and over again. Pretty hilarious really.
By cutting down the lambda to trigger only on inserts, we not only saved money, but also made it more efficient. Additionally, we only wanted the lambda to trigger for new records and retry old ones and this bit of code achieved that purpose.&lt;/p&gt;
&lt;h3&gt;7. Special error cases&lt;/h3&gt;
&lt;p&gt;We worked with the Cappfinity team closely on this one. We found that in some cases, somehow, records were in the database ready to submit back to the ATS, that shouldn't have been there. These were the cases we were trying to handle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Straight up invalid records&lt;/li&gt;
&lt;li&gt;The candidate hadn't actually completed the assessment&lt;/li&gt;
&lt;li&gt;We had already sent data but had not marked it as processed in our system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To solve this problem, we needed to introduce some new status codes so that we could categorize the errors we got back. Previously, if we sent an invalid request of any kind, it would return a 500 error to us. This categorization of errors meant we could handle each one uniquely. For complete invalid records, this meant just deleting them. Whilst for duplicate submissions, we marked them as &amp;quot;processed&amp;quot;.&lt;/p&gt;
&lt;p&gt;After we deployed this change, we let it chew through a huge backlog of records that were marked as unprocessed and soon we were down to 0 records marked as &amp;quot;unprocessed&amp;quot;. Great success!&lt;/p&gt;
&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;I'm really happy with how solid and robust the system is now. There are still improvements that could be made but that's the way with all things. I hope to have this system taken off my list of &amp;quot;most modified&amp;quot; into a pile of systems that &amp;quot;just work&amp;quot;(tm). None of these techniques are new, but the key is to take the time to identify first why things happen. This system resiliency work too me to places that felt out my comfort zone and put under the microscope the gaps in my knowledge - namely, how NodeJS actually works under the hood so to speak and networking principles. I've since taken a couple of courses and watched a number of conference talks on these very topics.&lt;/p&gt;
&lt;p&gt;Takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use your work to identify gaps in your knowledge&lt;/li&gt;
&lt;li&gt;Don't assume - look for the why's and measure to test the hypothesis&lt;/li&gt;
&lt;/ul&gt;</description><author/><pubDate>Mon, 24 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/ats-resiliency/</guid></item><item><title>Computer Architecture Takeaways</title><link>https://venam.net/blog/programming/2020/08/24/computer-architecture.html</link><description>Computer architecture can be considered a boring topic, one that is studied during CS education, then put aside, and leaves place to the shiny new toys that capture the attention.  I've recently revisited it, and I'd like to summarize some takeaways.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Mon, 24 Aug 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/programming/2020/08/24/computer-architecture.html</guid></item><item><title>Home</title><link>https://www.unsungnovelty.org/home/</link><description/><author>unsungNovelty</author><pubDate>Sun, 23 Aug 2020 16:32:55 GMT</pubDate><guid isPermaLink="true">https://www.unsungnovelty.org/home/</guid></item><item><title>Swift package manager build for iOS</title><link>https://xenodium.com/swift-package-manager-build-for-ios</link><description>&lt;p&gt;While playing around with Swift package manager, it wasn't immediately obvious how to build for iOS from the command line. The default behaviour of invoking &lt;em&gt;swift build&lt;/em&gt; is to build for the host. In my case, macOS. In any case, this was it:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;swift build -Xswiftc &amp;quot;-sdk&amp;quot; -Xswiftc &amp;quot;/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk&amp;quot; -Xswiftc &amp;quot;-target&amp;quot; -Xswiftc &amp;quot;x86_64-apple-ios13.0-simulator&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ps. Can get the SDK path with:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;xcrun --sdk iphonesimulator --show-sdk-path
&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 23 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/swift-package-manager-build-for-ios</guid></item><item><title>QR code bookmarks</title><link>https://xenodium.com/qr-code-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/divan/txqr"&gt;divan/txqr: Transfer data via animated QR codes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://research.swtch.com/qart"&gt;research!rsc: QArt Codes&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=24158125"&gt;Show HN: Photo Realistic QR-Codes (Hacker News)&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 23 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/qr-code-bookmarks</guid></item><item><title>Book: Less is More by Jason Hickel</title><link>https://nutcroft.mataroa.blog/blog/book-less-is-more-by-jason-hickel/</link><description>&lt;p&gt;&lt;a href="https://www.jasonhickel.org/less-is-more"&gt;Less is More: How Degrowth Will Save the World&lt;/a&gt;. A new book by Jason Hickel.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“We are not the defenders of the river. We are the river.”&lt;br /&gt;
– Fisherman, Magdalena River, Colombia&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Core idea of capitalism is: one not only has to always profit but also do it in an accelerating way. When one does not grow enough, it's an economic crisis. The movement of degrowth raises the arguments against this &lt;a href="https://en.wikipedia.org/wiki/Imaginary_(sociology)"&gt;social imaginary&lt;/a&gt;. Always growing is irrational, with no basis, but more importantly it is fatally dangerous. Earth is a balanced system; humanity is one of the cogs and by massively exploiting the Earth's resources the balance is no more and the system collapses.&lt;/p&gt;
&lt;p&gt;Degrowth is about scaling down world production, as it's the only way to prevent the aforementioned environmental collapse. There are several pathways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;End planned obsolescence. The lightbulb's life is the most famous example.&lt;/li&gt;
&lt;li&gt;Advertising. Manipulating people to make irrational purchases does increase the GDP yet it doesn't improve our well-being.&lt;/li&gt;
&lt;li&gt;Usership. Not every house needs a lawn mower every day.&lt;/li&gt;
&lt;li&gt;End food waste. 30%-50% of all the food that's being produced is wasted.&lt;/li&gt;
&lt;li&gt;Scale down eco-destructive industries. E.g. fossil fuel and beef.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Undoubtedly, these pathways require massive economic and social restructuring. Countless problems, expected and unexpected, will arise. The author provides answers and solutions to many, yet, of course it could never be enough. Alas, it seems it's the only way to mitigate the sixth extinction.&lt;/p&gt;
&lt;p&gt;Looking back millions of years into the Earth system’s history there have been five mass extinction events. It looks like the &lt;a href="https://en.wikipedia.org/wiki/Holocene_extinction"&gt;sixth&lt;/a&gt; one has began.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Recent figures show that around 85% of global fish stocks are now depleted or facing collapse. Haddock have fallen to 1% of their former volume; halibut, those magnificent giants of the sea, to one-fifth of 1%. Fish catches are beginning to decline around the world, for the first time in recorded history. In the Asia-Pacific, fishery yields are on track to hit zero by 2048.  &lt;/p&gt;
&lt;p&gt;Most of this is due to aggressive overfishing: just as with agriculture, corporations have turned fishing into an act of warfare, using industrial megatrawlers to scrape the seafloor in their hunt for increasingly scarce fish, hauling up hundreds of species in order to catch the few that have ‘market value’, turning coral gardens and colourful ecosystems into lifeless plains in the process. Whole ocean landscapes have been decimated in the scramble for profit.”  &lt;/p&gt;
&lt;p&gt;– Excerpt from “Less is More” by Jason Hickel, Chapter: &lt;em&gt;Welcome to the Anthropocene&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The book begins with a very succinct state of affairs on the Earth system. Hopelessness overtakes one's mind as the amount of suffering and death humanity has caused during the last 500 years is immeasurable. In exchange for what? Inequality in survival potential—caused by the few at the top. But, Jason's &lt;a href="https://www.jasonhickel.org/the-divide"&gt;other book&lt;/a&gt; is a much more complete case for this argument.&lt;/p&gt;
&lt;p&gt;When a constituent of a system does not play its role then the system’s collapse is inevitable. This is what happened a few thousand years ago, during the &lt;a href="https://en.wikipedia.org/wiki/Austronesian_peoples#Austronesian_expansion"&gt;Austronesian expansion&lt;/a&gt;, when humans left mainland Asia and settled in the islands of south-east Pacific Ocean. Being accustomed to the huge ecosystem of mainland Asia, they didn’t consider that those small islands have a much more delicate life balance. Their rate of tree cutting and animal hunting were unsustainable, which lead to whole islands collapsing and being abandoned. However, the settlers learned from their mistakes. They understood how the ecosystem worked and did, subsequently, achieve a balance that allowed all organisms of the ecosystem to live.&lt;/p&gt;
&lt;p&gt;This is the challenge we are facing, only this time on a planet level rather than on a small island. Odds are against us. It will require global collaboration in an unprecedented level. It's one of the greatest collective challenges of all time. If one is looking for something to work on, this is a considerably attractive choice.&lt;/p&gt;
&lt;p&gt;The author says this is a book about hope. It’s difficult to apprehend that, especially in the beginning of the book. As it progresses, potential solutions are offered but their application and success do not seem likely. &lt;/p&gt;
&lt;p&gt;In the end, after having the whole picture together, one can finally understand. True optimism is not blind optimism. And true hope is not one without knowing the bleakness of reality. One has to know; and still venture into this high-stakes undertaking—not because they fear death, but because they are excited about life. &lt;em&gt;This&lt;/em&gt; is why this book is about hope.&lt;/p&gt;</description><author>nutcroft</author><pubDate>Sun, 23 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/book-less-is-more-by-jason-hickel/</guid></item><item><title>Seastar's temporary buffer</title><link>https://makedist.com/posts/2020/08/23/seastars-temporary-buffer/</link><description>A staple utility for memory management in Seastar.</description><author>Noah Watkins</author><pubDate>Sun, 23 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://makedist.com/posts/2020/08/23/seastars-temporary-buffer/</guid></item><item><title>Effective Data Visualization Part 2: Formatting numbers</title><link>https://bytepawn.com/effective-data-visualization-part-2-formatting-numbers.html</link><description>&lt;p&gt;Format numbers for human consumption. What is more readable, &lt;code&gt;1.539e+5&lt;/code&gt; or &lt;code&gt;153,859&lt;/code&gt;? Showing numbers effectively on spreadsheets, charts, dashboards, reports is a basic ingredient for readability, like formatting code in programming. &lt;br /&gt;&lt;br /&gt; &lt;img src="/images/d3format.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sun, 23 Aug 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/effective-data-visualization-part-2-formatting-numbers.html</guid></item><item><title>Stupid project ideas: the War Machine</title><link>https://ounapuu.ee/posts/2020/08/22/stupid-project-ideas-1/</link><description>Maybe not stupid, but definitely stupid expensive.</description><author>./techtipsy</author><pubDate>Sat, 22 Aug 2020 21:24:08 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/08/22/stupid-project-ideas-1/</guid></item><item><title>What Producerism gets surely wrong</title><link>https://stop.zona-m.net/2020/08/what-producerism-gets-surely-wrong/</link><description>&lt;p&gt;Go back to analog tech? WHY?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 22 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/what-producerism-gets-surely-wrong/</guid></item><item><title>superimposed hexagonal grids</title><link>https://qubyte.codes/blog/superimposed-hexagonal-grids</link><description>&lt;p&gt;Based on the &lt;a href="/blog/superimposed-triangular-grids"&gt;last experiment&lt;/a&gt;, this one uses hexagonal grids rather than
triangular ones. The way the SVG is constructed isn't pretty (a mish-mash of
paths) but it gets the job done. I've given the two grids red and blue lines
and a black background to make the moiré pattern stand out.&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Sat, 22 Aug 2020 16:30:00 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/blog/superimposed-hexagonal-grids</guid></item><item><title>Disk is OK</title><link>https://ounapuu.ee/posts/2020/08/22/disk-is-ok/</link><description>It's all good, man.</description><author>./techtipsy</author><pubDate>Sat, 22 Aug 2020 07:29:19 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/08/22/disk-is-ok/</guid></item><item><title>Engagement</title><link>https://ben.bolte.cc/posts/2020-08-22-engagement</link><description>I got engaged to a really wonderful girl.</description><author>Ben Bolte</author><pubDate>Sat, 22 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ben.bolte.cc/posts/2020-08-22-engagement</guid></item><item><title>Hello World!</title><link>https://www.chriswales.uk/blog/hello-world</link><description>Hello, and welcome to my new website. I've been working on this for the last few days in my spare time and I'm happy to finally put it out…</description><author>Christopher Wales' Blog</author><pubDate>Sat, 22 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.chriswales.uk/blog/hello-world</guid></item><item><title>Effective Data Visualization Part 1: Categorical data</title><link>https://bytepawn.com/effective-data-visualization-part-1-categorical-data.html</link><description>&lt;p&gt;Making clear, readable charts is part of the craftmanship minimum for any data related role. In part one, I look at how to present categorical data. &lt;br /&gt;&lt;br /&gt; &lt;img alt="A pie chart" src="/images/pie_chart1.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Sat, 22 Aug 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/effective-data-visualization-part-1-categorical-data.html</guid></item><item><title>Staying Focused with a Simple Method</title><link>https://zenhabits.net/simple-focus/</link><description>&lt;p&gt;Leo Babauta, in &lt;a href="https://zenhabits.net/simple-focus/"&gt;&lt;em&gt;Staying Focused with a Simple Method&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;When you notice yourself avoiding something hard or uncertain ... the method is to turn towards it. Turn towards what you’re avoiding. Open to the discomfort, embrace it as training and growth. Bring curiosity. Do it even when you don’t feel like it. This is the training. The simple method makes it easier. Take it on, and see what happens.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As &lt;a href="https://zacs.site/blog/showing-up.html"&gt;I have said before&lt;/a&gt;, and will keep on saying, there is no shortcut, life hack, or trick; grind.&lt;/p&gt;


                &lt;p&gt;&lt;a href="https://zenhabits.net/simple-focus/"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Fri, 21 Aug 2020 23:59:36 GMT</pubDate><guid isPermaLink="true">https://zenhabits.net/simple-focus/</guid></item><item><title>The WRONG way to mix self driving cars and city planning</title><link>https://stop.zona-m.net/2020/08/the-wrong-way-to-mix-self-driving-cars-and-city-planning/</link><description>&lt;p&gt;What comes first? Cities that exist, or cars that don&amp;rsquo;t, and maybe shouldn&amp;rsquo;t?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 21 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/the-wrong-way-to-mix-self-driving-cars-and-city-planning/</guid></item><item><title>superimposed triangular grids</title><link>https://qubyte.codes/blog/superimposed-triangular-grids</link><description>&lt;p&gt;This experiment was inspired by field of &lt;a href="https://en.wikipedia.org/wiki/Twistronics"&gt;&lt;em&gt;twistronics&lt;/em&gt;&lt;/a&gt;, the study
of the intersesting properties of misaligned graphene sheets. The misalignment
produces a &lt;a href="https://en.wikipedia.org/wiki/Moir%C3%A9_pattern"&gt;moiré pattern&lt;/a&gt; which echoes the underlying structure. I'm too
lazy to do hexagonal grids in an afternoon of tinkering so I used triangular
grids instead.&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Fri, 21 Aug 2020 19:30:00 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/blog/superimposed-triangular-grids</guid></item><item><title>Cheatsheet for moving from Master to Main</title><link>https://www.swyx.io/master_to_main</link><description>Notes I have collected on how to renaming the Git default/primary branch</description><author>swyx's site RSS Feed</author><pubDate>Fri, 21 Aug 2020 06:04:51 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/master_to_main</guid></item><item><title>Writing a SIGGRAPH paper (for fun)</title><link>https://mattkeeter.com/projects/siggraph</link><description>Behind the scenes of a research paper</description><author>Matt Keeter</author><pubDate>Fri, 21 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://mattkeeter.com/projects/siggraph</guid></item><item><title>Prod++[3]: Leaner Search Using DuckDuckGo !Bangs</title><link>https://aknapen.nl/blog/prod-plus-plus-3-duckduckgo-bashes/</link><description>In this mini-series I will walk you through some habits I replaced in recent times, which have shown to pay off and make me a more productive programmer/power-user of my computer. All these changes should be easy to gradually adopt, so I would highly recommend checking them out. If you’ve any suggestions ☝️ or improvements ✍️, then email me at hi@aknapen.nl or reach out using any of the social media listed here.</description><author>Adriaan Knapen</author><pubDate>Fri, 21 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://aknapen.nl/blog/prod-plus-plus-3-duckduckgo-bashes/</guid></item><item><title>Multi-armed bandits and false positives</title><link>https://bytepawn.com/multi-armed-bandits-and-false-positives.html</link><description>&lt;p&gt;I use Monte Carlo simulations to explore the false positive rate of Multi-armed bandits.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Epsilon-greedy" src="/images/mab-fixed-fpr-ps.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 21 Aug 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/multi-armed-bandits-and-false-positives.html</guid></item><item><title>Sicily tries an old solution to fight old work problems</title><link>https://stop.zona-m.net/2020/08/sicily-tries-an-old-solution-to-fight-old-work-problems/</link><description>&lt;p&gt;COVID19 may have made work smarter, but it is surely making taxes harder.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 20 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/sicily-tries-an-old-solution-to-fight-old-work-problems/</guid></item><item><title>Cultivate the Skill of Undivided Attention, or 'Deep Work' (Crosspost from `letterstoanewdeveloper.com`)</title><link>https://josh.works/letters-to-a-new-developer-deep-work</link><description>&lt;p&gt;&lt;em&gt;Dan Moore is always welcoming to guest authors; he accepted something I wrote: &lt;a href="https://letterstoanewdeveloper.com/2019/12/19/cultivate-the-skill-of-undivided-attention-or-deep-work/"&gt;Cultivate the Skill of Undivided Attention, or “Deep Work” (Letters to a New Developer)&lt;/a&gt;. It ended up on &lt;a href="https://news.ycombinator.com/item?id=22646839"&gt;Hacker News&lt;/a&gt; with 100 comments. I wrote this back in December 2019, forgot to post here until now.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dan published a book by the title &lt;a href="https://letterstoanewdeveloper.com/2020/08/17/letters-to-a-new-developer-the-book/"&gt;Letters to a New Developer&lt;/a&gt;. This letter is in it, but don’t let that disuade you. The book is full of great insights from developers of all experience levels.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dear New Developer,&lt;/p&gt;

&lt;p&gt;You &lt;em&gt;know&lt;/em&gt; that there’s a chasm between your skill level and that of the mythical “senior software developer”.&lt;/p&gt;

&lt;p&gt;If you build a list of topics you encounter on your job that, if learned to a deep enough level, would put you on the same level as a senior developer, you’ll end up even more demoralized than before compiling that list.&lt;/p&gt;

&lt;p&gt;No need to assemble this list yourself! I’ve done it for you.&lt;/p&gt;

&lt;p&gt;Here’s the list of topics that I’d need to dedicate significant time to, in order to close the gap between me and the senior developers on our team, that I’ve encountered &lt;em&gt;in my last two days of work&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Breaking complex unknowns into simpler unknowns that can be further split into individual tickets&lt;/li&gt;
  &lt;li&gt;Adding tests to complex, legacy code, to guide further refactoring of said code.&lt;/li&gt;
  &lt;li&gt;Using &lt;code class="language-plaintext highlighter-rouge"&gt;grep&lt;/code&gt; to comb through server logs to diagnose a hard-to-identify-and-reproduce problem&lt;/li&gt;
  &lt;li&gt;Provisioning new servers&lt;/li&gt;
  &lt;li&gt;Building bash scripts to automate complex workflows&lt;/li&gt;
  &lt;li&gt;Digging into gem source code to can shed gem dependencies while maintaining certain features&lt;/li&gt;
  &lt;li&gt;Understanding indexing well enough to see that certain queries that we &lt;em&gt;thought&lt;/em&gt; were using indexes were not, and fix this oversight index on the fly, without causing any blips in availability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these line-items has many books written about the topic.&lt;/p&gt;

&lt;p&gt;It seems like you could fill a bookshelf with books that address knowledge senior developers have available to them inside their own heads.&lt;/p&gt;

&lt;p&gt;It takes me long enough to work through a single book, so imagining a bookshelf of extra-curricular reading is quite daunting.&lt;/p&gt;

&lt;p&gt;It might feel daunting for you, too.&lt;/p&gt;

&lt;h2 id="leading-vs-lagging-indicators"&gt;Leading vs. lagging indicators&lt;/h2&gt;

&lt;p&gt;The above list of skills is a lagging indicator of the underlying knowledge. We should not target improving lagging indicators, we should improve leading indicators.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Josh, what is this ‘lagging and leading indicator’ stuff?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Great question!&lt;/p&gt;

&lt;p&gt;A lagging indicator is “evidence that something has already happened.”&lt;/p&gt;

&lt;p&gt;If you got an A on a test, that is evidence that you learned the material.&lt;/p&gt;

&lt;p&gt;A leading indicator is “evidence that something will likely happen”.&lt;/p&gt;

&lt;p&gt;If you want to get an A on a test, you should study in a similar way as others who have gotten an A on that test. Maybe you need ten high-quality hours of study to get an A, so “number of high-quality study hours” would be a &lt;em&gt;leading&lt;/em&gt; indicator of your grade.&lt;/p&gt;

&lt;p&gt;We no longer take tests (phew. I hated taking tests.) but we get mini-tests of our knowledge, daily. We’re paid to solve problems, which often require learning new things.&lt;/p&gt;

&lt;p&gt;Rather than focusing on a list of things other developers have learned, and targeting that list, I humbly propose that a &lt;em&gt;leading indicator&lt;/em&gt; of acquiring this kind of knowledge is “hours per week spent in a state of intentional deep work”.&lt;/p&gt;

&lt;p&gt;The above list of topics are &lt;em&gt;lagging indicators&lt;/em&gt; of a high degree of technical knowledge. Someone acquires the knowledge, then, and only then, can demonstrate that they have it.&lt;/p&gt;

&lt;p&gt;Leading indicators are “predictive”, in that if you can identify correctly those indicators, you can predict the outcome of the issue at hand.&lt;/p&gt;

&lt;p&gt;In this case, the issue at hand is “become significantly more experienced in the domain of software development”.&lt;/p&gt;

&lt;p&gt;I propose that a &lt;em&gt;leading indicator&lt;/em&gt; of someone gaining these skills is the amount of time they spend in a state of &lt;em&gt;deep work&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I’d encourage you to read &lt;a href="https://www.goodreads.com/book/show/25744928-deep-work"&gt;Deep Work: Rules for Focused Success in a Distracted World&lt;/a&gt;. The author makes a case for deep work being a key role in the success of “knowledge workers” (which includes many types of work, including, of course, software development.)&lt;/p&gt;

&lt;p&gt;If you’d rather not read the book, here’s the gist, from &lt;a href="https://www.samuelthomasdavies.com/book-summaries/business/deep-work/"&gt;this summary of the book&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;In order to produce the absolute best stuff you’re capable of, you need to commit to deep work.&lt;/li&gt;
  &lt;li&gt;The ability to quickly master hard things and the ability to produce at an elite level, in terms of both quality and speed, are two core abilities for thriving in today’s economy.&lt;/li&gt;
  &lt;li&gt;“To learn hard things quickly, you must focus intensely without distraction.”&lt;/li&gt;
  &lt;li&gt;“Your work is craft, and if you hone your ability and apply it with respect and care, then like the skilled wheelwright you can generate meaning in the daily efforts of your professional life.”&lt;/li&gt;
  &lt;li&gt;“The key to developing a deep work habit is to move beyond good intentions and add routines and rituals to your working life designed to minimize the amount of your limited willpower necessary to transition into and maintain a state of unbroken concentration.”&lt;/li&gt;
  &lt;li&gt;Imagine two equally knowledgeable early-career software developers. They have the exact same skills on January 1, 2020. If the first software developer spends four hours a week doing deep work, while the second software developer spends fifteen hours a week doing deep work, their trajectories will be quite different, and that second developer will quickly gain technical knowledge and proficiencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, if you’re an early-career software developer, track the time you spend doing deep work. That has you focusing on a &lt;em&gt;leading&lt;/em&gt; indicator of growing in your skills.&lt;/p&gt;

&lt;p&gt;At that point, you’ll benefit from Peter Drucker’s assessment:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What is measured, improves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You’ll track how many hours you spend doing deep work, and by tracking it, you’ll do more and more of it.&lt;/p&gt;

&lt;h2 id="in-conclusion"&gt;In conclusion&lt;/h2&gt;

&lt;p&gt;Do more deep work, and over a year or two years, your skills will grow much faster than those doing less deep work. Eventually, you might find that you’re doing the work of a senior developer!&lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;

&lt;p&gt;-Josh&lt;/p&gt;</description><author>Josh Thompson</author><pubDate>Thu, 20 Aug 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/letters-to-a-new-developer-deep-work</guid></item><item><title>What was the biggest blunder in your career as a developer?</title><link>https://www.mootoday.com/blog/what-was-the-biggest-blunder-in-your-career-as-a-developer</link><description>A twenty year tech career retrospective of what I would do differently and why.</description><author>www.mootoday.com - RSS Feed</author><pubDate>Thu, 20 Aug 2020 15:47:18 GMT</pubDate><guid isPermaLink="true">https://www.mootoday.com/blog/what-was-the-biggest-blunder-in-your-career-as-a-developer</guid></item><item><title>Rebuilding a Monolith</title><link>/rebuilding-a-monolith/</link><description>&lt;p&gt;It's no secret that microservices are the hotness right now (I won't say new at this point because they're fairly well established). But you only have to Google the phrase &amp;quot;Why not to use Microservices&amp;quot; to see a treasure trove of articles about why to be sceptical of this pattern. As with all things, in some instances it's the &amp;quot;correct&amp;quot; approach and in other's, it's not. I'm not entering into a holy war of which is better, nor am I a Basecamp hipster who despises frameworks. This is a story about why and how we collapsed a few &amp;quot;microservices&amp;quot; into our central API.&lt;/p&gt;
&lt;h2&gt;The Setup&lt;/h2&gt;
&lt;p&gt;Koru is a pre-interview assessment filter. That sounds wordy but basically it's designed for large corporations who get thousands of applications to jobs, and this tool aids companies in seeing what different strengths a candidate has based on an assessment. The product is fairly simple infrastructure wise. An event-driven microservices architecture with a central API, a React frontend for customers and a admin interface for employees. In addition to that we have systems to generate PDF's and send emails that are part of the candidate lifecycle through our system.&lt;/p&gt;
&lt;p&gt;What we wanted to combine was the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our admin interface and it's API&lt;/li&gt;
&lt;li&gt;Our internal tooling API&lt;/li&gt;
&lt;li&gt;Our internal API documentation
...into our main API that serves customers and their candidates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's worth noting that these were all separate repositories.&lt;/p&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;The reasons for doing this were simple&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our admin portal was incredibly buggy and since we had moved over to a new assessment provider, our API no longer provided us with all the functionality that we needed. Additionally, it had no tests suite, or documentation. The biggest reason however, was that Koru runs (currently) as a single tenant model. In other words, each client gets their own API and DB instance. The problem with this is that the admin API needs to then connect to each customers database. And because we're not insane that means we have to create a VPC peer with each individual customer database from the admin API. Not only is this complex to maintain and debug but also a pain to update. Furthermore, it was hosted on it's own EC2 instance which meant that it was costing us a reasonable amount of money. This would be fine if it was high usage but it was barely ever used.&lt;/li&gt;
&lt;li&gt;Our internal tooling API had the same issue as the admin API, we wanted to keep things simple from a &amp;quot;what has access to the DB&amp;quot; point of view so we chose to collapse this one as well.&lt;/li&gt;
&lt;li&gt;The API documentation was something that we wanted to be constantly updated along with new changes to the API. To make developers go to a whole new repo, make a whole new PR and such meant that it seldom got updated. We chose to combine it so it can be referenced as part of a Pull request change to any code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How we did it&lt;/h2&gt;
&lt;p&gt;As all things should be, we tackled these one at a time and released each one of them so we didn't have any confused boundaries about where large swaths of code got introduced.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The documentation
The documentation site was written using Slate, which is a Ruby based project. To add this to our &lt;em&gt;NodeJS/Express&lt;/em&gt; API, sounds painful but all we did was put it in new folder 'devdocs' and treat it as it's own separate project. Next we added a GitHub Action (Our CI/CD tool of choice) to build and deploy the 'devdocs' to the S3 bucket where they are served from.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="That was easy" src="https://blogs.psychcentral.com/hidden-disabilities/files/2020/02/easy-button-300x300.png" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Well that was easy&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Right, next... 2. Internal Tooling API
Since this was a new service written only a few months prior, it was already similar to our main API in terms of the patterns used. Additionally, it was written in Typescript so the code could quite literally be copied across. We took the time to fix up some tools that were broken and created new ones. Additionally, we added a few simple sanity tests for each one so that we could verify they worked.&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Admin Portal
This is where things became a bit tricky. As stated previously, one of the main reasons we wanted to merge these API's was because the current API didn't really serve the needs of the system, we were sort of bending it to our needs and in a number of cases, it snapped under the pressure. We embarked first on a mission of discovery, what were all the things that it did, why did it do them, and how did we want to improve them.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The API was written in Python using Flask as this is what the previous team had mostly used. But since there was little expertise within the team for Python, we decided to rewrite it in Typescript. One of the main improvements we wanted to make was to merge the creation of different records in various tables into one easy to use endpoint. Previously, each individual section when creating anything (like a study, survey etc.) had to be saved individually. This lead to confusion from users and confusion when debugging issues where some data was relied on by another part of the system. By combining them, we made the save process one simple API call, and more importantly, one set of errors to deal with.
Along with this merge, we added new tests, both unit and integration so that we could verify the integrity of this process. We also made plans to improve the service further by adding tools for Koru employees to be able to &amp;quot;Copy&amp;quot; existing studies to make them easier to setup.&lt;/p&gt;
&lt;p&gt;The difficult part with this merge was authentication. In our main API we had no mechanism to authenticate requests only from Koru Employees. Thankfully this was a breeze, because we use Auth0 to handle authentication. We simply wrote a new middleware handler that reads from Auth0 based on the JWT &lt;code&gt;req.user.sub&lt;/code&gt; field and checks certain properties of that user in Auth0's system.&lt;/p&gt;
&lt;p&gt;The interface was built in React but although not inherently bad, it was clearly coded in a bit of a rush. Things over time had been hacked in as new features came along so we took the time to clean this up (as the boy scouts that we are) before merging it into our central tooling interface. Again we added tests to make sure that the interface loaded the data correctly and behaved the way we expected.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, I'm really happy with &amp;quot;the big merge&amp;quot;, because it's meant that we've created a useful resource for Koru employees and they can self-serve for whatever customers ask of them. Additionally, it will be easier to add documentation for the API and consolidate that back to a single work ticket. On top of this, the main Koru API is now a complete CRUD API rather than having bits of &amp;quot;R&amp;quot; and &amp;quot;U&amp;quot; with &amp;quot;C&amp;quot; and &amp;quot;D&amp;quot; being all the way over in a different service! Hooray!&lt;/p&gt;</description><author/><pubDate>Thu, 20 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/rebuilding-a-monolith/</guid></item><item><title>Useful Constants in Ruby's Date Class</title><link>https://nelson.cloud/useful-constants-in-rubys-date-class/?ref=rss</link><description>Diving into useful constants in Ruby&amp;rsquo;s Date class</description><author>Nelson Figueroa</author><pubDate>Thu, 20 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nelson.cloud/useful-constants-in-rubys-date-class/?ref=rss</guid></item><item><title>"Be yourself" is terrible advice</title><link>https://theoutline.com/post/7142/be-yourself-is-terrible-advice</link><description>&lt;p&gt;One of my favorite mentors used to tell me this: &amp;#8220;Be yourself, unless yourself is a shitbag; then be someone else.&amp;#8221;&lt;/p&gt;


                &lt;p&gt;&lt;a href="https://theoutline.com/post/7142/be-yourself-is-terrible-advice"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Wed, 19 Aug 2020 23:19:38 GMT</pubDate><guid isPermaLink="true">https://theoutline.com/post/7142/be-yourself-is-terrible-advice</guid></item><item><title>On Work, Money and PURPOSE, Part 3</title><link>https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-3/</link><description>&lt;p&gt;Time to talk about money.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 19 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-3/</guid></item><item><title>The Fifth Prototype</title><link>https://www.pinecoder.dev/blog/2020-08-19/the-fifth-prototype/</link><description>On July 2nd I re-booted a stalled side project of mine called Chronicles — a markdown based journaling application. On August 14th I shipped the first (very basic) phase of it. Nobody should be interested in this release, but it is an important milestone for me — something usable shipped. This is a brief retrospective on the first milestone.
Getting in a rhythm with Go The thought of restarting this project was daunting.</description><author>Home on Pinecoder blog</author><pubDate>Wed, 19 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.pinecoder.dev/blog/2020-08-19/the-fifth-prototype/</guid></item><item><title>Lifetimes in Rust</title><link>https://hashrust.com/blog/lifetimes-in-rust/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Lifetimes is a hard concept to grasp for a lot of beginner Rustaceans. I too struggled with them for some time before I started to appreciate how vital they are for the Rust compiler to carry out its duties. Lifetimes are not inherently hard. It is just that they are such a novel construct that most programmers have never seen them in any other language. What makes things worse is the overloaded use of the word &lt;em&gt;lifetime&lt;/em&gt; to talk about many closely related ideas. In this article I will separate those ideas from each other, and in doing so give you tools to think clearly about lifetimes.&lt;/p&gt;
&lt;h2 id="purpose-of-lifetimes"&gt;Purpose of lifetimes&lt;/h2&gt;
&lt;p&gt;Before discussing specifics, let's first understand why lifetimes exist. What purpose do they serve? Well, lifetimes help the compiler in enforcing one simple rule: no reference should outlive its referent. In other words, lifetimes help the compiler in squashing dangling pointer bugs. As you will see in examples below, the compiler achieves this through analyzing the lifetimes of the variables involved. If the lifetime of a reference is smaller than the lifetime of the referent, the code compiles, otherwise it doesn't.&lt;/p&gt;
&lt;h2 id="meaning-of-the-word-lifetime"&gt;Meaning of the word &lt;em&gt;lifetime&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Part of the reason why lifetimes are so confusing is because in much of Rust writing the word &lt;em&gt;lifetime&lt;/em&gt; is loosely used to refer to three different things — the actual lifetimes of variables, lifetime constraints and lifetime annotations. Let's talk about them one by one.&lt;/p&gt;
&lt;h3 id="lifetimes-of-variables"&gt;Lifetimes of variables&lt;/h3&gt;
&lt;p&gt;This is straightforward. Lifetime of a variable is the amount of time for which it is alive. This meaning is closest to the dictionary sense of &lt;em&gt;the duration of a thing's existence or usefulness&lt;/em&gt;. For example, in the below code, &lt;code&gt;x&lt;/code&gt;'s lifetime extends until the end of the outer block, while &lt;code&gt;y&lt;/code&gt;'s lifetime ends at the end of the inner block.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//---------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;span class="z-comment"&gt;//                                                 |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;        let&lt;/span&gt;&lt;span class="z-variable"&gt; y&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;from&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Why&amp;quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span class="z-comment"&gt;//---+              | x's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;        //                               | y's lifetime |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;--------------------------------+              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;---------------------------------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="lifetime-constraints"&gt;Lifetime constraints&lt;/h3&gt;
&lt;p&gt;The way variables interact in the code puts some constraints on their lifetimes. For example, in the following code, the line &lt;code&gt;x = &amp;amp;y;&lt;/code&gt;  adds a constraint that &lt;code&gt;x&lt;/code&gt;'s lifetime should be enclosed within &lt;code&gt;y&lt;/code&gt;'s lifetime:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//error:`y` does not live long enough&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;        let&lt;/span&gt;&lt;span class="z-variable"&gt; y&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//----+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//                               | y's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//                               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;        x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;y&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//----------------|--------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//                               |              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;------------------------+              | x's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;x's length is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;span class="z-comment"&gt;//    |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;-------------------------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If this constraint was not added, &lt;code&gt;x&lt;/code&gt; could access invalid memory in the &lt;code&gt;println!&lt;/code&gt; line because &lt;code&gt;x&lt;/code&gt; is a reference to &lt;code&gt;y&lt;/code&gt; which will be destroyed in the previous line.&lt;/p&gt;
&lt;p&gt;Note that a constraint does not change the actual lifetimes — &lt;code&gt;x&lt;/code&gt;'s lifetime, for example, still extends until the end of the outer block — they are just a tool used by the compiler to disallow dangling references. And in the above example, the actual lifetimes do not meet the constraint: &lt;code&gt;x&lt;/code&gt;'s lifetime has strayed beyond &lt;code&gt;y&lt;/code&gt;'s lifetime. Hence, this code fails to compile.&lt;/p&gt;
&lt;h3 id="lifetime-annotations"&gt;Lifetime annotations&lt;/h3&gt;
&lt;p&gt;As seen in the last section, many times the compiler generates all the lifetime constraints. But as code gets more complex, the compiler asks the programmer to manually add constraints. The programmer does this through lifetime annotations. For example, in the code snippet below, the compiler needs to know whether the reference returned from the &lt;code&gt;print_ret&lt;/code&gt; function borrows from &lt;code&gt;s1&lt;/code&gt; or &lt;code&gt;s2&lt;/code&gt;, so the compiler asks the programmer to explicitly add this constraint:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//error:missing lifetime specifier&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//this function's return type contains a borrowed value,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//but the signature does not say whether it is borrowed from `s1` or `s2`&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_ret&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;s1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;str&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;str&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;s1 is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    s2&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; some_str&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Some string&amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;to_string&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; other_str&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Other string&amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;to_string&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; s1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_ret&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;some_str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;other_str&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
In case you are wondering why can't the compiler see that the output reference is borrowed from &lt;code&gt;s2&lt;/code&gt;, go read &lt;a href="https://stackoverflow.com/a/31612025"&gt;this StackOverflow answer&lt;/a&gt;. To see when the compiler lets you omit lifetime annotations, see the &lt;em&gt;Lifetime elision&lt;/em&gt; section below.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;p&gt;The programmer then annotates both &lt;code&gt;s2&lt;/code&gt; and the returned reference with &lt;code&gt;'a&lt;/code&gt;, thus telling the compiler that the return value is borrowed from &lt;code&gt;s2&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_ret&lt;/span&gt;&lt;span&gt;&amp;lt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;s1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a str&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a str&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;s1 is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    s2&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; some_str&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Some string&amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;to_string&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; other_str&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Other string&amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;to_string&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; s1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_ret&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;some_str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;other_str&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I want to emphasize that just because the annotation &lt;code&gt;'a&lt;/code&gt; appears on both the argument &lt;code&gt;s2&lt;/code&gt; and the returned reference, do not interpret this to mean that both &lt;code&gt;s2&lt;/code&gt; and the returned reference have the exact same lifetime. Instead, this should be read as: the returned reference with annotation &lt;code&gt;'a&lt;/code&gt; is borrowed from the argument with the same annotation.&lt;/p&gt;
&lt;p&gt;And since &lt;code&gt;s2&lt;/code&gt; is further borrowed from &lt;code&gt;other_str&lt;/code&gt;, the lifetime constraint is that the returned reference must not outlive &lt;code&gt;other_str&lt;/code&gt;. The code compiles because the lifetime constraint is indeed met:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_ret&lt;/span&gt;&lt;span&gt;&amp;lt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;s1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a str&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a str&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;s1 is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; s1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    s2&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; some_str&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Some string&amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;to_string&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; other_str&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;Other string&amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;to_string&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//-------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; ret&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_ret&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;some_str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;other_str&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span class="z-comment"&gt;//---+                 | other_str's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;    //                                              | ret's lifetime  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;-----------------------------------------------+-----------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before showing you more examples, let me briefly cover lifetime annotation syntax. To create a lifetime annotation, a lifetime parameter must first be declared. For example, &lt;code&gt;&amp;lt;'a&amp;gt;&lt;/code&gt; is a lifetime declaration. Lifetime parameters are a kind of generic parameter and you can read &lt;code&gt;&amp;lt;'a&amp;gt;&lt;/code&gt; as "for some lifetime &lt;code&gt;'a&lt;/code&gt;...". Once a lifetime parameter is declared, it can be used in references to create a lifetime constraint.&lt;/p&gt;
&lt;p&gt;Remember that by annotating references with &lt;code&gt;'a&lt;/code&gt;, the programmer is just formulating some constraints; it is then the compiler's job to find a concrete lifetime for &lt;code&gt;'a&lt;/code&gt; that satisfies the imposed constraints.&lt;/p&gt;
&lt;h3 id="more-examples"&gt;More examples&lt;/h3&gt;
&lt;p&gt;Next, consider a function &lt;code&gt;min&lt;/code&gt; which finds the minimum of two values:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; min&lt;/span&gt;&lt;span&gt;&amp;lt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; y&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;    if&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&lt;/span&gt;&lt;span class="z-variable"&gt; y&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;        x&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class="z-keyword"&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;        y&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; p&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;        let&lt;/span&gt;&lt;span class="z-variable"&gt; q&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 10&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;        let&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; min&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;p&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;q&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;        println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Min is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the &lt;code&gt;'a&lt;/code&gt; lifetime parameter annotates arguments &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt; and the return value. It means that the return value could borrow from either &lt;code&gt;x&lt;/code&gt; or &lt;code&gt;y&lt;/code&gt;. Since &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; further borrow from &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; respectively, the returned reference's lifetime should be enclosed within &lt;em&gt;both&lt;/em&gt; &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt;'s lifetimes. This code also compiles because the constraint is met:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; min&lt;/span&gt;&lt;span&gt;&amp;lt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; y&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;    if&lt;/span&gt;&lt;span class="z-variable"&gt; x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&lt;/span&gt;&lt;span class="z-variable"&gt; y&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;        x&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class="z-keyword"&gt; else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;        y&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; p&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//-------------------------------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    {&lt;/span&gt;&lt;span class="z-comment"&gt;//                                                           |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;        let&lt;/span&gt;&lt;span class="z-variable"&gt; q&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 10&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//------------------------------+              | p's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;        let&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; min&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;p&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;q&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span class="z-comment"&gt;//------+              | q's lifetime |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;        println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;Min is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; r&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span class="z-comment"&gt;// | r's lifetime |              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;---------------------------+--------------+              |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;-------------------------------------------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In general, when the same lifetime parameter annotates two or more arguments of a function, the returned reference must not outlive the smallest of the arguments' lifetimes.&lt;/p&gt;
&lt;p&gt;One last example. Many new C++ programmers make a mistake of returning a pointer to a local variable. A similar attempt in Rust is not allowed:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//Error:cannot return reference to local variable `i`&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; get_int_ref&lt;/span&gt;&lt;span&gt;&amp;lt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;()&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-operator"&gt;    &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;i&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; get_int_ref&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As there is no argument to the &lt;code&gt;get_int_ref&lt;/code&gt; function, the compiler knows that the returned reference must be borrowing from a local variable, which is not allowed. The compiler rightly averts disaster because the local variable will be cleaned up by the time the returned reference tries to access it:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; get_int_ref&lt;/span&gt;&lt;span&gt;&amp;lt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;()&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt; &amp;amp;&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;a i32&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; i&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//-------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-operator"&gt;    &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;i&lt;/span&gt;&lt;span class="z-comment"&gt;//                     | i's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; main&lt;/span&gt;&lt;span&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;    let&lt;/span&gt;&lt;span class="z-variable"&gt; j&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; get_int_ref&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//-----+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//                               | j's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;// &amp;lt;----------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="lifetime-elision"&gt;Lifetime elision&lt;/h2&gt;
&lt;p&gt;When the compiler lets the programmer omit the lifetime annotations, it is called lifetime elision . Again, the term &lt;em&gt;lifetime elision&lt;/em&gt; is misleading — how could lifetimes be elided when they are inextricably linked with how variables come into and go out of existence? It is not the lifetimes that are being elided, but rather lifetime annotations, and by extension lifetime constraints. In early versions of the Rust compiler, no elision was allowed and every lifetime annotation was required. But over time the compiler team observed that same patterns of lifetime annotations were being repeated, so the compiler was modified such that it started inferring them.&lt;/p&gt;
&lt;p&gt;The programmer can omit the annotations in the following cases:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When there is exactly one input reference. In this case the input's lifetime annotation is assigned to all the output references. For example: &lt;code&gt;fn some_func(s: &amp;amp;str) -&amp;gt; &amp;amp;str&lt;/code&gt; is inferred as &lt;code&gt;fn some_func&amp;lt;'a&amp;gt;(s: &amp;amp;'a str) -&amp;gt; &amp;amp;'a str&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;When there are multiple input references, but the first argument is &lt;code&gt;&amp;amp;self&lt;/code&gt; or &lt;code&gt;&amp;amp;mut self&lt;/code&gt;. In this case too the input's lifetime annotation is assigned to all the output references. For example: &lt;code&gt;fn some_method(&amp;amp;self) -&amp;gt; &amp;amp;str&lt;/code&gt; is equivalent to &lt;code&gt;fn some_method&amp;lt;'a&amp;gt;(&amp;amp;'a self) -&amp;gt; &amp;amp;'a str&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lifetime elision reduces the clutter in the code and it is possible that in future the compiler could infer lifetime constraints for even more patterns.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Many Rust newcomers find the subject of lifetimes hard to understand. But lifetimes, per se, are not to blame, rather it is how the concept is presented in a lot of Rust writing. In this article I have tried to tease apart the shades of meaning hidden in the overloaded use of the word &lt;em&gt;lifetime&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Lifetimes of variables have to meet certain constraints put on them by the compiler and the programmer before the compiler can ensure that the code is sound. Without the lifetime machinery, the compiler would not be able to guarantee safety of most Rust programs.&lt;/p&gt;</description><author/><pubDate>Wed, 19 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hashrust.com/blog/lifetimes-in-rust/</guid></item><item><title>Solar Opposites: Season 1</title><link>https://olshansky.info/tv/solar_opposites_season_1/</link><description>Olshansky's review of Solar Opposites: Season 1</description><author>🦉 olshansky 🦁</author><pubDate>Wed, 19 Aug 2020 01:06:03 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/tv/solar_opposites_season_1/</guid></item><item><title>Here is a NICE electronic design service!</title><link>https://stop.zona-m.net/2020/08/here-is-a-nice-electronic-design-service/</link><description>&lt;p&gt;What is 1-click BOM, and why it is important.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 18 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/here-is-a-nice-electronic-design-service/</guid></item><item><title>Top Three Strategic Priorities of Developer Productivity Startups</title><link>https://whoisnnamdi.com/developer-productivity-strategic-priorities/</link><description>What's top of mind for developer productivity leaders</description><author>Who is Nnamdi?</author><pubDate>Tue, 18 Aug 2020 18:30:32 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/developer-productivity-strategic-priorities/</guid></item><item><title>Introducing JmFrX: A Bridge From JMX to JDK Flight Recorder</title><link>https://www.morling.dev/blog/introducing-jmfrx-a-bridge-from-jmx-to-jdk-flight-recorder/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_why_jmfrx"&gt;Why JmFrX?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_how_to_use_jmfrx"&gt;How To Use JmFrX&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_customizing_event_formats"&gt;Customizing Event Formats&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_how_it_works"&gt;How It Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_takeaways"&gt;Takeaways&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;I’m excited to share the news about an open-source utility I’ve been working on lately:
&lt;a href="https://github.com/gunnarmorling/jmfrx"&gt;JmFrX&lt;/a&gt;,
a tool for capturing JMX data with JDK Flight Recorder.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;When using JMX (&lt;a href="https://en.wikipedia.org/wiki/Java_Management_Extensions"&gt;Java Management Extensions&lt;/a&gt;), The Java platform’s standard for monitoring and managing applications,
JmFrX allows you to periodically record the attributes from any JMX MBean into &lt;a href="https://openjdk.java.net/jeps/328"&gt;JDK Flight Recorder&lt;/a&gt; (JFR) files,
which you then can analyse using &lt;a href="https://openjdk.java.net/projects/jmc/"&gt;JDK Mission Control&lt;/a&gt; (JMC).&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Tue, 18 Aug 2020 18:30:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/introducing-jmfrx-a-bridge-from-jmx-to-jdk-flight-recorder/</guid></item><item><title>Craves and Gets Nothing</title><link>http://evantravers.com/articles/2020/08/18/craves-and-gets-nothing/</link><description>&lt;blockquote&gt;
&lt;p&gt;[4] The soul of the sluggard craves and gets nothing,
while the soul of the diligent is richly supplied.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(Proverbs 13:4)&lt;/p&gt;
&lt;p&gt;Lord, thank you for allowing this scripture to jump out at me… and punch me squarely in my sluggard mouth.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;The sluggard is a common enough topic in Proverbs… and I have foolishly associated it only with the concepts of physical diligence and work ethic. This proverb clearly states that this sluggard struggles to provide for his &lt;em&gt;soul&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The very same day I read this I found myself crying out to you for more of yourself. While I am grateful you have placed within me the desire to know you more… I was instantly convicted that I crave… and get nothing. I have not showed diligence to seek you. &amp;quot;The soul of the diligent is richly supplied&amp;quot;… while I have everything I need for life and godliness (2 Pet 1:3) I don't have because I ask wrongly (James 4:3)… and I ought to submit and draw near. (James 4:8-9)&lt;/p&gt;
&lt;p&gt;Forgive me Lord for how long I have not given you the worship you are worth. This is my cry of humility and submission: you are Lord, and I am sorry. I want to give you the first-fruits of my day once more… please continue to challenge and encourage me. In the name of your Son, in whom I have peace with God and a surety of salvation, amen.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;To be honest… in my pride I realized I tend to skip over proverbs about sluggards thinking they don't apply to me. Well, I am chastened and humbled. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Tue, 18 Aug 2020 13:12:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/08/18/craves-and-gets-nothing/</guid></item><item><title>Methods for styling your React app</title><link>https://maxrozen.com/guide-to-styling-react-app</link><description>It can be pretty confusing to pick how to style your React app. This guide attempts to simplify your choice.</description><author>Max Rozen</author><pubDate>Tue, 18 Aug 2020 11:42:05 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/guide-to-styling-react-app</guid></item><item><title>Update for August, year of total chaos 2020</title><link>https://ciesie.com/post/update_18082020/</link><description>&lt;p&gt;Close to month and a half has passed since the last update. So many things have happened during that
time. I&amp;rsquo;ll only write about tech related topics. It&amp;rsquo;s not a hard constraint but it&amp;rsquo;s also not a
personal blog about my life.&lt;/p&gt;
&lt;p&gt;The project that takes most of my free time is the custom controller for CG artists. Unfortunately
the &lt;em&gt;BLE&lt;/em&gt; version is on hold. I have not been able to fix &lt;em&gt;Windows&lt;/em&gt; pairing problems. I have bought
&lt;a href="https://www.adafruit.com/product/2267"&gt;The Bluefruit LE Friend&lt;/a&gt; and uploaded the sniffer firmware.
That helps me to fix the advertising packets. I was inspired by the &lt;em&gt;Logitech&lt;/em&gt; mouse&amp;rsquo;s sniffed,
advertising packets.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Tue, 18 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/update_18082020/</guid></item><item><title>2020-08-18/01</title><link>https://ho.dges.online/pictures/2020-08-18-01/</link><description>&lt;p&gt;That wee face&amp;hellip;&lt;/p&gt;</description><author>ho.dges.online</author><pubDate>Tue, 18 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/pictures/2020-08-18-01/</guid></item><item><title>2020-08-18/02</title><link>https://ho.dges.online/pictures/2020-08-18-02/</link><description/><author>ho.dges.online</author><pubDate>Tue, 18 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/pictures/2020-08-18-02/</guid></item><item><title>Apple's Hell</title><link>https://omarabid.com/apple-hell/</link><description>Apple's issues</description><author>Omar Abid - Personal Blog</author><pubDate>Tue, 18 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://omarabid.com/apple-hell/</guid></item><item><title>Prerecording Talks for Online Conferences</title><link>https://www.swyx.io/prerecording-talks</link><description>Tips for Speakers Prerecording Talks for Online Conferences</description><author>swyx's site RSS Feed</author><pubDate>Tue, 18 Aug 2020 02:26:34 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/prerecording-talks</guid></item><item><title>Artisanal RSA</title><link>https://rya.nc/artisanal-rsa.html</link><description>&lt;!-- included from `include/globals.rst` --&gt;
&lt;p&gt;Sometimes hacking requires doing things that, while possible to do
with some algorithm, simply aren’t supported by any existing implementation.
Usually for good reason. A good example of this that I’ve run into in the past
is needing to initialize a hash algorithm with a specific state. There’s really
not any reason to do this unless you’re trying to execute a
&lt;a class="external" href="https://en.wikipedia.org/wiki/Length_extension_attack"&gt;length extension attack&lt;/a&gt;, and with the exception of
&lt;a class="external" href="https://github.com/bwall/HashPump"&gt;HashPump&lt;/a&gt; (which was written specifically
for that use case) I’m not aware of any library that supports it. I recently
ran into this with problem with &lt;a class="external" href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)"&gt;RSA&lt;/a&gt;.&lt;/p&gt;</description><author>rya.nc</author><pubDate>Mon, 17 Aug 2020 21:53:00 GMT</pubDate><guid isPermaLink="true">https://rya.nc/artisanal-rsa.html</guid></item><item><title>Algorithmic Colonization of Africa, part 1</title><link>https://stop.zona-m.net/2020/08/algorithmic-colonization-of-africa-part-1/</link><description>&lt;p&gt;Even if we may all have the same problems worldwide, we cannot just import, or export, &amp;ldquo;solutions&amp;rdquo;.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 17 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/algorithmic-colonization-of-africa-part-1/</guid></item><item><title>Tolkien &amp;amp; Politics</title><link>https://mebassett.info/tolkien-politics</link><description>When Tolkien first published the Lord of the Rings some critics mocked it by asking why any sensible adult would read a book about elves and orcs. They doubted whether it had any themes beyond the comprehension of a seven-year-old. 1 Yet one theme that runs through much of Tolkien's work — including the Lord of the Rings — is the relationship between language and power.</description><author>Essays by Matthew Eric Bassett</author><pubDate>Mon, 17 Aug 2020 19:20:00 GMT</pubDate><guid isPermaLink="true">https://mebassett.info/tolkien-politics</guid></item><item><title>Debunking btrfs</title><link>https://swag.industries/debunking-btrfs/</link><description>&lt;p&gt;&lt;em&gt;btrfs means no evil! btrfs is awesome!&lt;/em&gt;&lt;/p&gt;&lt;p&gt;A few weeks ago I listened to &lt;a href="https://linuxunplugged.com/358?ref=swag.industries"&gt;one of the Linux Unplugged podcasts&lt;/a&gt; about btrfs. It was a reminder that btrfs is great. I have been using btrfs for a few months now, so here is my comment.&lt;/p&gt;&lt;p&gt;For those who aren&amp;apos;&lt;/p&gt;</description><author>Swag Industries</author><pubDate>Mon, 17 Aug 2020 18:55:39 GMT</pubDate><guid isPermaLink="true">https://swag.industries/debunking-btrfs/</guid></item><item><title>Full Copy of 'The Atlanta Zone Plan' from 1922</title><link>https://josh.works/full-copy-of-1922-atlanta-zone-plan</link><description>&lt;p&gt;&lt;em&gt;update: I originally wrote this in 2020. It’s as present in my mind today as it was then. Some explanations can be found in the updates I wrote below. I might change the published date sometimes to float this up to the top of the list of blog posts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To see the document that enshrined this thing into law across the USA, read &lt;a href="https://nvlpubs.nist.gov/nistpubs/Legacy/BH/nbsbuildinghousing5.pdf"&gt;A Standard State Zoning Enabling Act: Under Which Municipalities May Adopt Zoning Regulations (pdf)&lt;/a&gt;. It is &lt;em&gt;full&lt;/em&gt; of jaw-dropping sentances. From page ONE:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Definitions. — No definitions are included. The terms used in the act are so commonly understood that definitions are unnecessary. Definitions are generally a source of danger. They give to words a restricted meaning. No difficulty will be found with the operation of the act because of the absence of such definitions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hilariously, the document is, in fact, &lt;em&gt;full&lt;/em&gt; of definitions. Each page has a few lines of text and 3/4s of it is footnotes.&lt;/p&gt;

&lt;p&gt;Under a section called &lt;code class="language-plaintext highlighter-rouge"&gt;remedies&lt;/code&gt;, my jaw dropped, &lt;em&gt;again&lt;/em&gt;. Wow. To see it, and appreciate that this document is being faithfully re-implemented, every day, today, a thousand times, in different cities around the world, especially though in the united states, is to be brought to tears.&lt;/p&gt;

&lt;h2 id="a-warning-and-a-request"&gt;A Warning and a Request&lt;/h2&gt;

&lt;p&gt;In a moment, you will read the full text of a 1922 marketing pamphlet. This document is an important thread to understanding some very large political problems facing the world today, specifically &lt;strike&gt;housing, affordability, the growing wealth gap, and more&lt;/strike&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;update from a few years after I first wrote this post&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When i first wrote this, I downplayed what this document connects to. It was written by a supremacist, who wanted to maintain the supremacy he was clinging to, the violent oppression and exploitation of people deemed slaves.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;this 1922 marketing pamphlet became “law” in the greater united states in 1926, in a supreme court case between the municipality of Euclid, ohio, and a real estate company. American-style zoning is known as ‘euclidean’ zoning, for this reason. That supreme court case obviously references this 1922 document. That style of zoning is presumed god in the USA today. The people who know enough about the space to know what ‘euclidean zoning’ is generally do not know that the person who invented it, in first penning the section about residence districts, wrote &lt;code class="language-plaintext highlighter-rouge"&gt;r1-white&lt;/code&gt; and &lt;code class="language-plaintext highlighter-rouge"&gt;r2-colored&lt;/code&gt; in it. Definitionally, american-style zoning expects all housing to be segregated by that european-american style of supremacy, hallucinations of the concept of ‘race’. ‘single-family housing’ was the supremacist fantasy of whiteness, and multi-family housing was where they poured their rejected shadow-side. It was all, of course, heavily wrapped with layers of coercive control. Womp womp. the concept of political authority is, definitionally, credible threats of violence from one group against another. yaaaaaaay!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This document tells a story. This story is about &lt;em&gt;power&lt;/em&gt;. Most people that have &lt;em&gt;true&lt;/em&gt; power, power that can shape entire cities and how billions of dollars get spent, don’t run around telling everyone “I’m ludicrously powerful and there’s nothing you can do about it.”&lt;/p&gt;

&lt;p&gt;These ludicrously powerful people hide their power under layers of misdirection and distraction, and they make it look like they’re less powerful than they actually are. Like Robert Moses.&lt;sup id="fnref:robert-moses"&gt;&lt;a class="footnote" href="#fn:robert-moses" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;This 100 year old marketing brochure influences your daily experiences &lt;em&gt;today&lt;/em&gt;. Powerful people wrote that document.&lt;/p&gt;

&lt;h2 id="context-for-the-atlanta-zone-plan-of-1922"&gt;Context for the Atlanta Zone Plan of 1922&lt;/h2&gt;

&lt;p&gt;I recently read &lt;a href="https://www.blackfeminisms.com/zoning/"&gt;Racial Zoning: Segregation and the U.S. Federal Government&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ll share a quote from the article:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Whitten then went ahead and designed a zoning ordinance for Atlanta, advising city officials that “home neighborhoods had to be protected from any further damage to values resulting from inappropriate uses, including the encroachment of the colored.”&lt;/p&gt;

  &lt;p&gt;The zone plan drafted by Whitten and unpublished by the Atlanta City Planning Commission in 1922 explained that “race zoning is essential in the interest of the public peace, order and security and will promote the welfare and prosperity of both the white and colored race.”&lt;/p&gt;

  &lt;p&gt;The zoning law divided the city into an “R-I white district” and “R-2 colored district” with additional neighborhoods undetermined (Rothstein 2017)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This quote referenced a zone plan: &lt;a href="https://babel.hathitrust.org/cgi/pt?id=osu.32435003851870"&gt;The Atlanta Zone Plan: Report Outlining a Tentative Zone Plan for Atlanta&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I read every word of that document. It’s pictures of the original pamphelt, converted to PDF. Here’s the full document:&lt;/p&gt;

&lt;p&gt;&lt;img alt="15 pages of text" src="/images_2020/1922-zoning-plan.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;There’s only 15 pages with much text on them, and it is all so riveting.&lt;/p&gt;

&lt;p&gt;I share some high points and screenshots of the zoning plan in the following thread. I’d encourage you to peruse the threads before continuing:&lt;/p&gt;

&lt;h3 id="thoughts-on-denvers-zoning-and-systemic-racism-twitter-thread-1"&gt;Thoughts on Denver’s zoning and systemic racism (Twitter thread #1)&lt;/h3&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;1/20 Thoughts on Denver's zoning and systemic racism. &lt;br /&gt;&lt;br /&gt;Here's a screenshot from &lt;a href="https://twitter.com/CityofDenver?ref_src=twsrc%5Etfw"&gt;@CityofDenver&lt;/a&gt;'s zoning map on &lt;a href="https://t.co/Tzx271JS8u"&gt;https://t.co/Tzx271JS8u&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This is textbook Euclidean Zoning, AKA &amp;quot;Single-Use Zoning&amp;quot;.&lt;br /&gt;&lt;br /&gt;The problems of this form of zoning are well-known:&lt;a href="https://t.co/WqiklxjB4h"&gt;https://t.co/WqiklxjB4h&lt;/a&gt; &lt;a href="https://t.co/7RDaFJlttS"&gt;pic.twitter.com/7RDaFJlttS&lt;/a&gt;&lt;/p&gt;&amp;mdash; Josh Thompson (@josh_works) &lt;a href="https://twitter.com/josh_works/status/1294726871574179840?ref_src=twsrc%5Etfw"&gt;August 15, 2020&lt;/a&gt;&lt;/blockquote&gt;


&lt;h3 id="deeper-dive-into-connections-between-1922-zoning-plan-and-modern-denver-twitter-thread-2"&gt;Deeper dive into connections between 1922 zoning plan and modern Denver (Twitter thread #2)&lt;/h3&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I missed a piece in this &amp;quot;R-1 White District&amp;quot; and &amp;quot;R-2 Colored District&amp;quot; narrative outlined in Atlanta's 1922 zoning plan.&lt;br /&gt;&lt;br /&gt;The central piece of Witten's racist zoning plan was &amp;quot;the encroachment of the colored&amp;quot; in white neighborhoods. &lt;a href="https://t.co/2gWMdsaEb8"&gt;https://t.co/2gWMdsaEb8&lt;/a&gt; &lt;a href="https://t.co/mej9ILqNOK"&gt;pic.twitter.com/mej9ILqNOK&lt;/a&gt;&lt;/p&gt;&amp;mdash; Josh Thompson (@josh_works) &lt;a href="https://twitter.com/josh_works/status/1295034724658737152?ref_src=twsrc%5Etfw"&gt;August 16, 2020&lt;/a&gt;&lt;/blockquote&gt;


&lt;p&gt;I wanted to make the text more readable/discoverable, instead of it living “inside” of this PDF, so I used a tool to extract text from the images. I’ve sprinkled some of my notes below.&lt;/p&gt;

&lt;p&gt;Oh, and if you find this kind of thing interesting, I’m working on an interesting related project, and I’d love your help:&lt;/p&gt;

&lt;h4&gt;Want to stay up to date on these projects? Enter your email below, and you'll get an approximately-monthly newsletter from me.&lt;/h4&gt;
&lt;form action="https://buttondown.email/api/emails/embed-subscribe/josht" class="embeddable-buttondown-form" method="post" target="popupwindow"&gt;
  &lt;label for="bd-email"&gt;Enter your email&lt;/label&gt;
  &lt;input id="bd-email" name="email" type="email" /&gt;
  
  &lt;input type="submit" value="Subscribe" /&gt;
  &lt;p&gt;&lt;i&gt;If you don't see the subscribe form above, &lt;a href="https://buttondown.email/josht"&gt;click here&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;
&lt;/form&gt;

&lt;hr /&gt;

&lt;h2 id="the-atlanta-zone-plan-report-outlining-a-tentative-zone-plan-for-atlanta"&gt;The Atlanta Zone Plan: Report Outlining a Tentative Zone Plan for Atlanta&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;copied from &lt;a href="https://babel.hathitrust.org/cgi/pt?id=osu.32435003851870"&gt;this online resource&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3 id="introduction-purpose-of-zoning"&gt;Introduction: Purpose of Zoning&lt;/h3&gt;

&lt;p&gt;Zoning will prevent the destruction of the comfort and value of your home through the erection nearby of a:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Public garage&lt;/li&gt;
  &lt;li&gt;Oil filling station&lt;/li&gt;
  &lt;li&gt;Grocery store&lt;/li&gt;
  &lt;li&gt;Steam Laundry&lt;/li&gt;
  &lt;li&gt;Sanatorium&lt;/li&gt;
  &lt;li&gt;Ice plant&lt;/li&gt;
  &lt;li&gt;Foundry&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="plan-authors"&gt;Plan Authors&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Atlanta City Planning Commission&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;James Key, &lt;em&gt;Mayor, Chairman&lt;/em&gt; &lt;sup id="fnref:they-mayor-was-in-on-it"&gt;&lt;a class="footnote" href="#fn:they-mayor-was-in-on-it" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
  &lt;li&gt;Robert R. Otis, &lt;em&gt;Vice-Chairman&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Frank Pittman&lt;/li&gt;
  &lt;li&gt;Fred J. Terry&lt;/li&gt;
  &lt;li&gt;Hoke Smith&lt;/li&gt;
  &lt;li&gt;Joel Hurt&lt;/li&gt;
  &lt;li&gt;Chas. A. Wickersham&lt;/li&gt;
  &lt;li&gt;Robert H. Whitten, &lt;em&gt;Consultant&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;H. D. Cutter, Jr, &lt;em&gt;Engineer and Secretary&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="five-illustrations-of-the-need-for-zoning"&gt;Five Illustrations of the Need for Zoning&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note from Josh: Each of these illustrations are complex. They interleave facts and misdirection, I have a lot I could say about each sentance, but I’ll restrain myself until later in the document, as much as possile.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id="illustration-1"&gt;Illustration 1&lt;/h3&gt;

&lt;p&gt;A mechanic buys a home for his family in a newly developed residence subdivision. He and his neighbors plant trees and shrubs and make the section a quiet and attractive home neighborhood.&lt;/p&gt;

&lt;p&gt;Then the adjoining house changes hands and the new owner (thinking only of his own immediate advantage) builds a small grocery store projecting to the sidewalk line and surrounds it with a litter of boxes and barrels.&lt;/p&gt;

&lt;p&gt;Our mechanic who has invested his entire savings, $3500 [$54,000 in 2020 dollars], in his home and given a first mortgage lien for the remainder of the purchase price would like to move away and offers his home for sale but finds that it will now bring but half the amount he paid for it and his entire savings, $3500, have been lost.&lt;/p&gt;

&lt;p&gt;He is forced to remain where he is. Not only his home but all the homes in the block are depreciated in value; as a result the owners are discouraged; the yards are neglected and the property allowed to run down.&lt;/p&gt;

&lt;p&gt;This nice, quiet home section has been ruined and the savings of the home owners wiped out. This is an example of what is happening in one block after another all over the city. Is this the way to encourage thrift or promote home ownership?&lt;/p&gt;

&lt;p&gt;&lt;img alt="A Store in the Middle of a Resident Block" src="/images_2020/2020-08-16 at 11.28 AM.jpg" title="A Store in the Middle of a Resident Block" /&gt;&lt;/p&gt;

&lt;h3 id="illustration-2"&gt;Illustration 2&lt;/h3&gt;

&lt;p&gt;Mr. Smith has purchased a home in an attractive neighborhood. All of the homes have large well kept yards.&lt;/p&gt;

&lt;p&gt;Mr. Smith believes that children, like plants, must have plenty of sun light and room in which to grow. The location selected seems an ideal one in which to live and raise his family. But there is a vacant lot next door. A speculative builder estimates that he can buy that lot, erect a four story, sixteen suite apartment house thereon, rent the apartments, sell to some investor and clean up a handsome profit for himself.&lt;/p&gt;

&lt;p&gt;The apartment house is erected and is quickly rented and sold.&lt;/p&gt;

&lt;p&gt;It rents well because it is in a section of private homes and has the benefit of the lawns and open spaces about the adjoining houses. But the value of Mr. Smith’s home is practically destroyed. His light and air is cut off by the huge bulk of the apartment house.&lt;/p&gt;

&lt;p&gt;The quiet and comfort of the entire block for private residence purposes has been largely destroyed.&lt;/p&gt;

&lt;p&gt;Each home owner fears that a similar apartment building may be constructed next door to him. Those who can, sell out or move away and rent their homes for any purpose or use that offers.&lt;/p&gt;

&lt;p&gt;Apartment houses are needed but is it necessary to permit them to scatter indiscriminately throughout the private home sections? If Atlanta is to be preserved as a city of homes we must protect the home owner by establishing definite limits beyond which the apartment house may not spread&lt;sup id="fnref:burying-the-lede"&gt;&lt;a class="footnote" href="#fn:burying-the-lede" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h3 id="illustration-3"&gt;Illustration 3&lt;/h3&gt;

&lt;p&gt;A number of large apartment houses have been erected in a block in a section near the center of the city that is being generally developed for apartment house purposes. There is a large vacant lot in the block and a speculative builder determines that in consequence of the demand for garage storage space in this apartment-house neighborhood he can make a good profit by building a public garage on the vacant lot.&lt;/p&gt;

&lt;p&gt;The garage is built and the noise and traffic incident to its operation makes the entire block undesirable for residence purposes. The tenants of the nearby apartment houses move out and the vacant suites are only again rented at a rate that means an enormous loss to the owners&lt;sup id="fnref:this-is-encouraged-by-zoning"&gt;&lt;a class="footnote" href="#fn:this-is-encouraged-by-zoning" rel="footnote"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Zoning is just as essential for the protection of the apartment-house owner as it is for the protection of the home owner.&lt;/p&gt;

&lt;h3 id="illustration-4"&gt;Illustration 4&lt;/h3&gt;

&lt;p&gt;Here is a large area that has been built up quite uniformly with small homes. There is a block near the center of the area that has remained undeveloped owing chiefly to the cost of bringing the lots to street grade.&lt;/p&gt;

&lt;p&gt;An ice manufacturer picks this block as a good location for his new ice plant. The plant is built and becomes the ice distributing center for a large area. The delivery teams are stabled at the plant, and early each morning the rumbling of the wagons and the shouts of the teamsters make sleep for the nearby residents impossible.&lt;/p&gt;

&lt;p&gt;Added to this, there is the continuous noise arising from the operation of the plant. The entire district is now undesirable for residence purposes&lt;sup id="fnref:unless-the-workers-can-live-there"&gt;&lt;a class="footnote" href="#fn:unless-the-workers-can-live-there" rel="footnote"&gt;5&lt;/a&gt;&lt;/sup&gt;. Property values fall and other small shops and industries take advantage of the low prices to secure locations for their operations.&lt;/p&gt;

&lt;p&gt;The area becomes blighted.&lt;/p&gt;

&lt;p&gt;It is spoiled for residence use and being without railroad track facilities is of little value for industrial purposes.&lt;/p&gt;

&lt;h3 id="illustration-5"&gt;Illustration 5&lt;/h3&gt;

&lt;p&gt;A ten story office and store building is erected at the corner of the best business block in the central business section of the city. The building is a financial success: the ground floor is rented for retail store purposes and the upper floors, being light and airy, bring good rentals.&lt;/p&gt;

&lt;p&gt;Its success, however, leads to the erection of a sixteen story building across the street from one of its frontages, a twenty story building across the street from the other frontage and of sixteen to twenty-four story buildings on both sides and in the rear.&lt;/p&gt;

&lt;p&gt;The offices, being darkened by the higher buildings are forced to use artificial light throughout the entire day and are rentable only at a fraction of the former amounts.&lt;/p&gt;

&lt;p&gt;The building no longer earns a fair return on the investment. As the competition in building height proceeds a large proportion of the office floors of each building in this entire section are so darkened as to make the returns from the rentals insufficient to cover the investment&lt;sup id="fnref:office-buildings"&gt;&lt;a class="footnote" href="#fn:office-buildings" rel="footnote"&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Unless office building heights are strictly limited the result is bound to be disastrous to the investors as well as injurious to the health and comfort of the clerks working in the darkened offices.&lt;/p&gt;

&lt;h2 id="what-zoning-is-and-does"&gt;What Zoning is and does&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Josh: We’re getting closer to the author’s revealing their true colors. Just keep in mind the authors have a strong preference to keep black people out of white neighborhoods.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Zoning is a conscious, intelligent effort to direct the building of the city in accord with a well-considered plan&lt;sup id="fnref:conscious-intelligent-plan"&gt;&lt;a class="footnote" href="#fn:conscious-intelligent-plan" rel="footnote"&gt;7&lt;/a&gt;&lt;/sup&gt;. Like good housekeeping it provides a place for everything and tries to keep everything in its place. Like good industrial management it plans for an orderly growth and expansion of the plant.&lt;/p&gt;

&lt;p&gt;Zoning divides the land area of the city into residence, business and industrial districts and prevents the erection of business and industrial buildings in the residence districts or of industrial buildings in the business districts&lt;sup id="fnref:prohibit-businesses"&gt;&lt;a class="footnote" href="#fn:prohibit-businesses" rel="footnote"&gt;8&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Zoning prevents the development of great blighted areas near the heart of the city. Unless some definite limit is fixed to the distance to which business may spread out from the central business area one block after another is abandoned by the resident owners until great areas are affected that will never be needed for business and the typical blighted district results&lt;sup id="fnref:white-flight"&gt;&lt;a class="footnote" href="#fn:white-flight" rel="footnote"&gt;9&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;St. Louis has one of the best examples of this wasteful development&lt;sup id="fnref:st-lewis"&gt;&lt;a class="footnote" href="#fn:st-lewis" rel="footnote"&gt;10&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Zoning will centralize local business in well-defined local business centers. This will facilitate the transaction of business. It will improve land and rental values in the business sections, while at the same time conserving values in the residence sections&lt;sup id="fnref:zoning-enforces-sprawl"&gt;&lt;a class="footnote" href="#fn:zoning-enforces-sprawl" rel="footnote"&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Zoning will keep the apartments out of the private house sections. The coming of the apartment drives out the private home. Only by setting definite limits to the spread of the apartment can the city be preserved as a city of homes&lt;sup id="fnref:apartments-means-black-people"&gt;&lt;a class="footnote" href="#fn:apartments-means-black-people" rel="footnote"&gt;12&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Zoning will prevent congestion of population. In addition to confining tenement house construction to certain areas, zoning will prevent excessive crowding even in the tenement areas. This will be accomplished by requiring a minimum number of square feet of lot area for each family for which the tenement is arranged&lt;sup id="fnref:minimum-lot-size"&gt;&lt;a class="footnote" href="#fn:minimum-lot-size" rel="footnote"&gt;13&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Zoning is essential to preserve the morale of the various neighborhoods or communities into which the city is divided. Zoning creates confidence that the existing character of the neighborhood will be preserved&lt;sup id="fnref:neighborhood-character"&gt;&lt;a class="footnote" href="#fn:neighborhood-character" rel="footnote"&gt;14&lt;/a&gt;&lt;/sup&gt;. Such confidence is essential to the improvement of the area and to the maintenance of a vigorous civic pride and spirit.&lt;/p&gt;

&lt;p&gt;Zoning requires each owner so to use his property as not to injure his neighbor. Without zoning the individual owner is powerless to prevent the destruction of the value of his property&lt;sup id="fnref:such-tricky-wording"&gt;&lt;a class="footnote" href="#fn:such-tricky-wording" rel="footnote"&gt;15&lt;/a&gt;&lt;/sup&gt;. Only by submitting to some restriction on his power to do with his own just as he pleases is he himself able to obtain protection. Zoning is a practical application of the Golden Rule to the use of property.&lt;/p&gt;

&lt;p&gt;Zoning enforces a certain degree of co-operation among property owners for their mutual advantage and protection. A certain degree of uniformity in the development of a block or area is beneficial to all owners. This is the meaning of restrictive covenants in all better-class residential developments. Zoning applies the principle of the restrictive covenant in so far as it can be used to promote public as distinct from purely private ends.&lt;/p&gt;

&lt;p&gt;&lt;img alt="the reason for the building line" src="/images_2020/2020-08-16-reason-for-the-building-line.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;The growth of cities has made it necessary to modify former ideas both of personal library and property rights. What a man can be allowed to do and what uses he can be allowed to make of his property depend on whether he lives on a 100 acre farm or in the middle of a city block.&lt;/p&gt;

&lt;p&gt;With the growth of the city it becomes more and more necessary to distinguish between liberty and license both as applied to persons and to property. Property in a city is “affected with a public interest.” Its value is a joint product of individual initiative and community growth. Its misuse can bring irreparable injury to the community and to property owners generally. It must submit to control both in the public interest and for its own preset vation.&lt;/p&gt;

&lt;p&gt;No useful trade or industry is in itself a nusiance; but any trade, industry or other use of property may become a nuisance if located in violation of an appropriate and orderly plan of city development.&lt;/p&gt;

&lt;p&gt;&lt;img alt="When is it time to zone?" src="/images_2020/2020-08-16-when-is-it-time-to-zone.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;Zoning will limit the height of buildings differently in different parts of the city. The height limits will be those appropriate for the various classes of use. No owner will be permitted to appropriate for the use of his building an undue share of the common stock of light and air. Without a height limit the tendency is for each new office or hotel building to push up higher than its neighbors in order to get more light and air. This competition to build the highest building with its attendant street traffic congestion will be stopped by zoning.&lt;/p&gt;

&lt;p&gt;Zoning will conserve property values. Haphazard development is bound to be costly and uneconomic development. Zoning will save enormous waste in building construction. With uncontrolled building development the construction of a new building in a neighborhood often means a net loss in the aggregate value of the building of that neighborhood. With zoning, each new building increases the aggregate value in an amount equal to and usually in excess of its own cost.&lt;/p&gt;

&lt;p&gt;Zoning will attract money to a city for investment in real estate. Large lending institutions will be inclined to favor those cities in which their investments will be afforded the safeguard of a comprehensive zoning plan. Failure to provide the zoning safeguard is as inexcusable as failure to protect property against destruction by fire.&lt;/p&gt;

&lt;p&gt;Zoning protects the home. Quiet and freedom from the distraction incident to trade, industy and attendant street traffic are essential to a wholesome home environment.&lt;/p&gt;

&lt;p&gt;Zoning will establish uniform building lines in the residence sections, thus giving opportunity for a front yard with a lawn and trees and preventing one building from pushing out in front of its neighbors.&lt;/p&gt;

&lt;p&gt;Zoning will promote industrial development. It will set aside adequate areas for industries within which the new plant may locate without incurring the criticism and continual complaints of neighboring residents and owners. It will attract to the city and to the home areas near the industrial areas a good and abundant labor supply. The segregation of industries will make it possible to serve the industrial areas more ef efficiently and more economically with sewers, trucking routes and freight facilities.&lt;/p&gt;

&lt;p&gt;Zoning promotes the health and comfort of the people. Orderly city growth cannot fail to have a marked effect on the physical fitness and vitality of the city’s inhabitants. The rapid increase in nervous and organic disorders has some very definite relation to the congestion, noise and confusion incident to the existing haphazard and uncontrolled building development.&lt;/p&gt;

&lt;p&gt;The New York Zoning Commission said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The necessity for reducing the stress and strain of city life is becoming more and more apparent. This is essential if the city is to be a place in which our heritage of health and vitality is to be used, conserved and handed down to succeeding generations instead of being abused and exhausted.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="outline-of-tentative-zone-plan"&gt;Outline of Tentative Zone Plan&lt;/h2&gt;

&lt;p&gt;The zoning amendment of the city charter provides that zoning plans may be prepared by the City Planning Commission and that such plans if adopted by the General Council after public hearing have been held shall have the force of law. It is fully realized that plans of this kind, before being adopted, should have the benefit resulting from their study and criticism by property owners and civic and business organizations throughout the city. The plan herewith presented is not a final plan, but merely a tentative draft to secure public suggestions and criticism.&lt;/p&gt;

&lt;p&gt;&lt;img alt="A Five-Story Apartment Projecting Beyond the Building Line Established by Residences" src="/images_2020/2020-08-16 at 1.22 PM.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;It is proposed that this tentative plan shall be taken up in detail with the members of the General Council, with citizens interested, and with civic and commercial organizations and as a result of the recommendations thus received a final plan will be prepared for submission to the Commission and the General Council. It is expected that the final plan will be the result of the joint efforts and best thought of all concerned in the direction of building development along orderly and well considered lines of city growth.&lt;/p&gt;

&lt;p&gt;The city of Atlanta is divided into six classes of use districts. Two of these are residence districts and four are business and industrial districts. In addition to the use districts there are four classes of height districts and five classes of area districts. The height and area districts are superimposed over the use districts.&lt;/p&gt;

&lt;p&gt;Consequently, each portion of the city is in some one of the six classes of use districts, in some one of the four classes of height districts and also in some one of the five classes of area districts. The boundaries of the various use, height and area districts are shown on the zone map.&lt;/p&gt;

&lt;h3 id="residence-districts"&gt;Residence Districts&lt;/h3&gt;

&lt;p&gt;THE two classes of residence districts are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Class UI or dwelling house district.&lt;/li&gt;
  &lt;li&gt;Class U2 or apartment house district.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A building arranged for more than two families may not be constructed in a dwelling house district. One of the chief purposes of the zone plan is to preserve Atlanta as a city of homes.&lt;/p&gt;

&lt;p&gt;While a certain number of apartment houses are beneficial, they should not be allowed to drive out the private homes in all sections of the city. Carefully limited but adequate areas are allowed for apartment house developement. The dwelling house districts, from which apartment houses are excluded, will include the larger portion of the entire area of Atlanta&lt;sup id="fnref:apartments-are-banned"&gt;&lt;a class="footnote" href="#fn:apartments-are-banned" rel="footnote"&gt;16&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Trade and industry are excluded from the residence districts&lt;sup id="fnref:trade-is-banned"&gt;&lt;a class="footnote" href="#fn:trade-is-banned" rel="footnote"&gt;17&lt;/a&gt;&lt;/sup&gt;. Churches, schools, libraries, etc., are permitted in the residence districts. Hospitals, sanitariums and institutional buildings are permitted in those blocks of the residence districts already occupied by similar buildings. They will also be permitted in other locations with the approval of the board of zoning appeals.&lt;/p&gt;

&lt;h3 id="race-zoning"&gt;Race Zoning&lt;/h3&gt;

&lt;p&gt;The residence districts are further subdivided into three race districts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;R1 or white residence district.&lt;/li&gt;
  &lt;li&gt;R2 or colored residence district.&lt;/li&gt;
  &lt;li&gt;R3 or undetermined race district.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the white residence districts no house not occupied by a colored family at the time of the passage of the zoning ordinance can be thereafter occupied by a colored family.&lt;sup id="fnref:black-people-cannot-buy"&gt;&lt;a class="footnote" href="#fn:black-people-cannot-buy" rel="footnote"&gt;18&lt;/a&gt;&lt;/sup&gt; In the colored residence districts no house not occupied by a white family at the time of the passage of the zoning ordinance can be thereafter occupied by a white family.&lt;sup id="fnref:black-people-cannot-sell"&gt;&lt;a class="footnote" href="#fn:black-people-cannot-sell" rel="footnote"&gt;19&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Servants quarters located on the same lot as the residence they serve will nevertheless be allowed in either districts without distinction to race&lt;sup id="fnref:blanket-exclusion-for-slaveholding-white-people"&gt;&lt;a class="footnote" href="#fn:blanket-exclusion-for-slaveholding-white-people" rel="footnote"&gt;20&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Certain limited limited residence areas are placed in neither the white district nor the colored district but are left undetermined as to the race zoning. The above race zoning is essential in the in interest of the public peace, order and security and will promote the welfare and prosperity of both the white and colored race. Care has been taken to prevent discrimination and to provide adequate space for the expansion of the housing areas of each race without encroaching on the areas now occupied by the other.&lt;/p&gt;

&lt;h3 id="business-and-industrial-districts"&gt;Business and Industrial Districts&lt;/h3&gt;

&lt;p&gt;There are four classes of business and industrial districts:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Class U3 or local retail store district.&lt;/li&gt;
  &lt;li&gt;Class U4 or commercial district.&lt;/li&gt;
  &lt;li&gt;Class U5 or industrial district.&lt;/li&gt;
  &lt;li&gt;Class U6 or industrial (semi-nuisance) district.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the local retail store (class U3) district retail stores, offices and small shops for custom work or for the making of articles to be sold at retail on the premises are permitted. The uses permitted in the residence districts are also permitted in the local retail business district.&lt;/p&gt;

&lt;p&gt;Public garages, light manufacturing and bulk storage are excluded from the local retail business district. This district is suitable chiefly for the smaller retail centers adjacent to the resident tial sections. The attempt has been to provide small areas for neighborhood stores at half-mile intervals throughout the resident sections.&lt;/p&gt;

&lt;p&gt;The commercial (class U4) district regulations permit in addition to all uses permitted in the local retail business district, light manufacturing of a non-nuisance character and also public garages, bulk storage and wholesale business. The commercial districts will include most of the central business sections and some of the local business sections along the main traffic arteries and street car lines.&lt;/p&gt;

&lt;p&gt;In the industrial (class U5) district all heavy industrial uses of a comparatively non-nuisance type are permitted in addition to all the uses permitted in the residence and business districts.&lt;/p&gt;

&lt;p&gt;Most of the area appropriate for industrial development extending out through the industrial housing areas along the railroads should be placed in the class U5 district and thus aid in the spreading out of the industries and of the industrial population.&lt;/p&gt;

&lt;p&gt;In the semi-nuisance industrial (class U6) district such uses as boiler making, structual iron works and junk yards are permitted. This district provides for industries that need to be distributed in various industrial sectors about the city but are detrimental if immediately adjacent to residences. The nuisance features, usually noise, smoke or odor, extend up to about 1,200 feet from the industry, thus making the vicinity undesirable for certain other types of industry and very undesirable for housing.&lt;/p&gt;

&lt;p&gt;Fertilizer plants, glue factories, slaughter houses and similar industries are classed as nuisances and under the zone plan will not be permitted to locate within the city limits.&lt;/p&gt;

&lt;p&gt;The excluded nuisances are those that affect a very wide area with these exceptions the purpose of the four business and industrial districts is to provide locations for all types of business and industrial use with a minimum of inconvenience and waste and a maximum of efficiency.&lt;/p&gt;

&lt;p&gt;A manufacturer of food preparations may be seriously injured by the location nearby of a chemical plant. Moreover certain types of business and industrial use may be lo city close to good residential sections without material injury while other types if located within a quarter of mile of such sections are distinct nuisances.&lt;/p&gt;

&lt;p&gt;It is only by carefully grading the various trade and industrial uses according to their comparative freedom from nuisance characteristics that an orderly and efficient development of the city can be secured.&lt;/p&gt;

&lt;p&gt;The zoning regulations also provide that such special uses as a cemetery, crematory, aviation field, sewage disposal plant or refuse dump may be located only on application to and with the approval of the board of zoning appeals.&lt;/p&gt;

&lt;h3 id="height-districts"&gt;Height Districts&lt;/h3&gt;

&lt;p&gt;The entire city is divided into four classes of height districts. The maximum limits are 35 feet, 50 feet, 100 feet and 150 feet, and the height districts are termed respectively class H1, H2, H3 and H4.&lt;/p&gt;

&lt;p&gt;In the class Hı height district the height limit is 2 1/2 stories but not in excess of 35 feet&lt;sup id="fnref:this-is-awkward"&gt;&lt;a class="footnote" href="#fn:this-is-awkward" rel="footnote"&gt;21&lt;/a&gt;&lt;/sup&gt;. The one and two family dwelling and the two story apartment sections will generally be placed in the class H1 district. This class will therefore include most of the residence sections.&lt;/p&gt;

&lt;p&gt;In the class H2 height district the maximum height is 50 feet. The 50 foot limit permits the erection of the ordinary four story apartment or the four story commercial building.&lt;/p&gt;

&lt;p&gt;In the class H3 height district the maximum height is 100 feet. The 100 foot limit provides for the ordinary eight story office or factory building. Most of the industrial areas will be included in this district.&lt;/p&gt;

&lt;p&gt;In the class H4 height district the maximum height is 150 feet. This 150 foot limit provides for the ordinary twelve story office or hotel building. The class H4 district will include that portion of the central business area where the most intensive office and hotel dedevelopment is anticipated.&lt;/p&gt;

&lt;p&gt;There are at present only seven buildings in the city over 150 feet in height. Our streets in the business section are so congested that it is imperative that the height of buildings be strictly limited so as to spread out the areas of intensive use. The widths of the streets will not take care of the traffic of a three story city and it will be absolutely disastrous to burden them with the traffic of a twenty or thirty story city.&lt;/p&gt;

&lt;p&gt;Values in the high grade shopping sections can best be maintained by encouraging the spreading out of the business area and the reservation of such sections for retail business and the traffic incident to retail business. The proposed height limit of 150 feet will tend to spread out the business district and will tend also to reduce traffic congestion and maintain values in the best retail business sections. The experience of New York and other large cities is that excessively high buildings are un-economic and very undesirable from a public standpoint&lt;sup id="fnref:tall-buildings-are-uneconomic"&gt;&lt;a class="footnote" href="#fn:tall-buildings-are-uneconomic" rel="footnote"&gt;22&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;A single high building may pay as it takes its light and air from above its neighbors; but when this first skyscraper becomes surrounded by buildings of similar height, light and air are cut off and only the upper floors can be leased at remunerative rentals. The occupants of the darkened offices on all the other floors must use artificial light throughout the&lt;/p&gt;

&lt;p&gt;day. By restricting all buildings to a reason ble height, so that when the business area is solidly built up, most of the floors of every building will have a fair supply of daylight, enormous economic loss will be avoided and the health of the people occupying offices and shops in the buildings will be conserved.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Which is the Common Sense Plan?" src="/images_2020/2020-08-16-which-is-the-common-sense-plan.jpg" /&gt;&lt;/p&gt;

&lt;h3 id="area-districts"&gt;Area Districts&lt;/h3&gt;

&lt;p&gt;The entire city is divided into five classes of area districts:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Class A1 requiring 5000 sq. ft. of lot area per family&lt;/li&gt;
  &lt;li&gt;Class A3 requiring 1250 sq. ft. of lot area per family.&lt;/li&gt;
  &lt;li&gt;Class A4 requiring 625 sq. ft. of lot area per family.&lt;/li&gt;
  &lt;li&gt;Class A5 with no required lot area per family when applied to commercial districts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The area districts are superimposed over the height and use districts. The area district regulations are intended to promote an approprate distribution of population and to resist the tendency toward the congestion of population. The requirement of a specified number of square feet of lot area per family is based on the number of housekeeping units or families for which the building is arranged or designed.&lt;/p&gt;

&lt;p&gt;On a lot of 40 feet by 125 feet a single family house can be constructed in a class A1 district; a two family house in a class A2 district; a four family house in a class A3 district; and an eight family house in a class A4 district. A more intensive development is in cach case allowed on corner lots.&lt;/p&gt;

&lt;p&gt;The class A1 district requiring 5000 sq. ft. of lot area per family is applied in those sections of the city where a single family house is the most appropriate development. The two family house is prohibited in A1 districts.&lt;/p&gt;

&lt;p&gt;The residence actions that seem appropriate for improvement with either a single family house on a small lot or a two family house on a lot having 5000 sq. ft. of lot area are placed in the class A2 district where the requirement is 2500 sq. ft. of lot area per family. Most of the apartment house districts will be in the class A4 districts requiring 625 sq ft. of lot area per family. This will permit an eight family apartment house on a lot 40 feet by 125 feet. Other apartment house areas will be placed in the A3 district which will permit the housing of but for families on the same size lot.&lt;/p&gt;

&lt;p&gt;The requirement of a certain number of square feet of lot area per family applies to residence buildings whether they are within the residence districts or are constructed within business or industrial districts. In computing the number of families that may be housed on a given lot area, deduction is made where a portion of the lot is used for business or industrial purposes. Thus in a class A3 area district where, for example, four families might be housed on a 40 ft. by 125 ft. lot, if there are stores occupying 2000 sq. ft. of area on the ground floor, the number of families that can be housed on the lot is reduced by one, or in other words there is a reduction of one family for each 2000 sq. ft. of lot area occupied for business purposes.&lt;/p&gt;

&lt;p&gt;The ordinary two or three story store and dwelling building is not a desirable type of construction from a public stand point. The regulations as applied will tend to reduce the number of flats that would otherwise be located over stores. The erection of dwellings or apartment houses is not prohibited in the industrial districts, though for the most part these districts are so located that there would be little tendency to build residences within them.&lt;/p&gt;

&lt;p&gt;It is, of course undesirable for many reasons to have residences and factories intermingled. The factories do not create a proper environment for the home, and the nearness of the home to the factories subject the factory owners to the complaints of the residents because of the nuisance features incident to the normal operations of the factories.&lt;/p&gt;

&lt;p&gt;While the zone plan does not prohibit the erection of residences even in the semi-nuisance industrial districts, it will tend to discourage the erection of dwellings therein for two reasons:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;first, with definite areas set aside for residences and factories, the financial hazard incident to the placing of residences in a factory zone will, in most cases, serve as a suf ficient deterrent;&lt;/li&gt;
  &lt;li&gt;second, the semi-nuisance in industrial districts will be placed in the A1 area districts which will require 5000 sq. ft. of lot area per family. This will further tend to make the erection of a residence in one of these districts uneconomic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="side-and-rear-yards"&gt;Side and Rear Yards&lt;/h3&gt;

&lt;p&gt;Side and rear yards are required in all residence districts. In business and industrial districts, side yards are not required, but rear yards are required where such districts adjoin residence districts.&lt;/p&gt;

&lt;p&gt;The zone plan does not attempt to provide a complete code for the lighting and ventilation of the building. It simply establishes minimum standards for those open spaces about the building that have a relation to the lighting and ventilation of the adjoining buildings as well as to that of the building itself. The zone regulations are thus confined to those things in which adjoining owners have a mutual interest. Side yards, rear yard and front yard spaces are required for the mutual advantage of all owners and occupants of the block. The provision or omission of an interior court, on the other hand, does not affect the neighbor.&lt;/p&gt;

&lt;p&gt;&lt;img alt="A Public Garage Located Among Apartments" src="/images_2020/2020-08-17-a-public-garage.jpg" title="A Public Garage Located Among Apartments" /&gt;&lt;/p&gt;

&lt;h3 id="front-yards-building-lines"&gt;Front Yards: Building Lines&lt;/h3&gt;

&lt;p&gt;Atlanta has been generally developed with residences setting well back from the street line, affording adequate room for lawn and trees. This makes a healthful and convenient city as well as beautiful city. Grass and trees make an attractive home environment and are almost essential to a normal, healthful development of the child.&lt;/p&gt;

&lt;p&gt;Occasionally, in a detached residence section, an apartment house disregards the existing building line and is erected at or near the street line. This cuts off light and air from the neighboring buildings and if it becomes a type will entirely change the character of our residence sections. Atlanta will tend to reproduce conditions obtaining in certain other cities where there are great areas with apartment houses erected right on the street line and with out a bit of vegetation-nothing but the pavement and the bare brick walls. We can pre vent the reproduction of such conditions in our residence sections by maintaining the existing building lines.&lt;/p&gt;

&lt;p&gt;&lt;img alt="An Apartment Projecting Beyond Single Family Residences" src="/images_2020/2020-08-17-an-apartment-projecting-beyond-single-family-residences.jpg" title="An Apartment PRojecting Beyond Single Family Residences" /&gt;&lt;/p&gt;

&lt;h3 id="classification-of-uses"&gt;Classification of Uses&lt;/h3&gt;

&lt;p&gt;The classification of uses which is a part of the zoning ordinance divides the various uses of property into groups, classes and subdivisions. The use classes correspond to the use districts. Each use class lists the uses for which the corresponding use district class is specially designed to provide. Starting with the private dwelling, the classification enumerates the various kinds of residential use and then the business and industrial uses graded and arranged according to their comparative freedom from nuisance characteristics. In the hierarchy of uses the dwelling comes first and garbage reduction and fertilizer plants last.&lt;/p&gt;

&lt;p&gt;&lt;img alt="&amp;quot;Shall the mass of the population of the great city of the future be housed like this or that?&amp;quot;" src="/images_2020/2020-08-17-house-the-masses.jpg" title="Zoning is the only safeguard against excessive congestion" /&gt;&lt;/p&gt;

&lt;h3 id="non-conforming-uses"&gt;Non-conforming Uses&lt;/h3&gt;

&lt;p&gt;The zoning ordinance does not affect existing uses of property. A use or building existing at the time of the passage of the zoning ordinance which does not comply with the regulations of the use district in which it is located is called a non-conforming use. Such use or building may be continued though not conforming to the use district regulations. The zoning ordinance is not retroactive. If, for example, there is a store in an area that under the zoning ordinance is included in a residence district the store may nevertheless be continued. A non-conforming use may also be changed subject to the general rule that, if changed, it must be to a higher use as listed in the classification of uses. If, however, the non-conforming use is a class U6 (semi-nuisance) use or class U7 (nuisance) use it may not be changed unless to a conforming use. A change to another use listed in the same subdivision of the classification is not deemed a change of use under the ordinance. Thus a change from a grocery store to any other kind of a retail store or shop would technically be deemed a continuance of the existing use.&lt;/p&gt;

&lt;p&gt;A building housing a non-conforming use may not be structurally altered to an extent exceeding during any ten year period 60 per cent of the assessed value of the building&lt;sup id="fnref:10-year-60-per-cent-assessed-value"&gt;&lt;a class="footnote" href="#fn:10-year-60-per-cent-assessed-value" rel="footnote"&gt;23&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;While, therefore, an existing non-conforming use may be continued the limitations imposed on a change of use and on the reconstruction of the building housing the non-conforming use will eventually bring about the elimination of the non-conforming use&lt;sup id="fnref:remember-the-goal"&gt;&lt;a class="footnote" href="#fn:remember-the-goal" rel="footnote"&gt;24&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h3 id="enforcement-board-of-zoning-appeals"&gt;Enforcement: Board of Zoning Appeals&lt;/h3&gt;

&lt;p&gt;The zoning ordinance will be enforced by the inspector of buildings&lt;sup id="fnref:or-anyone-else"&gt;&lt;a class="footnote" href="#fn:or-anyone-else" rel="footnote"&gt;25&lt;/a&gt;&lt;/sup&gt;. No building permit will be issued unless the building and its proposed use conform to the zoning regulations.&lt;/p&gt;

&lt;p&gt;In the application of the zoning many cases will arise, especially near the dividing line be tween two use districts, where the strict letter of the zoning regulations may properly be modified. This can be done in specific cases with out injury to general public purposes of the ordinance, while at the same time avoiding unnecessary injury to the individual owner.&lt;/p&gt;

&lt;p&gt;Strictly limited discretion is therefore lodged in a board of zoning appeals created by the ordinance to make minor modifications and exceptions to the general rules and regulations established by the ordinance.&lt;/p&gt;

&lt;h3 id="amendment-of-zone-plan"&gt;Amendment of Zone Plan&lt;/h3&gt;

&lt;p&gt;The Council will have full power to amend or supplement the zoning plan. Minor changes will be necessary to correct imperfections in the plan. Other amendments will be required to meet changing conditions of city growth. It is to be expected that the plan will be supplemented and changed when certain fundamental factors affecting the physical structure of the city have been fully worked out.&lt;/p&gt;

&lt;p&gt;While provision should be made for necessary changes, the method of such change should be safeguarded so as to prevent hasty and ill-considered action. A zone plan in order to afford the protection for which it is designed should be fairly permanent. Those who build in accordance with its provisions should feel reasonably sure that their investment will not be jeopardized by changes in the district lines. On the other hand, the method of change should not be so difficult as to make it impractical to conform the zone plan to changing conditions of city growth.&lt;/p&gt;

&lt;p&gt;Under the zoning ordinance any amendment proposed must secure a three-fourths vote of the Council for adoption&lt;sup id="fnref:this-plan-is-written-by-racists"&gt;&lt;a class="footnote" href="#fn:this-plan-is-written-by-racists" rel="footnote"&gt;26&lt;/a&gt;&lt;/sup&gt;, and before voting on such amendment the Council is required to submit the amendment to the city planning commission for its recommendation&lt;sup id="fnref:i-bet-they-are-racist-too"&gt;&lt;a class="footnote" href="#fn:i-bet-they-are-racist-too" rel="footnote"&gt;27&lt;/a&gt;&lt;/sup&gt;. If an amendment is proposed by the petition of the owners of 50% of the land in the area to be changed, Council must vote on such amendment within 90 days&lt;sup id="fnref:i-laughed-out-loud"&gt;&lt;a class="footnote" href="#fn:i-laughed-out-loud" rel="footnote"&gt;28&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Waste in City Building!" src="/images_2020/2020-08-17-waste-in-city-building.jpg" title="Waste in City Building" /&gt;&lt;/p&gt;

&lt;h3 id="building-the-future-city"&gt;Building the Future City&lt;/h3&gt;

&lt;p&gt;Zoning is a first essential to the securing of a measure of orderliness in the building of the city. The common sense of the average citizen leads to a degree of order in the home, the store and the factory that is all but lacking in the life and work of the community as a whole. For want of a well-considered plan of building development each man builds without reference to his neighbor. The result is chaotic. Haphazard growth is inefficient, wasteful and ugly. Why not use the same forethought and care in the building of our community home that each sane man uses in the building of his individual home or factory? Zoning is the direction of building development along orderly and well-considered lines of city growth. On the economic side, zoning means increased industrial efficiency and the prevention of enormous waste. On the human side, zoning means better homes and an increase of health, comfort and happiness for all the people.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;And that is the end of the 1922 Zoning Plan!&lt;/p&gt;

&lt;p&gt;Like I’ve mentioned before, I’m working on projects in this space. I’d love to have your help:&lt;/p&gt;

&lt;h4&gt;Want to stay up to date on these projects? Enter your email below, and you'll get an approximately-monthly newsletter from me.&lt;/h4&gt;
&lt;form action="https://buttondown.email/api/emails/embed-subscribe/josht" class="embeddable-buttondown-form" method="post" target="popupwindow"&gt;
  &lt;label for="bd-email"&gt;Enter your email&lt;/label&gt;
  &lt;input id="bd-email" name="email" type="email" /&gt;
  
  &lt;input type="submit" value="Subscribe" /&gt;
  &lt;p&gt;&lt;i&gt;If you don't see the subscribe form above, &lt;a href="https://buttondown.email/josht"&gt;click here&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;
&lt;/form&gt;

&lt;h2 id="updates-across-the-years"&gt;Updates across the years&lt;/h2&gt;

&lt;p&gt;I could have, maybe wish I had, done more incremental updates to this post. Since writing it, I’ve written many other stand-alone pieces that are thematically related, but never updated this piece itself. I’ll do some back-filling. I’m writing these updates long after I’ve written some of these pieces:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://zoningverydifferentthanours.substack.com/"&gt;zoning regimes very different than ours&lt;/a&gt; it’s a substack, of course. In it I was/am simply discussing zoning regimes, in the style of a book titled ‘legal systems very different than ours’. &lt;a href="https://zoningverydifferentthanours.substack.com/p/introduction-land-use-regimes-very"&gt;the first post of the substack explains the name more&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://zoningverydifferentthanours.substack.com/p/parking-minimums-as-ethnic-cleansing"&gt;parking minimums as ethnic cleansing&lt;/a&gt; is an attempt at a partial answer to ‘gosh, josh, why do you dislike some things about american style parking lots so much?’&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="2025"&gt;2025&lt;/h3&gt;

&lt;p&gt;I’ve referenced this document quite a few times since 2020, the year I first discovered the document and did this write-up.&lt;/p&gt;

&lt;p&gt;For instance, I once showed up at a neighborhood zoning meeting (right after doing this write-up), and while everyone was mixing and mingling about a proposed modification to the zoning code (a neighborhood zoned r2, where I lived at the time, yet almost every attendee lived in an adjoining r1 neighborhood).&lt;/p&gt;

&lt;p&gt;I asked the then director of planning and zoning for the city of Golden (Rick Muriby, &lt;code class="language-plaintext highlighter-rouge"&gt;Director of Community and Economic Development&lt;/code&gt;), if he know about this wild thing I’d just encountered, ‘the racialized origins of american-style zoning’?&lt;/p&gt;

&lt;p&gt;As I recall, he gave a bit of a smirk - not shock or fear or discomfort or whatever, and silently turned around and walked away.&lt;sup id="fnref:racialized"&gt;&lt;a class="footnote" href="#fn:racialized" rel="footnote"&gt;29&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Few people capable of reading today will explicitly defend supremacy, and the ones who &lt;em&gt;do&lt;/em&gt; defend it explicitly are so odious that everything about them is off-putting, thus to join them is to sorta willingly cede influence, and the possibility of being taken seriously by anyone of dignity or interest.&lt;/p&gt;

&lt;p&gt;Please remember that &lt;code class="language-plaintext highlighter-rouge"&gt;r1 zoning&lt;/code&gt; is virtually synonymous with ‘single family housing’ is virtually synonymous with ‘the suburbs’.&lt;/p&gt;

&lt;p&gt;Here’s a quote from Golden’s zoning code, today:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Residentially zoned area&lt;/em&gt;. “Residentially zoned area” means an area zoned for the development of residential dwelling units, including the CO, AG, RE, &lt;strong&gt;R1&lt;/strong&gt;, R1A, &lt;strong&gt;R2&lt;/strong&gt;, &lt;strong&gt;R3 zone districts&lt;/strong&gt;, and portions of PUD developments designed for such use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think a ‘proper appreciation’ for the origin of such designations lead to conversations vastly more interesting about American-style zoning than are otherwise available.&lt;/p&gt;

&lt;p&gt;I, personally, notice fatigue or boredom settling in on me when I am overhearing people speak seriously about modern american-style zoning, residence districts, the suburbs, all of it.&lt;/p&gt;

&lt;p&gt;to have one’s life affected by something like &lt;code class="language-plaintext highlighter-rouge"&gt;race districts&lt;/code&gt;/&lt;code class="language-plaintext highlighter-rouge"&gt;residence districts&lt;/code&gt; is to have ones life grievously affected by the ongoing effect of a supremacists willingness/desire to coerce their supremacy and beliefs and fears and griefs upon the world around them.&lt;/p&gt;

&lt;h2 id="footnotes"&gt;Footnotes&lt;/h2&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:robert-moses"&gt;
      &lt;p&gt;After this document from 1922 was sorta ‘ratified’ by the american supreme court in Euclid vs. Ambler (1926), it got labelled ‘euclidean zoning’ or ‘form-based zoning’. &lt;a href="/robert-moses"&gt;Robert Moses&lt;/a&gt; got his hands on it, and as reported early in &lt;em&gt;The Power Broker: Robert Moses and the Fall of New York&lt;/em&gt;, he spread this municipal form of government all around new york city and state. he’s more responsible for the built environment of the globe today than anyone else conceivable. (literally the geometry of roads, highway onramps, features multiplied across the world in asphalt, steel, and concrete like leaves on a tree.) He invented ‘urban highways’, ‘eminent domain’ in the modern sense, slum clearence/urban renewal, the federal highway administration, and much more. &lt;a class="reversefootnote" href="#fnref:robert-moses"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:they-mayor-was-in-on-it"&gt;
      &lt;p&gt;Only now did I realize &lt;em&gt;the mayor&lt;/em&gt; signed his name on this document. This document is explicitely racist, and the mayor was certainly not trying to &lt;a href="https://en.wikipedia.org/wiki/Overton_window"&gt;move the Overton window&lt;/a&gt;. That means nothing in this proposal would jepordize the mayor’s political future. &lt;em&gt;This is a plan by racists and for racists&lt;/em&gt;. &lt;a class="reversefootnote" href="#fnref:they-mayor-was-in-on-it"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:burying-the-lede"&gt;
      &lt;p&gt;The plan buries the lede. They are going to soon propose creating &lt;code class="language-plaintext highlighter-rouge"&gt;R-1 White Districts&lt;/code&gt; (which ban apartment buildings) and &lt;code class="language-plaintext highlighter-rouge"&gt;R-2 Colored Districts&lt;/code&gt; which permit small apartment buildings. The author also argues that a principle purpose of this zoning plan is to prevent the encroachment of Black people on White neighborhoods. &lt;a class="reversefootnote" href="#fnref:burying-the-lede"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:this-is-encouraged-by-zoning"&gt;
      &lt;p&gt;I actually agree with this assessment. Living next door to a parking garage is unpleasent and damages property values. Ironically, our modern zonign paradigm &lt;em&gt;forces&lt;/em&gt; the creation of parking garages where they would otherwise never exist, and forces the harms it claims to defend against. &lt;a class="reversefootnote" href="#fnref:this-is-encouraged-by-zoning"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:unless-the-workers-can-live-there"&gt;
      &lt;p&gt;Long commutes are expensive, harmful to the environment, pocketbook, and soul. How nice would it be to live next to where you work? If I read Illustration 4 with the perspective of someone who works at the ice plant, I would be a big fan of being able to live near where I worked. &lt;a class="reversefootnote" href="#fnref:unless-the-workers-can-live-there"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:office-buildings"&gt;
      &lt;p&gt;I laughed a little as I read this. I’m sure in 1922 a 20-story building was rather large and uncommon. I think we’ve all grown up with enough tall buildings that we can reject this assessment as categorically false, based on our lived experience. Every urban area has tall buildings (50 stories, 100 stories tall!) and the adjacent buildings go &lt;strong&gt;up&lt;/strong&gt; in value, not down. &lt;a class="reversefootnote" href="#fnref:office-buildings"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:conscious-intelligent-plan"&gt;
      &lt;p&gt;We could re-word this sentence to:&lt;/p&gt;
      &lt;blockquote&gt;
        &lt;p&gt;Zoning is a conscious, intelligent effort to &lt;strike&gt;direct&lt;/strike&gt; enforce the building of the city in accord with a &lt;strike&gt;well-considered&lt;/strike&gt; supremacist plan.&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;&lt;a class="reversefootnote" href="#fnref:conscious-intelligent-plan"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:prohibit-businesses"&gt;
      &lt;p&gt;screenshot zoning codes from Denver that show restrictions of commercial activity in residential zones &lt;a class="reversefootnote" href="#fnref:prohibit-businesses"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:white-flight"&gt;
      &lt;p&gt;The author is describing a phenomena known as “white flight”, but without labeling it as such. &lt;a class="reversefootnote" href="#fnref:white-flight"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:st-lewis"&gt;
      &lt;p&gt;St. Lewis has horrific history around racism. I’ll add links here soon. Just know that alarm bells should be going off in your head, as you read this reference to St. Lewis. &lt;a class="reversefootnote" href="#fnref:st-lewis"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:zoning-enforces-sprawl"&gt;
      &lt;p&gt;The authors are arguing for “Euclidean zoning”. There’s no question that Euclidean zoning encourages sprawl and car-dependence, accomplishing the exact opposite of what the authors say zoning will accomplish. &lt;a href="#context-twitter-thread-1"&gt;My first twitter thread&lt;/a&gt; goes into this phenomina in some detail. &lt;a class="reversefootnote" href="#fnref:zoning-enforces-sprawl"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:apartments-means-black-people"&gt;
      &lt;p&gt;Remember that the authors associate apartment buildings and black people. They should have written &lt;code class="language-plaintext highlighter-rouge"&gt;Zoning will keep the Blacks out of the White neighborhoods. The coming of the Black drives out the White. Only by setting definite limits to the spread of the Blacks can the city be preserved as a city of Whites.&lt;/code&gt; &lt;a class="reversefootnote" href="#fnref:apartments-means-black-people"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:minimum-lot-size"&gt;
      &lt;p&gt;This sentiment is what gives us “minimum lot size requirements”, which are, again, &lt;em&gt;everywhere&lt;/em&gt; in modern zoning codes. (screenshots? I can add screenshots) Oh, and this is where our density limits come from. &lt;a class="reversefootnote" href="#fnref:minimum-lot-size"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:neighborhood-character"&gt;
      &lt;p&gt;This sentance is why so many “pro-density” advocates claim that anyone who mentions ‘preserving neighborhood character’ is racist. They’re wrong - neighborhood character is an AMAZING thing to preserve, but our modern form of zoning just happens to be a pretty bad way of going about it. Neighborhoods can be preserved even as they adapt to the needs of the people that live there, as everyone becomes better off and more satisfied with where they live. &lt;a class="reversefootnote" href="#fnref:neighborhood-character"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:such-tricky-wording"&gt;
      &lt;p&gt;Of course we should not injure others. This sentance is tricky because what it’s really saying is &lt;code class="language-plaintext highlighter-rouge"&gt;Without zoning the White owner is powerless to prevent a black person from modifying their property as they see fit.&lt;/code&gt; &lt;a class="reversefootnote" href="#fnref:such-tricky-wording"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:apartments-are-banned"&gt;
      &lt;p&gt;Translation: This zoning plan bans apartment buildings from most of the city. &lt;a class="reversefootnote" href="#fnref:apartments-are-banned"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:trade-is-banned"&gt;
      &lt;p&gt;Translation: This zoning plan bans &lt;em&gt;all&lt;/em&gt; commercial activity from most of the city. &lt;a class="reversefootnote" href="#fnref:trade-is-banned"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:black-people-cannot-buy"&gt;
      &lt;p&gt;Translation: In an R1 district, it will become illegal for a black person to buy or rent property from a white property owner. &lt;a class="reversefootnote" href="#fnref:black-people-cannot-buy"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:black-people-cannot-sell"&gt;
      &lt;p&gt;Translation: In an R2 district, it will become illegal for a black property owner to sell or rent their property to a white person. &lt;a class="reversefootnote" href="#fnref:black-people-cannot-sell"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:blanket-exclusion-for-slaveholding-white-people"&gt;
      &lt;p&gt;Translation: White people who own slaves or have servents get a blanket exclusion from all this zoning limits we’re about to place on R1 (white single-family home) districts. &lt;a class="reversefootnote" href="#fnref:blanket-exclusion-for-slaveholding-white-people"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:this-is-awkward"&gt;
      &lt;p&gt;Would it be strange if we found many, many references to a 35 foot height limit in zoning codes across the nation? I predict it would be uncomfortable. (most of the land in american cities has a 35 foot height limit) &lt;a class="reversefootnote" href="#fnref:this-is-awkward"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:tall-buildings-are-uneconomic"&gt;
      &lt;p&gt;Now that we have 100 more years of experience with cities like New York City, I don’t think one can accept at face value the proposition that “excessively high buildings are uneconomic and very undesirable from a public standpoint”. Based off of the price of land in NYC, many, many people desire to live there. &lt;a class="reversefootnote" href="#fnref:tall-buildings-are-uneconomic"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:10-year-60-per-cent-assessed-value"&gt;
      &lt;p&gt;Translation: If a given building is “non-conforming” and assessed at a value of $50,000 (for example), if you spend more than $30,000 on renovations over a ten-year period, &lt;em&gt;you are required by law&lt;/em&gt; to bring the entire building into ‘conforming uses’, which means you may spend more on bringing the building “to code” than you wanted to spend on the renovation. Sprinkler systems and elevators are &lt;em&gt;very&lt;/em&gt; expensive. &lt;a href="https://www.strongtowns.org/journal/2017/6/9/learning-from-a-non-conforming-neighborhood"&gt;Most old neighborhoods are non-conforming&lt;/a&gt; &lt;a href="https://www.strongtowns.org/journal/2019/7/16/dropping-weight-is-not-enough-how-making-your-town-stronger-is-like-improving-bike-performance"&gt;This single clause causes near-endless fiscal trouble for property owners, cities running out of money, and renters&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:10-year-60-per-cent-assessed-value"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:remember-the-goal"&gt;
      &lt;p&gt;Remember the goal of this “non-conforming use” section. It’s &lt;em&gt;to force compliance with zoning laws over time&lt;/em&gt;, and it’s dammned effective. &lt;a href="https://www.nytimes.com/interactive/2016/05/19/upshot/forty-percent-of-manhattans-buildings-could-not-be-built-today.html"&gt;40 percent of the buildings in Manhattan could not be built today&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:remember-the-goal"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:or-anyone-else"&gt;
      &lt;p&gt;Local law enforcement is often an arm for zoning enforcement. &lt;a href="https://projects.tampabay.com/projects/2020/investigations/police-pasco-sheriff-targeted/intelligence-led-policing/"&gt;This article&lt;/a&gt; is an amazing investigation into long-term abuse of policing powers in Florida. One of the themes is “police harass residents”. You don’t have to read the whole article, just notice how they use zoning code to harass residents, &lt;em&gt;including issuing mandatory court appearances, and if the person failed to show up or pay the fine, the police would arrest them&lt;/em&gt;:&lt;/p&gt;
      &lt;blockquote&gt;
        &lt;p&gt;If the targets, their family members or associates wouldn’t speak to deputies or answer questions, &lt;strong&gt;STAR team deputies were told to look for code enforcement violations like faded mailbox numbers, a forgotten bag of trash or overgrown grass, Rodgers said.&lt;/strong&gt;
&lt;strong&gt;The father of one Sheriff’s Office target was fined over the numbers posted on his house. The numbers were there, the document notes in the top-right, but a nearby light made them hard to see. The form indicates the father had to attend a mandatory court hearing.&lt;/strong&gt;&lt;/p&gt;

        &lt;p&gt;Pasco Sheriff’s Office:&lt;/p&gt;

        &lt;p&gt;“We would literally go out there and take a tape measure and measure the grass if somebody didn’t want to cooperate with us,” he said.&lt;/p&gt;

        &lt;p&gt;Rodgers said people sometimes would fail to pay the fine, which would result in a warrant being issued for their arrest.&lt;/p&gt;

        &lt;p&gt;“We’d get them one way or another,” he said.&lt;/p&gt;

        &lt;p&gt;Rodgers said the tactics made him and many of his colleagues uneasy. He thought the strategy was both ineffective and unethical, he said. But when he raised concerns, he said, a supervisor threatened to strip him of his rank and send him back to patrol.&lt;/p&gt;
      &lt;/blockquote&gt;

      &lt;p&gt;&lt;img alt="What a disaster" src="/images_2020/citation1-2x.jpg" title="The father of one Sheriff’s Office target was fined over the numbers posted on his house. The numbers were there, the document notes in the top-right, but a nearby light made them hard to see. The form indicates the father had to attend a mandatory court hearing." /&gt;
  &lt;em&gt;The father of one Sheriff’s Office target was fined over the numbers posted on his house. The numbers were there, the document notes in the top-right, but a nearby light made them hard to see. The form indicates the father had to attend a mandatory court hearing.&lt;/em&gt; &lt;a class="reversefootnote" href="#fnref:or-anyone-else"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:this-plan-is-written-by-racists"&gt;
      &lt;p&gt;Remember, the mayor signed his name on this supremacist document. No way will 3/4ths of the city council sign off on anything that diminishes institutionalized supremacy/european american nobility norms. &lt;a class="reversefootnote" href="#fnref:this-plan-is-written-by-racists"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:i-bet-they-are-racist-too"&gt;
      &lt;p&gt;🤔 I wonder how supremacist the city council in Atlanta in 1920 was. How about 1950? 1980? 2010? 2020? 2025? &lt;a class="reversefootnote" href="#fnref:i-bet-they-are-racist-too"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:i-laughed-out-loud"&gt;
      &lt;p&gt;I laughed out loud as I read this last line of the paragraph. This zoning regime is carefully sculpted to look like it’s responsive to the inputs of “the people”, but it’s really responsive to the inputs of &lt;em&gt;only&lt;/em&gt; politically powerful people, like the mayor who put his name on this supremacist plan. &lt;a class="reversefootnote" href="#fnref:i-laughed-out-loud"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:racialized"&gt;
      &lt;p&gt;I don’t remember if I used the word ‘racialized origin’, which is technical and very specific, or if I used the phrase ‘race-based origin’. &lt;code class="language-plaintext highlighter-rouge"&gt;racialized&lt;/code&gt; means &lt;code class="language-plaintext highlighter-rouge"&gt;make racial in tone or character&lt;/code&gt;, and &lt;code class="language-plaintext highlighter-rouge"&gt;categorize or divide according to race.&lt;/code&gt;. It’s the same as enslaved, segregated, ghetto-ized, interred (internment camps), reserved (native people slaughtered and entrapped inside of reservations), it’s known to be what Very Bad People did in Eastern Europe in the 19th century. &lt;a class="reversefootnote" href="#fnref:racialized"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>Josh Thompson</author><pubDate>Mon, 17 Aug 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/full-copy-of-1922-atlanta-zone-plan</guid></item><item><title>Thank You TailwindCSS</title><link>https://www.brightball.com/articles/thank-you-tailwindcss</link><description>In the last 2-3 weeks, after seeing a lot of recommendations, I decided to read the Refactoring UI book and then dove into TailwindCSS. Design has always been a huge gap in my skillset. As frontend complexity increased over the last decade, it seemed less and less worth it to invest time to fill it. Then came TailwindCSS.</description><author>Brightball Articles</author><pubDate>Mon, 17 Aug 2020 14:50:18 GMT</pubDate><guid isPermaLink="true">https://www.brightball.com/articles/thank-you-tailwindcss</guid></item><item><title>How to change your day with meeting plans</title><link>https://ilearnt.com/blog/meetingplans/</link><description>&lt;p&gt;I recently had a day where I had about 10 different meetings - all on different subjects. I knew that I would struggle to be productive in each of them if I turned up for them unprepared and had to switch subjects each time.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Mon, 17 Aug 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/meetingplans/</guid></item><item><title>Events and callbacks in the Python language</title><link>https://nicolaiarocci.com/events-and-callbacks-in-the-python-language/</link><description>&lt;p&gt;So last week I got an email from my friend Michael Kennedy. Michael runs the
&lt;a href="https://training.talkpython.fm/"&gt;TalkPython Training&lt;/a&gt; website, arguably the best place where you can learn
Python today. He also hosts two popular Python podcasts: &lt;a href="https://talkpython.fm/"&gt;TalkPython&lt;/a&gt; and
&lt;a href="https://pythonbytes.fm/"&gt;PythonBytes&lt;/a&gt;, the latter co-hosted with Brian Okken. He is super active in
the Python space, so much that he received the Python Software Foundation
Fellow Membership back in 2018. I first met Michael back in 2014, I think, at
MongoDB Headquarters in New York, where we were both invited as part of the
MongoDB Masters program. We shared a C#/.NET background, which was something of
note in that context, and I remember Michael being curious about me embracing
Python and my first open-source release in that space. Fun times.&lt;/p&gt;</description><author>Nicola Iarocci</author><pubDate>Mon, 17 Aug 2020 08:05:25 GMT</pubDate><guid isPermaLink="true">https://nicolaiarocci.com/events-and-callbacks-in-the-python-language/</guid></item><item><title>How to build a snap using ROS 2 Foxy</title><link>https://kyrofa.com/posts/how-to-build-a-snap-using-ros-2-foxy/</link><description>The snapcraft CLI (the tool used to create snaps) has long had support for building snaps that use both ROS 1 and ROS 2. ROS 2 Foxy Fitzroy is the latest ROS 2 LTS, which runs on Ubuntu 20.04 (Focal Fossa). The snapcraft CLI recently gained experimental support for building Foxy snaps, so I wanted to walk you through doing exactly that with the goal of helping both of us: getting you familiar with this new feature, and at the same time getting some mileage on this so as to make it not experimental.</description><author>kyrofa's blog</author><pubDate>Mon, 17 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://kyrofa.com/posts/how-to-build-a-snap-using-ros-2-foxy/</guid></item><item><title>Wild Mushrooms in Lebanon</title><link>https://venam.net/blog/nature/2020/08/17/wild-mushrooms.html</link><description>Finally, The project about mapping wild mushrooms in Lebanon is out!  The project consists of a map with wild mushroom specimens, their locations, along with pictures and descriptions of them. It is based on the only two research papers on the topic I've found, Joseph Thiébaut research paper Champignons observés dans le Liban et la Syrie de 1930 à 1933 along with Nadine Modad research paper Survey and identification of wild mushrooms in Lebanon and my own research and findings over the past few years.  It took me around 2 months, or almost 15h to fill the map. These research papers have been my bedtime stories for quite a while.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Mon, 17 Aug 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/nature/2020/08/17/wild-mushrooms.html</guid></item><item><title>Searching code with Sourcegraph</title><link>https://lwn.net/Articles/828748/</link><description>A look at Sourcegraph, a code search and code intelligence tool (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Sun, 16 Aug 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/828748/</guid></item><item><title>The eyes to think about the world</title><link>https://ferrucc.io/posts/eyes/</link><description>&lt;p&gt;This is the world in the eyes of a dog&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://ferrucc.io/eyes/world-dog-eyes.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The poor things have such a cold experience of the world. Our eyes while giving us a richer experience of the world are also a limited mechanical tool.&lt;/p&gt;
&lt;p&gt;The world doesn&amp;rsquo;t care though. It stays the same regardless of the tools we use to perceive it - whether it&amp;rsquo;s the eyes of a dog or my presbyc ones.&lt;/p&gt;
&lt;p&gt;This sounds like stoner talk, but hear me out.&lt;/p&gt;</description><author>ferrucc.io</author><pubDate>Sun, 16 Aug 2020 18:46:44 GMT</pubDate><guid isPermaLink="true">https://ferrucc.io/posts/eyes/</guid></item><item><title>My first post</title><link>https://apurva-shukla.me/blog/my-first-post/</link><description>I’m learning React &amp; Gatsby’s framework all in one go in an effort to build my own personal website. I’m hoping for it to house my blog…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Sun, 16 Aug 2020 12:39:23 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/blog/my-first-post/</guid></item><item><title>Videoconferencing on FreeBSD</title><link>https://www.davidschlachter.com/misc/freebsd-videoconferencing</link><description>Support for videoconferencing platforms, like Zoom, Skype, and Teams, on FreeBSD.</description><author>David Schlachter</author><pubDate>Sun, 16 Aug 2020 06:41:00 GMT</pubDate><guid isPermaLink="true">https://www.davidschlachter.com/misc/freebsd-videoconferencing</guid></item><item><title>Trying out gccemacs on macOS</title><link>https://xenodium.com/trying-out-gccemacs-on-macos</link><description>&lt;p&gt;&lt;em&gt;UPDATE: I'm no longer using these steps. See &lt;a href="https://xenodium.com/emacs-plus-with-native-comp/"&gt;Emacs plus –with-native-comp&lt;/a&gt; for an easier alternative.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Below are the instructions I use to build Andrea Corallo's &lt;a href="http://akrl.sdf.org/gccemacs.html"&gt;gccemacs&lt;/a&gt; on macOS. It is based on &lt;a href="https://github.com/AllenDang"&gt;Allen Dang&lt;/a&gt;'s handy &lt;a href="https://gist.github.com/AllenDang/f019593e65572a8e0aefc96058a2d23e"&gt;instructions&lt;/a&gt; plus some changes of my own.&lt;/p&gt;
&lt;h2&gt;Install gcc and libgccjit via homebrew&lt;/h2&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;brew install gcc libgccjit
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Save configure script&lt;/h2&gt;
&lt;p&gt;Create configure-gccemacs.sh&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;#!/bin/bash

set -o nounset
set -o errexit

# Configures Emacs for building native comp support
# http://akrl.sdf.org/gccemacs.html

readonly GCC_DIR=&amp;quot;$(realpath $(brew --prefix libgccjit))&amp;quot;
[[ -d $GCC_DIR ]] ||  { echo &amp;quot;${GCC_DIR} not found&amp;quot;; exit 1; }

readonly SED_DIR=&amp;quot;$(realpath $(brew --prefix gnu-sed))&amp;quot;
[[ -d $SED_DIR ]] ||  { echo &amp;quot;${SED_DIR} not found&amp;quot;; exit 1; }

readonly GCC_INCLUDE_DIR=${GCC_DIR}/include
[[ -d $GCC_INCLUDE_DIR ]] ||  { echo &amp;quot;${GCC_INCLUDE_DIR} not found&amp;quot;; exit 1; }

readonly GCC_LIB_DIR=${GCC_DIR}/lib/gcc/10
[[ -d $GCC_LIB_DIR ]] ||  { echo &amp;quot;${GCC_LIB_DIR} not found&amp;quot;; exit 1; }

export PATH=&amp;quot;${SED_DIR}/libexec/gnubin:${PATH}&amp;quot;
export CFLAGS=&amp;quot;-O2 -I${GCC_INCLUDE_DIR}&amp;quot;
export LDFLAGS=&amp;quot;-L${GCC_LIB_DIR} -I${GCC_INCLUDE_DIR}&amp;quot;
export LD_LIBRARY_PATH=&amp;quot;${GCC_LIB_DIR}&amp;quot;
export DYLD_FALLBACK_LIBRARY_PATH=&amp;quot;${GCC_LIB_DIR}&amp;quot;

echo &amp;quot;Environment&amp;quot;
echo &amp;quot;-----------&amp;quot;
echo PATH: $PATH
echo CFLAGS: $CFLAGS
echo LDFLAGS: $LDFLAGS
echo DYLD_FALLBACK_LIBRARY_PATH: $DYLD_FALLBACK_LIBRARY_PATH
echo &amp;quot;-----------&amp;quot;

./autogen.sh

./configure \
     --prefix=&amp;quot;$PWD/nextstep/Emacs.app/Contents/MacOS&amp;quot; \
     --enable-locallisppath=&amp;quot;${PWD}/nextstep/Emacs.app/Contents/MacOS&amp;quot; \
     --with-mailutils \
     --with-ns \
     --with-imagemagick \
     --with-cairo \
     --with-modules \
     --with-xml2 \
     --with-gnutls \
     --with-json \
     --with-rsvg \
     --with-native-compilation \
     --disable-silent-rules \
     --disable-ns-self-contained \
     --without-dbus
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make it executable&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;chmod +x configure-gccemacs.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Clone Emacs source&lt;/h2&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;git clone --branch master https://github.com/emacs-mirror/emacs gccemacs
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Configure build&lt;/h2&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;cd gccemacs
../configure-gccemacs.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Native lisp compiler found?&lt;/h2&gt;
&lt;p&gt;Verify native lisp compiler is found:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-fundamental"&gt;Does Emacs have native lisp compiler?                   yes
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Build&lt;/h2&gt;
&lt;p&gt;Put those cores to use. Find out how many you got with:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;sysctl hw.logicalcpu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok so build with:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;make -j4 NATIVE_FAST_BOOT=1
cp -r lisp nextstep/Emacs.app/Contents/Resources/
cp -r native-lisp nextstep/Emacs.app/Contents
make install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Using &lt;em&gt;NATIVE_FAST_BOOT=1&lt;/em&gt; significantly improves build time (totalling between 20-30 mins, depending on your specs). Without it, the build can take &lt;strong&gt;hours&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The macOS app build (under nextstep/Emacs.app) is ready, but read on before launching.&lt;/p&gt;
&lt;h2&gt;Remove ~/emacs.d&lt;/h2&gt;
&lt;p&gt;You likely want to start with a clean install, byte-compiling all packages with the latest Emacs version. In any case, rename ~/emacs.d (for backup?) or remove ~/emacs.d.&lt;/p&gt;
&lt;h2&gt;init.el config&lt;/h2&gt;
&lt;p&gt;Ensure &lt;em&gt;exec-path&lt;/em&gt; includes the script's &amp;quot;–prefix=&amp;quot; value, &lt;em&gt;LIBRARY_PATH&lt;/em&gt; points to gcc's lib dir, and finally set &lt;em&gt;comp-deferred-compilation&lt;/em&gt;. I wrapped the snippet in my &lt;em&gt;exec-path-from-shell&lt;/em&gt; config, but setting early in init.el should be enough.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(use-package exec-path-from-shell
  :ensure t
  :config
  (exec-path-from-shell-initialize)
  (if (and (fboundp 'native-comp-available-p)
           (native-comp-available-p))
      (progn
        (message &amp;quot;Native comp is available&amp;quot;)
        ;; Using Emacs.app/Contents/MacOS/bin since it was compiled with
        ;; ./configure --prefix=&amp;quot;$PWD/nextstep/Emacs.app/Contents/MacOS&amp;quot;
        (add-to-list 'exec-path (concat invocation-directory &amp;quot;bin&amp;quot;) t)
        (setenv &amp;quot;LIBRARY_PATH&amp;quot; (concat (getenv &amp;quot;LIBRARY_PATH&amp;quot;)
                                       (when (getenv &amp;quot;LIBRARY_PATH&amp;quot;)
                                         &amp;quot;:&amp;quot;)
                                       ;; This is where Homebrew puts gcc libraries.
                                       (car (file-expand-wildcards
                                             (expand-file-name &amp;quot;~/homebrew/opt/gcc/lib/gcc/*&amp;quot;)))))
        ;; Only set after LIBRARY_PATH can find gcc libraries.
        (setq comp-deferred-compilation t))
    (message &amp;quot;Native comp is *not* available&amp;quot;)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Launch Emacs.app&lt;/h2&gt;
&lt;p&gt;You're good to go. Open Emacs.app via finder or shell:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;open nextstep/Emacs.app
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Deferred compilation logs&lt;/h2&gt;
&lt;p&gt;After setting &lt;em&gt;comp-deferred-compilation&lt;/em&gt; (in init.el config section), .elc files should be asyncronously compiled. Function definition should be updated to native compiled equivalent.&lt;/p&gt;
&lt;p&gt;Look out for an &lt;strong&gt;&lt;strong&gt;Async-native-compile-log&lt;/strong&gt;&lt;/strong&gt; buffer. Should have content like:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-fundamental"&gt;Compiling .emacs.d/elpa/moody-20200514.1946/moody.el...
Compiling .emacs.d/elpa/minions-20200522.1052/minions.el...
Compiling .emacs.d/elpa/persistent-scratch-20190922.1046/persistent-scratch.el...
Compiling .emacs.d/elpa/which-key-20200721.1927/which-key.el...
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Can also check for .eln files:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.bash"&gt;find ~/.emacs.d -iname *.eln | wc -l
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UPDATE1: Added &lt;em&gt;Symlink Emacs.app/Contents/eln-cache&lt;/em&gt; section for &lt;a href="http://akrl.sdf.org/gccemacs.html#org4b11ea1"&gt;update 11&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UPDATE2: Noted using NATIVE_FAST_BOOT makes the build much faster.&lt;/p&gt;
&lt;p&gt;UPDATE3: Removed symlinks and copied content instead. This simplifies things. Inspired by Ian Wahbe's &lt;a href="https://github.com/iwahbe/doom-config/blob/master/build-emacs.sh"&gt;build-emacs.sh&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UPDATE4: Removed homebrew recipe patching. Thanks to Dmitry Shishkin's &lt;a href="https://github.com/shshkn/emacs.d/blob/master/docs/nativecomp.md"&gt;instructions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;UPDATE5: Use new flag –with-native-compilation and master branch.&lt;/p&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 16 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/trying-out-gccemacs-on-macos</guid></item><item><title>A Daily Choice that Changes Everything</title><link>http://spirals.blog/articles/a-daily-choice/</link><description>&lt;p&gt;Early morning sunlight shone through the jungle’s canopy lighting the well trodden trail for Mani. It was a clear day with a soft, cool breeze blowing through the leaves, however Mani paid no attention to its beauty. He hated this track. Every day he would wake up at dawn and cart his heavy bag of fruits through the island’s jungle to trade in his neighbouring fishing village, and every night he would return. It was all Mani had ever known. His earliest memories were of him and his father making the journey each morning. Now Mani’s father was old and frail, and could no longer hold the bag of fruit on his back so Mani endured it alone.&lt;/p&gt;
&lt;p&gt;He had been hiking for a few hours when the trail took a veer to the left. Mani’s heart sunk. He dreaded this part of his day. The path descended deep down into jungle, growing darker and gloomier with each step he took. Trees pressed in closer with an eerie silence that sent chills down Mani’s spine, and the road ahead became rockier and dangerous to walk on. Once again, he was bombarded with a vanguard of mosquitos, ticks, and spiders, biting and frustrating him as he attempted to make his passage down the darkened path.&lt;/p&gt;
&lt;p&gt;After an hour or so, the sound of running water could be heard drawing nearer. Mani turned around a bend, and a small river flowed over his path. This was the worst part. He looked remorsefully at the stumps of the old bridge his father had built when Mani was a child. It had been lost by a flash flood one year in a terrible storm, and Mani did not have the skills to rebuild it, so he did what he did every day. He took off his shoes, rolled up his simple pants, and plunged into the icy waters. The current was strong today, and it was all Mani could manage not to lose his footing on the slippery rocks and be carried downstream. He clawed his way ever so slowly to the other bank, and heaved himself up the side muddying all his clothes and mood. He rested a few minutes to find his breath before continuing down his sombre road, soaking wet and miserable.&lt;/p&gt;
&lt;p&gt;As Mani sludged along his mind wandered into a daydream he often had. He did not have to walk the track twice a day, and instead could lay about on the beach drinking coconut milk, and eating fish. He could be carefree and peaceful and people would approach him and enjoy talking instead of ignoring him. There was no jungle to trek, no river to soak in, no heavy fruits to heave across the island, just a relaxed hammock on the warm, sunny sands.&lt;/p&gt;
&lt;p&gt;“Look, it’s Moody Mani!” The laughter of small children ripped Mani out of his dream, and back onto the road. Finally stepping out of the jungle and into a small clearing, he had arrived at the island’s other village only to be greeted (as per usual) with a torment of names and teasing from it’s youngsters.&lt;/p&gt;
&lt;p&gt;“Leave me alone! I do not want to be bothered today” Mani retorted. He was exhausted and the last thing on the whole island he wanted was to fend off these brats.&lt;/p&gt;
&lt;p&gt;“What’s the matter? Did the monkeys through poo at you again?” one jeered, and they all burst into laughter.&lt;/p&gt;
&lt;p&gt;“My daddy says he has a banana for a brain!” jibed another.&lt;/p&gt;
&lt;p&gt;“Banana brain, banana brain! Moody Mani’s a banana brain!” they chanted, and Mani’s temper got the better of him.&lt;/p&gt;
&lt;p&gt;“ENOUGH!” he commanded, and the children scattered, giggling back to their huts and the safety of their mothers.&lt;/p&gt;
&lt;p&gt;“Maybe I do have a banana brian,” Mani thought as he slumped over to the small market and setup his fruit, “After all, I never seem to do anything other than carry this stupid fruit, back and forth, every day”. He had developed quite a reputation on the island for being irritable and foul tempered, which certainly did not help in the market. The village people tended to avoid him and preferred trading their fruit with others who were more cheery. Mani was saddened by the loneliness of the market, kept company only by the odd monkey attempting to steal his fruit. Everywhere he looked he was greeted with disapproving looks, scowls, or was just ignored completely.&lt;/p&gt;
&lt;p&gt;He remembered his father selling fruit here all those years ago. People flocked to Mani’s dad everyday to greet him and see what new fruits he had brought. There would be many regulars that returned and talked for hours, sharing stories and personal problems with him. His dad always smiled and greeted every customer with a warm hello. They would always travel back home with empty bags having sold all their fruit to the excited village. Now, nobody came to talk with Mani. He finished the day having sold only a few coconuts, and set out to lug the heavy bag home.&lt;/p&gt;
&lt;p&gt;The journey back was more dangerous, as Mani could not see clearly in the dark jungle, and there was the chance of running into a large wildcat. He dreaded the disappointment on his family’s faces when he returned next to empty handed for his days work. He hated letting them down. The shadow of his father’s successful trading business loomed over him, but he had no idea how to match him. He was just unlucky and disliked. Some people are born with the ability to be happy, and some just are not. Mani had come to terms with that. He reached home and collapsed on his straw bed, drained from all the hiking. The children’s taunts ran over in his mind, and he fell asleep to a sad chorus of “Banana brain, banana brain…”&lt;/p&gt;
&lt;p&gt;&lt;img alt="Look up" src="http://spirals.blog/articles/a-daily-choice/trees.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;“Wake up sleepy!” Mani’s little brother, Ina, jumped up and down on the end of his bed, a bundle of excitement. Mani groaned, and awoke rubbing his eyes. “Tata says I am to go with you to the other village today. He says I am to learn how to fish from the men there!” he squealed. Mani envied his younger brother. Ina spent most of his time exploring, adventuring, and learning. He always appeared happy, and full of life. It cheered him up when he was around.&lt;/p&gt;
&lt;p&gt;“Are you sure? It is a long journey,” Mani warned, slipping on his damp shoes, “I am not going to carry you.”&lt;/p&gt;
&lt;p&gt;“Don’t worry, I can walk around the whole island twice in a day!” Ina said triumphantly. Mani laughed, he would enjoy his brothers company today.&lt;/p&gt;
&lt;p&gt;The pair set off into the jungle after a quick breakfast, Ina bounding in front, inspecting all the trees and bugs with youthful fascination. Mani often wondered why he also had not been passed his brothers enthusiasm for life from his parents. “It is not fair” he thought, “I work hard, I deserve to be happy.”&lt;/p&gt;
&lt;p&gt;They soon reached the veer in the road, leading down into depths of the jungle. Mani whined, “I hate this part” glad that he could share his discomfort with someone else. Ina looked back, puzzled.&lt;/p&gt;
&lt;p&gt;“What do you mean?”&lt;/p&gt;
&lt;p&gt;“It gets all dark and morbid down there, and I have to swim through the river. All the bugs bite me, and come out all itchy and wet.” Mani continued.&lt;/p&gt;
&lt;p&gt;“Well why don’t you take a different path?” Ina replied.&lt;/p&gt;
&lt;p&gt;Mani did not understand. “I have always taken this path. It is the one Tata showed me when I was your age. It is what we always do. It is the path.”&lt;/p&gt;
&lt;p&gt;“So?” Ina questioned, “Do you like that path?” He grabbed a branch from a tree, and snapped it off.&lt;/p&gt;
&lt;p&gt;“What are you doing?” Mani asked, unsure of where this was going. Ina ignored him and started smashing vines and plants. “Stop! This way is already well trodden. That is not the right way!”&lt;/p&gt;
&lt;p&gt;“How do you know,” Ina asked, grinning, “If you have never been this way before?” Mani was terrified. He could not walk off the track. It was dangerous. What if they got lost? How would they find their way back again? They could end up in a ditch, or a dead end. Even worse, they could fall off a cliff. Ina seemed uninterested, and continued to push through the jungle.&lt;/p&gt;
&lt;p&gt;Main followed after him, “Do you even know where you are going?” This seemed ridiculous. The branches and twigs scratched him as he made after his brother. “Stop! Where are you going? I would rather go this way, it is familiar. We know where this goes. I do not really mind the river, I was just complaining. Stop!”&lt;/p&gt;
&lt;p&gt;“Oh relax you big wuss! Let’s try something different. Trust me.” Ina pressed on. Mani did not like this at all, but there was no stopping his determined little brother, and he did not want to leave him alone in the jungle. They walked for hours, Ina in front with his stick, making a path for Mani to follow, all the while heading steadily up. Ina never looked back once, and Mani thought he even seemed to be enjoying it. Mani however could not understand and grew more frightened with every step.&lt;/p&gt;
&lt;p&gt;The jungle grew lighter and thinner the higher they rose, and soon they could see large patches of blue sky shining between the treetops. The pack on Mani’s back was wearing him down, and he was considering turning back when they reached the summit. They had climbed on top the dormant volcano that comprised the larger part of the island. Mani stood in awe. He had never seen anything so beautiful in his life. Before him in the clearing he could see the whole island below in every way he turned. The blue sea stretched out in the distance, covering the world in a shimmering blue sheet.&lt;/p&gt;
&lt;p&gt;“I told you to trust me” Ina remarked. Mani was speechless. He had no idea that the world held such remarkable beauty. He sat down on a small boulder, and a sense of peace washed over him as he stared out over his home. “How could I have missed this all along?” he thought, “I had no idea this even existed”. They both sat eating the fruit for a while, taking in the view. Something moved in Mani. A small glimmer of hope that maybe life was not so gloomy as he had made it out to be.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The Top" src="http://spirals.blog/articles/a-daily-choice/the-top.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;“Let’s keep going” Ina said after some time, throwing his banana peels into a bush, and they resumed their hike down the volcano. It was easier going down. Mani did not notice the cuts and bruises anywhere near as much as before. His pack felt lighter and little details of the jungle he had never noticed before now seemed so vivid. The tiny flowers, colourful birds, and the wash of the gentle breeze all felt new to him, as if he had never walked through the jungle in his life. Time flew by with Mani and Ina chatting about what learning to fish would be like and before he knew they had made it to the neighbouring village in no time.&lt;/p&gt;
&lt;p&gt;The fishing village was alive today, and once again the children came running up to them, joking and taunting Mani as usual, but something was different. The names did not sink in like they used to, and the chants grew boring. The children grew tiresome and left Mani and Ina alone. He was off to a good start. Ina helped Mani setup his fruit, and shouting out what they had to offer to anybody who would listen. They had soon amassed a small crowd of passersby, and Mani chatted to them all pleasantly, telling everyone of the beautiful views atop the volcano. He was buzzing. With Ina’s help and Mani’s good mood, they sold out of all the fruit for the first time since their dad had ventured across the island. Mani left his brother, and proudly marched back to the forest to tell his family.&lt;/p&gt;
&lt;p&gt;The fork faced him at the jungles entrance. With Ina now no longer by his side, the new path to his left felt daunting. He was still sore from all the scratches and bruises and his clothes had been ripped from the morning’s exploration. To the right, the old path that was so familiar winded down into the dark. He knew exactly what was down that road. Mani stood there contemplating his options, and decided he had had enough. He was no longer going to take the miserable path just because it was easier. He did not want people to tease him anymore, or call him ‘Moody Mani’. He wanted everyone to respect him like his father. He would show them. He grabbed a stick, and went left up the volcano. It was tough. The jungle clutched on to him as he forced his way upwards as if to mock his attempts and deter him. “Just keep going” Mani heard his little brothers voice coaxing him on. He wanted to quit. His mind begged him to turn back down the easier road. Mani pressed on.&lt;/p&gt;
&lt;p&gt;The moon was high in the sky by the time Mani reached the top for the second time that day. This was getting easier. The island looked very different at night, but just as beautiful. He was glad he took this route. He descended back into the jungle and made his way home, the view still fixed in his mind.&lt;/p&gt;
&lt;p&gt;The next day, Mani was faced with the same choice, and the day after that, and so on for months. Each passing day he chose his new path, and his mood lightened. It grew easier the more he trod on it and a road began to form. The children no longer greeted him with rude names but rather asked him to share his stories of the jungle. The villages now eagerly awaited him each day to see what he had brought for them. He would often visit his brother after he had finished at the market and Ina would tell him what he had learnt that day.&lt;/p&gt;
&lt;p&gt;“I’m proud of you,” Ina said one afternoon as they were sitting by the beach, “I know how hard it was for you to follow me that morning. You kept going too. I’m glad you did”.&lt;/p&gt;
&lt;p&gt;“I am too” Mani replied, and he truly was. Everything had changed for him and that night on his journey home, he returned to the old path as it veered to the left. Despite all efforts to search for it he could not see the road anywhere. The jungle had consumed it, left it overgrown, never to be walked on again. Unfazed, Mani left it alone, smiling, and never once looked back.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The End" src="http://spirals.blog/articles/a-daily-choice/the-end.jpg" /&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 16 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/a-daily-choice/</guid></item><item><title>Factorio and Software Engineering</title><link>https://nindalf.com/posts/factorio-and-software-engineering/</link><description>How playing the game Factorio reminds me of software engineering, from managing complexity to teamwork and automation</description><author>Krishna's blog</author><pubDate>Sun, 16 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nindalf.com/posts/factorio-and-software-engineering/</guid></item><item><title>Open does not always mean Open Source</title><link>https://jasoneckert.github.io/myblog/open-does-not-always-mean-open-source/</link><description>&lt;p&gt;&lt;img alt="Open Source vs Open standards" src="open.jpg#right" title="Open Source vs Open standards" /&gt;&lt;/p&gt;
&lt;p&gt;In the technology world today, the term &lt;em&gt;&lt;strong&gt;Open&lt;/strong&gt;&lt;/em&gt; is most commonly associated with &lt;em&gt;&lt;strong&gt;Open Source&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Open Source refers to software released under a license that gives other software developers access to modify the original Source code that was used to create the software. This, in turn allows other software developers worldwide to quickly identify and fix bugs and security loopholes, as well as make feature improvements to the software. Consequently, Open Source software evolves more rapidly than other (&lt;em&gt;&lt;strong&gt;Closed Source&lt;/strong&gt;&lt;/em&gt;) software, and is considered the gold standard for software today.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Sun, 16 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/open-does-not-always-mean-open-source/</guid></item><item><title>Writing a simple Python compiler: 1. hello, fibonacci</title><link>http://notes.eatonphil.com/writing-a-simple-python-compiler.html</link><description>&lt;p&gt;In this post we'll write a Python to C compiler in Python. This is
especially easy to do since Python has a &lt;a href="https://docs.python.org/3/library/ast.html"&gt;builtin parser
library&lt;/a&gt; and because a
number of &lt;a href="https://docs.python.org/3/c-api/"&gt;CPython internals are exposed for extension
writers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By the end of this post, in a few hundred lines of Python, we'll be able to
compile and run the following program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;cat&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;recursive_fib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;python3&lt;/span&gt; &lt;span class="n"&gt;pyc&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;recursive_fib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;
&lt;span class="mi"&gt;102334155&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This post implements an extremely small subset of Python and
&lt;strong&gt;completely gives up on even trying to manage memory&lt;/strong&gt; because I
cannot fathom manual reference counting. Maybe some day I'll find a
way to swap in an easy GC like Boehm.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/eatonphil/pyc"&gt;Source code for this project is available on Github.&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="dependencies"&gt;Dependencies&lt;/h3&gt;&lt;p&gt;We'll need Python3, GCC, libpython3, and clang-format.&lt;/p&gt;
&lt;p&gt;On Fedora-based systems:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;dnf&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;python3-devel&lt;span class="w"&gt; &lt;/span&gt;clang-format&lt;span class="w"&gt; &lt;/span&gt;python3
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And on Debian-based systems:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;python3-dev&lt;span class="w"&gt; &lt;/span&gt;clang-format&lt;span class="w"&gt; &lt;/span&gt;python3
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  This program will likely work as well on Windows, Mac, FreeBSD,
  etc. but I haven't gone through the trouble of testing this (or
  providing custom compiler directives). Pull requests welcome!
&lt;/p&gt;&lt;h3 id="a-hand-written-first-pass"&gt;A hand-written first-pass&lt;/h3&gt;&lt;p&gt;Before we get into the compiler, let's write the fibonacci program by
hand in C using libpython.&lt;/p&gt;
&lt;p&gt;As described in the &lt;a href="https://docs.python.org/3/extending/embedding.html#very-high-level-embedding"&gt;Python embedding
guide&lt;/a&gt;
we'll need to include libpython and initialize it in
our &lt;code&gt;main.c&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#define PY_SSIZE_T_CLEAN&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;Python.h&amp;gt;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Py_Initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To compile against libpython, we'll use
&lt;a href="https://helpmanual.io/man1/python3-config/"&gt;python3-config&lt;/a&gt; installed
as part of &lt;code&gt;python3-devel&lt;/code&gt; to tell us what should be linked
at each step during compilation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main.o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;python3-config&lt;span class="w"&gt; &lt;/span&gt;--cflags&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;main.c
$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;python3-config&lt;span class="w"&gt; &lt;/span&gt;--ldflags&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;main.o
$&lt;span class="w"&gt; &lt;/span&gt;./a.out&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cool! Now as we think about translating the fibonacci implementation,
we want to keep everything as Python objects for as long as
possible. This means passing and receiving
&lt;a href="https://docs.python.org/3/c-api/object.html"&gt;PyObject*&lt;/a&gt; to and from
all functions, and converting all C integers to
&lt;a href="https://docs.python.org/3/c-api/long.html"&gt;PyLong*&lt;/a&gt;, a "subtype" of
&lt;code&gt;PyObject*&lt;/code&gt;. You can imagine that everything in Python is
an &lt;code&gt;object&lt;/code&gt; until you operate on it.&lt;/p&gt;
&lt;p class="note"&gt;
  For more information on objects in Python, check out
  the &lt;a href="https://docs.python.org/3/reference/datamodel.html"&gt;Data
  model&lt;/a&gt; page in Python docs.
&lt;/p&gt;&lt;p&gt;To map a C integer to a &lt;code&gt;PyLong*&lt;/code&gt; we use
&lt;a href="https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong"&gt;PyLong_FromLong&lt;/a&gt;. To
map in reverse, we use
&lt;a href="https://docs.python.org/3/c-api/long.html#c.PyLong_AsLong"&gt;PyLong_AsLong&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To compare two &lt;code&gt;PyObject*&lt;/code&gt;s we can use
&lt;a href="https://docs.python.org/3/c-api/object.html#c.PyObject_RichCompareBool"&gt;PyObject_RichCompareBool&lt;/a&gt;
which will handle the comparison regardless of the type of the two
parameters. Without this helper we'd have to write complex checks to
make sure that the two sides are the same and if they are, unwrap them
into their underlying C value and compare the C value.&lt;/p&gt;
&lt;p&gt;We can use
&lt;a href="https://docs.python.org/3/c-api/number.html#c.PyNumber_Add"&gt;PyNumber_Add&lt;/a&gt;
and
&lt;a href="https://docs.python.org/3/c-api/number.html#c.PyNumber_Subtract"&gt;PyNumber_Subtract&lt;/a&gt;
for basic arithmetic, and there are many similar helpers available to
us for operations down the line.&lt;/p&gt;
&lt;p&gt;Now we can write a translation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#define PY_SSIZE_T_CLEAN&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;Python.h&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyLong_FromLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyLong_FromLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject_RichCompareBool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Py_EQ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject_RichCompareBool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Py_EQ&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyNumber_Subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyLong_FromLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyNumber_Subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;two&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyNumber_Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Py_Initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyLong_FromLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Should be 13&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyLong_AsLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Compile and run it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;main.o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;python3-config&lt;span class="w"&gt; &lt;/span&gt;--cflags&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;main.c
$&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;python3-config&lt;span class="w"&gt; &lt;/span&gt;--ldflags&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;main.o
$&lt;span class="w"&gt; &lt;/span&gt;./a.out&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="m"&gt;13&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's great! But we cheated in one place. We assumed that the input
to the &lt;code&gt;fib&lt;/code&gt; function was an integer, and we propagated
that assumption everywhere we wrote &lt;code&gt;PyNumber_*&lt;/code&gt;
operations. When we write the compiler, we'll need to check that both
arguments are an integer before we call a numeric helper, otherwise we
may need to call a string concatenation helper or something else
entirely.&lt;/p&gt;
&lt;h3 id="compiler-architecture"&gt;Compiler Architecture&lt;/h3&gt;&lt;p&gt;We'll break the code into four major parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;libpyc.c&lt;/code&gt;: helper functions for generated code&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pyc/context.py&lt;/code&gt;: utilities for scope and writing code in memory&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pyc/codegen.py&lt;/code&gt;: for generating C code from a Python AST&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pyc/__main__.py&lt;/code&gt;: the entrypoint&lt;/li&gt;
&lt;/ol&gt;
&lt;p class="note"&gt;
  When I'm writing a new compiler using an existing parser I almost
  always start with the entrypoint and code generator so I can explore
  the AST. However, it's easiest to explain the code if we start with
  the utilities first.
&lt;/p&gt;&lt;p&gt;We'll also want an empty &lt;code&gt;pyc/__init__.py&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="libpyc.c"&gt;libpyc.c&lt;/h3&gt;&lt;p&gt;This C file will contain three helper functions for safely adding,
subtracting, and printing. It will be concatenated to the top of the
generated C file. We'll only support integers for now but this
structure sets us up for supporting more types later on.&lt;/p&gt;
&lt;p&gt;We'll use
&lt;a href="https://docs.python.org/3/c-api/long.html#c.PyLong_Check"&gt;PyLong_Check&lt;/a&gt;
before calling number-specific methods.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;#define PY_SSIZE_T_CLEAN&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;Python.h&amp;gt;&lt;/span&gt;

&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;PYC_Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// TODO: allow __add__ override&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Includes ints and bools&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyLong_Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyLong_Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyNumber_Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// TODO: handle str, etc.&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// TODO: throw exception&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;PYC_Sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// TODO: allow __add__ override&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Includes ints and bools&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyLong_Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyLong_Check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyNumber_Subtract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// TODO: handle str, etc.&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// TODO: throw exception&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;inline&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;PYC_Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;PyObject_Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Py_PRINT_RAW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Py_None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it! We could generate these as strings in Python but it gets
hairy to do so. By using a dedicated C file, we can take advantage of
syntax highlighting since this file is only C code. And since we've
marked all functions as &lt;code&gt;inline&lt;/code&gt;, there's no runtime cost
to using not embedding these as strings in Python.&lt;/p&gt;
&lt;h3 id="pyc/context.py"&gt;pyc/context.py&lt;/h3&gt;&lt;p&gt;This file will contain a &lt;code&gt;Context&lt;/code&gt; class for managing
identifiers in scope and for proxying to a &lt;code&gt;Writer&lt;/code&gt; class
that contains helpers for writing lines of C code.&lt;/p&gt;
&lt;p&gt;We'll have two instances of the &lt;code&gt;Writer&lt;/code&gt; class in
&lt;code&gt;Context&lt;/code&gt; so that we can write to a body (or
current/primary) region and an initialization region.&lt;/p&gt;
&lt;p&gt;The initialization region is necessary in case there are any variables
declared at the top-level. We can't initialize these variables in C
outside of a function since every &lt;code&gt;PyObject*&lt;/code&gt; must be
created after calling &lt;code&gt;Py_Initialize&lt;/code&gt;. This section will be
written into our C &lt;code&gt;main&lt;/code&gt; function before we enter a
compiled Python &lt;code&gt;main&lt;/code&gt; function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;copy&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;  &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;initializations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;indentation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;namings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Helpers to avoid passing in self.indentation every time&lt;/span&gt;
        &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;initializations&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indentation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__getattr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;source_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;source_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register_global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tmp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="c1"&gt;# naming dictionary is copied, so we need to capture scope&lt;/span&gt;
            &lt;span class="c1"&gt;# at declaration&lt;/span&gt;
            &lt;span class="s2"&gt;&amp;quot;scope&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# For some reason copy.deepcopy doesn't do this&lt;/span&gt;
        &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;at_toplevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is all pretty boring boilerplate. Let's move on.&lt;/p&gt;
&lt;h3 id="pyc/&amp;lt;strong&amp;gt;main&amp;lt;/strong&amp;gt;.py"&gt;pyc/&lt;strong&gt;main&lt;/strong&gt;.py&lt;/h3&gt;&lt;p&gt;The entrypoint is responsible for reading source code, parsing it,
calling the code generator, writing the source code to a C file, and
compiling it.&lt;/p&gt;
&lt;p&gt;First, we read and parse the source code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ast&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;shutil&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;codegen&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;

&lt;span class="n"&gt;BUILTINS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;print&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;PYC_Print&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then we write &lt;code&gt;libpyc.c&lt;/code&gt; into the body, register builtins,
and run code generation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;libpyc.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;BUILTINS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we create a clean output directory and write
&lt;code&gt;main.c&lt;/code&gt; with the generated code and a &lt;code&gt;main&lt;/code&gt;
function to initialization Python and any global variables:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
   &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="c1"&gt;# Create and move to working directory&lt;/span&gt;
    &lt;span class="n"&gt;outdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bin&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rmtree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ignore_errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;int main(int argc, char *argv[]) &lt;/span&gt;&lt;span class="se"&gt;{{&lt;/span&gt;
&lt;span class="s2"&gt;  Py_Initialize();&lt;/span&gt;

&lt;span class="s2"&gt;  // Initialize globals, if any.&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initializations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="s2"&gt;  PyObject* r = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;();&lt;/span&gt;
&lt;span class="s2"&gt;  return PyLong_AsLong(r);&lt;/span&gt;
&lt;span class="se"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we run &lt;code&gt;clang-format&lt;/code&gt; and &lt;code&gt;gcc&lt;/code&gt; against
the generated C code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;clang-format&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-i&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;main.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;cflags_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;--cflags&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;cflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cflags_raw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;gcc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-o&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;main.o&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cflags&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ldflags_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;--ldflags&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ldflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ldflags_raw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;gcc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ldflags&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main.o&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All together:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ast&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;shutil&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;codegen&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt;

&lt;span class="n"&gt;BUILTINS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;print&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;PYC_Print&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;libpyc.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;BUILTINS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builtin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create and move to working directory&lt;/span&gt;
    &lt;span class="n"&gt;outdir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bin&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rmtree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ignore_errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outdir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;w&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;namings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;int main(int argc, char *argv[]) &lt;/span&gt;&lt;span class="se"&gt;{{&lt;/span&gt;
&lt;span class="s2"&gt;  Py_Initialize();&lt;/span&gt;

&lt;span class="s2"&gt;  // Initialize globals, if any.&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initializations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="s2"&gt;  PyObject* r = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;();&lt;/span&gt;
&lt;span class="s2"&gt;  return PyLong_AsLong(r);&lt;/span&gt;
&lt;span class="se"&gt;}}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;clang-format&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-i&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;main.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;cflags_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;--cflags&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;cflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cflags_raw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;gcc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-o&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;main.o&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;cflags&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main.c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ldflags_raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;python3-config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;--ldflags&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ldflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ldflags_raw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
    &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;gcc&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ldflags&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main.o&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Done!&lt;/p&gt;
&lt;h3 id="pyc/codegen.py"&gt;pyc/codegen.py&lt;/h3&gt;&lt;p&gt;Lastly we write the translation layer from Python AST to C. We'll
break this out into 10 helper functions. It is helpful to have the
&lt;a href="https://docs.python.org/3/library/ast.html#abstract-grammar"&gt;AST
spec&lt;/a&gt; for
reference.&lt;/p&gt;
&lt;h4 id="1/10:-generate"&gt;1/10: generate&lt;/h4&gt;&lt;p&gt;The entrypoint of the code generator is &lt;code&gt;generate(ctx: Context,
exp)&lt;/code&gt;. It generates code for any object with a &lt;code&gt;body&lt;/code&gt;
attribute storing a list of statements. This function will generate
code for objects like modules, function bodies, if bodies, etc.&lt;/p&gt;
&lt;p&gt;The statements we'll support to begin are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ast.Assign&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ast.FunctionDef&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ast.Return&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ast.If&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;and &lt;code&gt;ast.Expr&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For each statement, we'll simply pass on generation to an associated
helper function. In the case of expression generation though, we'll
also add a noop operation on the result of the expression otherwise
the compiler will complain about an unused variable.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Assign&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;generate_assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FunctionDef&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;generate_function_def&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;generate_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;If&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;generate_if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Expr&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;// noop to hide unused warning&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; += 0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unsupported statement type: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  Remember to throw exceptions aggressively otherwise you'll have a
  bad time debugging programs using new syntax.
&lt;/p&gt;&lt;p&gt;Let's dig into these helpers.&lt;/p&gt;
&lt;h4 id="2/10:-generate_assign"&gt;2/10: generate_assign&lt;/h4&gt;&lt;p&gt;To generate assignment code, we need to check if we're at the
top-level or not. If we're at the top-level we can declare the
variable but we can't initialize it yet. So we add the initialization
code to the &lt;code&gt;initialization&lt;/code&gt; section of the program.&lt;/p&gt;
&lt;p&gt;If we're not at the top-level, we can declare and assign in one
statement.&lt;/p&gt;
&lt;p&gt;Before doing either though, we register the variable name so we can
get a safe local name to use in generated code. Then we compile the
right-hand side so we can assign it to the left-hand side.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;ast&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;context&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at_toplevel&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;decl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initializations_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Assign&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO: support assigning to a tuple&lt;/span&gt;
    &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;initialize_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We're going to need to implement &lt;code&gt;generate_expression&lt;/code&gt; to
make this work.&lt;/p&gt;
&lt;h4 id="3/10:-generate_expression"&gt;3/10: generate_expression&lt;/h4&gt;&lt;p&gt;Just like for statements in &lt;code&gt;generate&lt;/code&gt;, there are a few
kinds of expressions we need to implement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ast.Num&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ast.BinOp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ast.BoolOp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ast.Name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ast.Compare&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;and &lt;code&gt;ast.Call&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For &lt;code&gt;ast.Num&lt;/code&gt;, we just need to wrap the literal number as a
&lt;code&gt;PyLong*&lt;/code&gt;. And for &lt;code&gt;ast.Name&lt;/code&gt; we just need to
look up the local name in context. Otherwise we delegate to more
helper functions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Num&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# TODO: deal with non-integers&lt;/span&gt;
        &lt;span class="n"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;num&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;initialize_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyLong_FromLong(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tmp&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinOp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;generate_bin_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoolOp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;generate_bool_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compare&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;generate_compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;generate_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unsupported expression: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For every code generation helper that is an expression, we store the
expression in a local variable and return the variable's name so that
parent nodes in the AST can refer to the child. This can result in
inefficient code generation (useless assignment) but that's not really
a big deal for a project like this and will likely be optimized away
by GCC anyway. The more annoying aspect is that useless assignment
just makes the generated code harder to read.&lt;/p&gt;
&lt;h4 id="4/10:-generate_bin_op"&gt;4/10: generate_bin_op&lt;/h4&gt;&lt;p&gt;For binary operators we need to support addition and
subtraction. Other binary operators like equality or and/or are
represented in &lt;code&gt;ast.Compare&lt;/code&gt; and &lt;code&gt;ast.BoolOp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is easy to write because we already prepared helpers in
&lt;code&gt;libpyc.c&lt;/code&gt;: &lt;code&gt;PYC_Sub&lt;/code&gt; and &lt;code&gt;PYC_Add&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_bin_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinOp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;binop&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = PYC_Add(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sub&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = PYC_Sub(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unsupported binary operator: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Easy enough.&lt;/p&gt;
&lt;h4 id="5/10:-generate_bool_op"&gt;5/10: generate_bool_op&lt;/h4&gt;&lt;p&gt;We only need to support &lt;code&gt;or&lt;/code&gt; for the fibonacci program, but
&lt;code&gt;or&lt;/code&gt; in Python is more complicated than in C. In Python,
the first value to be truthy short-circuits the expression and the
result is its value, not &lt;code&gt;True&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We'll use &lt;code&gt;goto&lt;/code&gt; to short-circuit and we'll use
&lt;a href="https://docs.python.org/3/c-api/object.html#c.PyObject_IsTrue"&gt;PyObject_IsTrue&lt;/a&gt;
to do the truthy check:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_bool_op&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boolop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoolOp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;boolop&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boolop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;done_or&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;done_or&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;boolop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;if (PyObject_IsTrue(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)) &lt;/span&gt;&lt;span class="se"&gt;{{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;goto &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;done_or&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indentation&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;done_or&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p class="note"&gt;
  Now that I write this down I see we could probably move this
  function into &lt;code&gt;libpyc.c&lt;/code&gt; if we used a loop. Maybe in
  the next iteration.
&lt;/p&gt;&lt;p&gt;We move on.&lt;/p&gt;
&lt;h4 id="6/10:-generate_compare"&gt;6/10: generate_compare&lt;/h4&gt;&lt;p&gt;This function handles equality and inequality checks. We'll adapt the
&lt;code&gt;PyObject_RichCompareBool&lt;/code&gt; helper we used in the
hand-written translation.&lt;/p&gt;
&lt;p&gt;The only additional thing to keep in mind is that the right-hand side
is passed as an array. So we have to iterate through it and apply the
equality/inequality check on all objects in the list.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compare&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;compare&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comparators&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = PyObject_RichCompare(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Py_EQ)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotEq&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = PyObject_RichCompare(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, Py_NE)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unsupported comparison: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="7/10:-generate_call"&gt;7/10: generate_call&lt;/h4&gt;&lt;p&gt;The last expression is simple enough. We compile the call's arguments
first, then the function itself, then we call the function with the
arguments like any C function. Calling the C function directly will
have ramifications for interacting with Python libraries (basically,
we won't be able to interact with any) but it's the easiest way to get
started.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;call_result&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# TODO: lambdas and closures need additional work&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that's it for expressions! Just a few more statement helpers to
support.&lt;/p&gt;
&lt;h4 id="8/10:-generate_function_def"&gt;8/10: generate_function_def&lt;/h4&gt;&lt;p&gt;This is a fun one. First we register the function name in scope. Then
we copy the context so variables within the function body are
contained within the function body. We increment &lt;code&gt;scope&lt;/code&gt; so
we know we've left the top-level. Finally, we compile the body.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_function_def&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FunctionDef&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;childCtx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;childCtx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_local&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;PyObject* &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) &lt;/span&gt;&lt;span class="se"&gt;{{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;childCtx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;childCtx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indentation&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;childCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;childCtx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;childCtx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;return Py_None&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The check for &lt;code&gt;childCtx.ret&lt;/code&gt; isn't strictly necessary
because we could just emit a return even if there already was
one. Asking &lt;code&gt;generate_return&lt;/code&gt; to set this attribute and
having &lt;code&gt;generate_function_def&lt;/code&gt; check it just makes the
generate code a little prettier.&lt;/p&gt;
&lt;h4 id="9/10:-generate_return"&gt;9/10: generate_return&lt;/h4&gt;&lt;p&gt;Very straightforward, we just compile the value to be returned and
then we emit a &lt;code&gt;return&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;We store the return value so that the function definition can know
whether to add a &lt;code&gt;return PyNone&lt;/code&gt; statement.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_write_statement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;return &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we've got one last statement to support!&lt;/p&gt;
&lt;h4 id="10/10:-generate_if"&gt;10/10: generate_if&lt;/h4&gt;&lt;p&gt;You know the deal: compile the test and if the test is truthy, enter
the compiled body. We'll deal with the else body another time.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;If&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_expression&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;if (PyObject_IsTrue(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)) &lt;/span&gt;&lt;span class="se"&gt;{{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indentation&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# TODO: handle exp.orelse&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indentation&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body_writeln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we're done the compiler!&lt;/p&gt;
&lt;h3 id="trying-it-out"&gt;Trying it out&lt;/h3&gt;&lt;p&gt;As promised:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;tests/recursive_fib.py
def&lt;span class="w"&gt; &lt;/span&gt;fib&lt;span class="o"&gt;(&lt;/span&gt;n&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;n

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;fib&lt;span class="o"&gt;(&lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+&lt;span class="w"&gt; &lt;/span&gt;fib&lt;span class="o"&gt;(&lt;/span&gt;n&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;


def&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="o"&gt;()&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;print&lt;span class="o"&gt;(&lt;/span&gt;fib&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;python3&lt;span class="w"&gt; &lt;/span&gt;pyc&lt;span class="w"&gt; &lt;/span&gt;tests/recursive_fib.py
$&lt;span class="w"&gt; &lt;/span&gt;./bin/a.out
&lt;span class="m"&gt;102334155&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h4 id="microbenchmarking,-or-making-compiler-twitter-unhappy"&gt;Microbenchmarking, or making compiler Twitter unhappy&lt;/h4&gt;&lt;p&gt;Keep in mind this implementation does a small fraction of what CPython
is doing.&lt;/p&gt;
&lt;p&gt;If you time the generated code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;python3&lt;span class="w"&gt; &lt;/span&gt;pyc&lt;span class="w"&gt; &lt;/span&gt;tests/recursive_fib.py
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;./bin/a.out
&lt;span class="m"&gt;102334155&lt;/span&gt;
./bin/a.out&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.69s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.03s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.854&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And CPython (with &lt;code&gt;main()&lt;/code&gt; append to the source):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python3&lt;span class="w"&gt; &lt;/span&gt;tests/recursive_fib.py
&lt;span class="m"&gt;102334155&lt;/span&gt;
python3&lt;span class="w"&gt; &lt;/span&gt;tests/recursive_fib.py&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;76&lt;/span&gt;.24s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.11s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:16.81&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only reason I mention this is because when I did a &lt;a href="/compiling-dynamic-programming-languages.html#next-steps-with-jsc"&gt;similar
compiler project for JavaScript targeting
C++/libV8&lt;/a&gt;,
the generated code was about the same or a little slower in speed.&lt;/p&gt;
&lt;p&gt;I haven't gotten &lt;em&gt;that much&lt;/em&gt; better at writing these compilers.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Latest post up, on writing a simple Python to C compiler (in Python).&lt;a href="https://t.co/4kkji0XXbp"&gt;https://t.co/4kkji0XXbp&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1295134027335204865?ref_src=twsrc%5Etfw"&gt;August 16, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 16 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/writing-a-simple-python-compiler.html</guid></item><item><title>Simple strategy pattern with Symfony</title><link>https://swag.industries/simple-strategy-with-symfony/</link><description>Use the dependency injection of Symfony to configure super-easily a strategy pattern with your services.</description><author>Swag Industries</author><pubDate>Sat, 15 Aug 2020 22:56:01 GMT</pubDate><guid isPermaLink="true">https://swag.industries/simple-strategy-with-symfony/</guid></item><item><title>On Work, Money and PURPOSE, Part 2</title><link>https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-2/</link><description>&lt;p&gt;Employment, WORK and p-work are very different things&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 15 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-2/</guid></item><item><title>Developer Exception Engineering</title><link>https://www.swyx.io/developer-exception</link><description>It's time we look beyond the easy questions in developer experience, and start addressing the uncomfortable ones.</description><author>swyx's site RSS Feed</author><pubDate>Sat, 15 Aug 2020 20:20:15 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/developer-exception</guid></item><item><title>Automatically add Jira issue to commit message from branch name</title><link>https://jmthornton.net/blog/p/jira-commit-msg</link><description>When your git branch name contains an issue number (e.g. from Jira), automatically format git commit messages with the issue number at the end</description><author>Blog by Jade Michael Thornton</author><pubDate>Sat, 15 Aug 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://jmthornton.net/blog/p/jira-commit-msg</guid></item><item><title>Wayland and input methods</title><link>https://dorotac.eu/posts/input_method/</link><description>&lt;h1&gt;Wayland and input methods&lt;/h1&gt;
&lt;p&gt;Wayland is gradually getting the ability to support input methods natively. Actually, it's plural "abilities", because there are several pieces related to the functionality. Working in this area, I had to explain this to newcomers so often that I decided to write this blog post instead, to explain to everyone what's going on here, once and for all.&lt;/p&gt;
&lt;h2&gt;Text input&lt;/h2&gt;
&lt;p&gt;Quick recap. The purpose of an input method is twofold: to give applications text from the user, and to recognize when and what kind of text is expected.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Input methods help the user enter text in an efficient way" src="purpose.svg" /&gt;&lt;/p&gt;
&lt;p&gt;The most basic thing to do that under Wayland is the &lt;strong&gt;text-input&lt;/strong&gt; protocol. It takes text from the compositor, and gives it to applications. It lets applications tell the compositor when and what kind of text they need. The protocol doesn't worry about the user, instead leaving that to the compositor.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Text input connects applications to the compositor" src="text_input.svg" /&gt;&lt;/p&gt;
&lt;h2&gt;Input method&lt;/h2&gt;
&lt;p&gt;The compositor can take two paths in order to let user input the text. Either it takes the burden of communication on its own, by handling input itself, or it can delegate that task to some other program.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Input method inserts itself between compositor and privileged program" src="input_method.svg" /&gt;&lt;/p&gt;
&lt;p&gt;In Wayland, the &lt;strong&gt;input-method&lt;/strong&gt; protocol was designed to help. It is very similar to &lt;em&gt;text-input&lt;/em&gt;, because it lets &lt;em&gt;a program&lt;/em&gt; send text &lt;em&gt;to the compositor&lt;/em&gt;, and allows &lt;em&gt;the compositor&lt;/em&gt; to tell &lt;em&gt;the program&lt;/em&gt; what kind of text is needed. Notice the inversion! This time, the program is special. It communicates with the user, and then gives the text to the compositor. The compositor is then typically going to send the text onward to the currently focused application using &lt;em&gt;text-input&lt;/em&gt;, creating a chain: special program → compositor → focused application.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Input method is one, text inputs are many." src="focused.svg" /&gt;&lt;/p&gt;
&lt;p&gt;This protocol has place for some additional responsibilities, too. Because there is typically only one application using this protocol, it can do things which would not work with multiple applications. One of them is grabbing the keyboard, known to CJKV language users. &lt;em&gt;Input-method&lt;/em&gt; allows the special program to ask the compositor to send it all keyboard presses ("exclusive grab"). Taking over the keyboard makes it possible to send the text "你好" when "nihao" is typed. The other extension is meant for creating a special pop up window, which the compositor places next to the text field, and which can be used to show typing completions.&lt;/p&gt;
&lt;h2&gt;Virtual keyboard&lt;/h2&gt;
&lt;p&gt;Input methods support would have been complete here, if all we cared about was text. However, the world is not so simple, and we have to deal with additional categories of input before being useful:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;text in legacy applications which don't support text-input, and&lt;/li&gt;
&lt;li&gt;triggering actions which would normally need a keyboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both of them can be addressed by using a keyboard. But what if we're using a tablet computer, a TV, game console, or a phone, and there isn't one to speak of? We can address this issue by emulating button presses. Again, there are two basic ways to address this. The compositor can come up with something on its own, or it can delegate the task to another program.&lt;/p&gt;
&lt;p&gt;The protocol &lt;strong&gt;virtual-keyboard&lt;/strong&gt; is designed for programs which want to tell the compositor to issue "fake" keyboard button press events.&lt;/p&gt;
&lt;h2&gt;Together&lt;/h2&gt;
&lt;p&gt;A fully-fledged input method program will be a Wayland client using the &lt;em&gt;input-method&lt;/em&gt; protocol for submitting text, but also supporting &lt;em&gt;virtual-keyboard&lt;/em&gt; for submitting actions, and as a fallback for legacy applications.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Virtual keyboard in parallel to input method" src="virtual_keyboard.svg" /&gt;&lt;/p&gt;
&lt;p&gt;A compositor would ferry text around between the input method program and whichever application is focused. It would also carry synthetic keyboard events from the input method program to the focused application.&lt;/p&gt;
&lt;p&gt;An application consuming text would support &lt;em&gt;text-input&lt;/em&gt;, and it would send enable and disable events whenever a text input field comes into focus or becomes unfocused. It would also accept keyboard events.&lt;/p&gt;
&lt;p&gt;Legacy applications won't send enable and disable, even when a text field is focused, and the user ready to type. When that happens, the compositor and the input method won't realize that text should be submitted now. If the input method uses an on-screen keyboard, it could remain hidden! Because of that, it's best to always make sure the user can bring up the input method and input text, which would then be delivered as keyboard events (which are always supported by applications).&lt;/p&gt;
&lt;h2&gt;Current state&lt;/h2&gt;
&lt;p&gt;As of 2020-08-15, the latest versions of relevant protocols are:&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/master/unstable/text-input/text-input-unstable-v3.xml"&gt;&lt;em&gt;text-input-unstable-v3&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Accepted in &lt;a href="https://gitlab.freedesktop.org/wayland/wayland-protocols/"&gt;wayland-protocols&lt;/a&gt;. Designed by me, based on &lt;a href="https://gitlab.gnome.org/GNOME/mutter/-/blob/efd7a4af5e37299f17011a7f39cc66d8416a1bf9/src/wayland/protocol/gtk-text-input.xml"&gt;&lt;em&gt;gtk-text-input&lt;/em&gt;&lt;/a&gt; by Carlos Garnacho, and on &lt;a href="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/master/unstable/text-input/text-input-unstable-v1.xml"&gt;&lt;em&gt;text-input-unstable-v1&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://github.com/swaywm/wlroots/blob/master/protocol/input-method-unstable-v2.xml"&gt;&lt;em&gt;input-method-unstable-v2&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Used in &lt;a href="https://github.com/swaywm/wlroots/"&gt;wlroots&lt;/a&gt;. Designed by me, based on &lt;a href="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/master/unstable/text-input/text-input-unstable-v3.xml"&gt;&lt;em&gt;text-input-unstable-v3&lt;/em&gt;&lt;/a&gt; and &lt;a href="https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/master/unstable/input-method/input-method-unstable-v1.xml"&gt;&lt;em&gt;input-method-unstable-v1&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://github.com/swaywm/wlroots/blob/master/protocol/virtual-keyboard-unstable-v1.xml"&gt;&lt;em&gt;virtual-keyboard-unstable-v1&lt;/em&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Used in &lt;a href="https://github.com/swaywm/wlroots/"&gt;wlroots&lt;/a&gt;. Designed by me, based on the &lt;a href="https://gitlab.freedesktop.org/wayland/wayland/-/blob/4e16ef0aed8db425afc8910b2a9708b57e165d39/protocol/wayland.xml#L2171"&gt;&lt;em&gt;wl_keyboard&lt;/em&gt;&lt;/a&gt; interface.&lt;/p&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;There are still some topics open. The most important one is about fixing the deficiencies in &lt;em&gt;text-input&lt;/em&gt;, and updating &lt;em&gt;input-method&lt;/em&gt; to match. Another one is regarding whether &lt;em&gt;virtual-keyboard&lt;/em&gt; is even worth the effort, considering how it stirs up some conflict with Wayland's design.&lt;/p&gt;
&lt;p&gt;Less important is implementing the additional features of &lt;em&gt;input-method&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There's also the exploratory idea of designing a protocol dedicated to submitting actions like "undo", "submit", "next field", but not text, in order to eliminate the need to emulate keys in modern keyboard.&lt;/p&gt;</description><author>dcz's posts</author><pubDate>Sat, 15 Aug 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/input_method/</guid></item><item><title>Disabling emergency alerts on Android</title><link>https://cmetcalfe.ca/blog/disabling-emergency-alerts-on-android.html</link><description>&lt;div class="admonition warning"&gt;
&lt;p class="admonition-title"&gt;Warning&lt;/p&gt;
&lt;p&gt;You probably shouldn't do this. If you already know this and don't care, read on.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Background&lt;/h2&gt;
&lt;p&gt;In Canada, the &lt;a href="https://crtc.gc.ca/"&gt;CRTC&lt;/a&gt; mandates that telecommunications companies and other organizations broadcast
warning messages over various mediums, one of which is via cell phones.&lt;/p&gt;
&lt;p&gt;Overall, this is a good idea that saves lives. However, the implementation is incredibly bad. All
alerts, no matter the severity, are broadcast at the very highest level (called "Presidential" by
Android phones), meaning that they can't be silenced or disabled by the user. In fact, the CRTC
actually &lt;a href="https://crtc.gc.ca/eng/publications/reports/alertmobil/alertmobil.htm#a13"&gt;tested this&lt;/a&gt; and
found that the only reliable way to silence the alerts was to put the phone on airplane mode.&lt;/p&gt;
&lt;p&gt;After I received three alerts all about an hour apart starting at 2am telling me about a missing
child over 1,300km away, I'd had enough.&lt;/p&gt;
&lt;p&gt;This is a "boy who cried wolf" situation here. If these alerts ever:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Implement a basic distance filter so I'm not woken up by things happening nowhere near me&lt;/li&gt;
&lt;li&gt;Start using an appropriate alert level instead of using the highest level for everything&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I'll re-enable them. For now though, I don't want to be repeatedly woken up in the middle of the
night because someone a full day's drive from me went missing. Maybe that's cold-hearted, but
realistically what was I even going to do about it?&lt;/p&gt;
&lt;p&gt;On Android at least, the lower-level emergency alerts can be configured to not make noise when the
device is silenced, but not disabled entirely. This seems a lot better as it won't wake people up,
but will show them the information the next time they look at the phone. Let's do that instead.&lt;/p&gt;
&lt;p&gt;For now though, I'm turning everything off. Hopefully I don't get killed by a tornado or something.&lt;/p&gt;
&lt;h2&gt;How to disable ALL alerts&lt;/h2&gt;
&lt;p&gt;This is surprisingly simple - the application responsible for handling the broadcasts can be
uninstalled.&lt;/p&gt;
&lt;div class="admonition warning"&gt;
&lt;p class="admonition-title"&gt;Warning&lt;/p&gt;
&lt;p&gt;This will disable ALL emergency broadcasts. If you live in an area that regularly has severe
weather or don't have a backup method for receiving these alerts, this is definitely not a good
idea. It also probably violates some sort of policy or something (not a lawyer). You are
responsible for your own decisions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;To uninstall it, enable developer options and debugging on the phone, connect it to a computer with
&lt;a href="http://developer.android.com/tools/help/adb.html"&gt;ADB&lt;/a&gt; installed and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;adb&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;shell&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;pm uninstall -k com.android.cellbroadcastreceiver&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Thanks to &lt;a href="https://web.archive.org/web/20230420065952/https://www.reddit.com/r/ontario/comments/boxx11/how_to_disable_amber_alerts/"&gt;this reddit post&lt;/a&gt; for the method of disabling
the alerts.&lt;/p&gt;
&lt;h2&gt;Why is it like this?&lt;/h2&gt;
&lt;p&gt;Which organization is responsible? Can this be changed?&lt;/p&gt;
&lt;p&gt;Below is a rough dump of some details I found while trying to dig up which organization is
responsible for this with the hopes of actually affecting some change.&lt;/p&gt;
&lt;p&gt;On 2017-04-06 the &lt;a href="https://crtc.gc.ca/"&gt;CRTC&lt;/a&gt; issued &lt;a href="https://crtc.gc.ca/eng/archive/2017/2017-91.htm"&gt;Telecom Regulatory Policy CRTC 2017-91&lt;/a&gt; which "directs wireless
service providers to implement wireless public alerting capability on their long-term evolution
networks by 6 April 2018". Relevant information pulled from that page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;34. SOREM has established a definitive list of emergency alert message types for immediate
    broadcast by alert distributors. These messages are defined as “Broadcast Immediately” (BI).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In a footnote on the page it defines SOREM as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SOREM is a federal/provincial/territorial body that works to harmonize and improve emergency
practices across the country. It includes representatives from provincial and territorial
emergency management organizations as well as Public Safety Canada.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There was some disagreement on making the alerts mandatory:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;35. Individual interveners’ views were divided among mandatory receipt, an opt-in mechanism, and
    the choice to opt out. Technology solutions providers indicated mixed support between
    mandatory reception and the choice to opt out. EMOs strongly supported mandatory receipt.&lt;/p&gt;
&lt;p&gt;36. The OPC submitted that many people consider their mobile devices to be private and personal,
    and that some individuals could consider emergency alerts to be intrusive. It recommended
    that the Commission review how opt-out mechanisms have been implemented in the United States
    and other jurisdictions, and whether the ability to opt out has had a significant negative
    effect on alerting individuals in an emergency situation. It submitted that individuals should
    be allowed to opt out if the effect is found to be minimal.&lt;/p&gt;
&lt;p&gt;39. Some WSPs provided insight on past experiences regarding the distribution of AMBER Alerts over
    their parent BDUs. For example, in March 2016, the Ontario Provincial Police issued an AMBER
    Alert, which was distributed by BDUs. Many television viewers were upset by the interruption
    of their television viewing and contacted their BDU customer service centres and, in some
    cases, 9-1-1 to complain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And finally, in a section titled "Commission’s analysis and determinations", a decision was made:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;41. Although some interveners suggested modifying the BI list, there was no consensus on which
    specific categories should be added or removed.&lt;/p&gt;
&lt;p&gt;42. However, the question in this proceeding is not whether the BI list used in the broadcasting
    context should be changed, but whether the same or a different approach should be taken with
    respect to emergency alert messages sent to mobile devices compared to those sent via
    broadcasting emergency alerting. The current BI list is designed to protect against threats to
    life and property. It is therefore important to promote consistency between broadcasting and
    wireless emergency alerts so that Canadians can receive the same alerts regardless of
    transmission medium.&lt;/p&gt;
&lt;p&gt;43. In light of the above, the Commission mandates the reception of emergency alert messages on
    mobile devices, based on the BI list developed by SOREM, as amended from time to time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This seems to say that the list of what alerts exist and their priority is managed by SOREM.&lt;/p&gt;
&lt;p&gt;To back this up, the CRTC's &lt;a href="https://crtc.gc.ca/eng/television/services/alert.htm"&gt;Emergency Alerts and the National Public Alerting System&lt;/a&gt; page has a section titled "Consistent appearance and sound of alerts" with the
quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The visual appearance, sound, content, and other aspects of emergency alerts are guided by the
Senior Officials Responsible for Emergency Management. This federal, provincial and territorial
body works to harmonize and improve emergency practices across the country.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That section also includes a link to the &lt;a href="https://www.publicsafety.gc.ca/cnt/mrgnc-mngmnt/mrgnc-prprdnss/npas/clf-lng-20-en.aspx"&gt;National Public Alerting System's Common Look and Feel
Guidance&lt;/a&gt; which has some more information in it:&lt;/p&gt;
&lt;p&gt;From the &lt;a href="https://www.publicsafety.gc.ca/cnt/mrgnc-mngmnt/mrgnc-prprdnss/npas/clf-lng-20-en.aspx#s73"&gt;7.3 SOREM Public Alerting Layer&lt;/a&gt; section:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The SOREM Public Alerting Layer establishes parameters that are referred to by the CLF. The
current version of the specification can be found in Appendix B.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;From the &lt;a href="https://www.publicsafety.gc.ca/cnt/mrgnc-mngmnt/mrgnc-prprdnss/npas/clf-lng-20-en.aspx#sb"&gt;APPENDIX B – SOREM Public Alerting Layer&lt;/a&gt; section:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The SOREM Public Alerting Layer establishes a number of CAP s which are used to support
the public alerting community in Canada. In a separate document, SOREM maintains the “Broadcast
Immediate Events List”, which works in conjunction with this layer. The current version of this
list is available at &lt;a href="https://alerts.pelmorex.com/highpriorityalerts/"&gt;https://alerts.pelmorex.com/highpriorityalerts/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That link goes to a page that doesn't exist, but by visiting &lt;a href="https://alerts.pelmorex.com"&gt;https://alerts.pelmorex.com&lt;/a&gt; directly
and looking around, it looks like it should point to: &lt;a href="https://alerts.pelmorex.com/wp-content/uploads/2022/07/List-of-Event-Codes-for-Broadcast-Immediate-Alerts_version-2.1.pdf"&gt;List of Event Codes for Broadcast
Immediate Alerts (version 2.1)&lt;/a&gt; (last updated 2022-05-25).&lt;/p&gt;
&lt;p&gt;This document contains a table titled "EVENT CODE DESCRIPTIONS FOR EMERGENCY PUBLIC ALERT BROADCAST
IMMEDIATE EVENTS" that defines what codes map to what alert severity. For example, the reason why an
AMBER alert is sent at the highest level is because of this entry:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Event Code&lt;/strong&gt;: amber &lt;br /&gt;
&lt;strong&gt;CAP Code for Urgency&lt;/strong&gt;: Immediate &lt;br /&gt;
&lt;strong&gt;CAP Code for Severity&lt;/strong&gt;: Severe or Extreme &lt;br /&gt;
&lt;strong&gt;CAP Code for Certainty&lt;/strong&gt;: Observed &lt;br /&gt;
&lt;strong&gt;Description&lt;/strong&gt;: Amber Alert:
    Issued by police services when a child has been abducted and it is believed that his/her life
    is in grave danger. An Amber Alert provides the public with immediate and up-to-date
    information about a child abduction and solicits the public's help in the safe and swift
    return of the child.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Where the following definitions for the CAP codes are used:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"Immediate" - Responsive action SHOULD be taken immediately&lt;/li&gt;
&lt;li&gt;"Extreme" - Extraordinary threat to life&lt;/li&gt;
&lt;li&gt;"Severe" - Significant threat to life&lt;/li&gt;
&lt;li&gt;"Observed" - Determined to have occurred or to be ongoing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is where the "everything at the highest alert level" issue comes from. Aside from
&lt;code&gt;testMessage&lt;/code&gt;, literally every other event code on this list has the same Immediate + Severe/Extreme
classification. This includes everything from &lt;code&gt;silver&lt;/code&gt; (&lt;em&gt;"a missing, wandering older adult who may
be suffering from a documented cognitive disability or degenerative memory disorder"&lt;/em&gt;) to &lt;code&gt;meteor&lt;/code&gt;
(&lt;em&gt;"A natural object of extraterrestrial origin [...] hits the ground with the potential for
catastrophic damage."&lt;/em&gt;) &lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;The CRTC requires that Wireless Service Providers (WSPs) implement the alerts as defined by SOREM.
SOREM's list of alerts defines an AMBER alert as requiring the same amount of urgency and disruption
as a planet-killing meteor dropping from the sky.&lt;/p&gt;
&lt;p&gt;This seems to be by design, but if not, SOREM is the organization that would need to fix it. As an
aside, it seems like the CRTC wouldn't even have to get involved as the policy just defers to the
&lt;em&gt;"BI list developed by SOREM, as amended from time to time"&lt;/em&gt; which seems pretty loose. Maybe I'm
missing something though.&lt;/p&gt;
&lt;p&gt;I didn't find anything that specified any details about how wide the affected range for these alerts
should or should not be. It seems like that's left up to the organization issuing the alert.&lt;/p&gt;</description><author>Carey Metcalfe</author><pubDate>Sat, 15 Aug 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://cmetcalfe.ca/blog/disabling-emergency-alerts-on-android.html</guid></item><item><title>Are small memory allocations in C++ STL containers still a concern?</title><link>https://blog.kaetemi.be/2020/08/15/are-small-memory-allocations-in-cpp-stl-containers-still-a-concern/</link><description>While benchmarking a custom concurrent functor queue against standard library containers, I noticed something that I didn&amp;#8217;t expect. The common concern about the standard containers, especially ones such as std::list,...</description><author>Kaetemi</author><pubDate>Sat, 15 Aug 2020 04:51:19 GMT</pubDate><guid isPermaLink="true">https://blog.kaetemi.be/2020/08/15/are-small-memory-allocations-in-cpp-stl-containers-still-a-concern/</guid></item><item><title>Scary Terrorism Math</title><link>/world_events/2020/08/scary_terrorism_math.html</link><description>&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/2020_Beirut_explosions"&gt;August 4th explosions in Beirut&lt;/a&gt; were very jarring to me due to the loss of human life, and the &lt;a href="https://www.youtube.com/watch?v=LNDhIGR-83w"&gt;numerous&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=eGEmD6j8diU"&gt;direct&lt;/a&gt; &lt;a href="https://www.youtube.com/watch?v=DwRF5liTGB4"&gt;videos&lt;/a&gt; that looked like something out my 80s youth nightmares. Hearing that it was caused by 2,750 tonnes of &lt;a href="https://en.wikipedia.org/wiki/Ammonium_nitrate"&gt;ammonium nitrate&lt;/a&gt;, I started working on my phone to quantify my fear by figuring out how easy it would be to ship that much, and how much it would cost.&lt;/p&gt;

&lt;p&gt;According to wikipedia, there were at least 171 deaths; 6,000 injuries; 300,000 people homeless; and US$10-15 billion in destruction with a blast radius causing damage up to two miles away. &lt;sup id="fnref:nytimes"&gt;&lt;a class="footnote" href="#fn:nytimes" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;After my initial shock, I heard 2,750 tonnes of &lt;a href="https://en.wikipedia.org/wiki/Ammonium_nitrate"&gt;ammonium nitrate&lt;/a&gt; mentioned in the news but didn’t know much about that and wanted to know how big that was. It surprised me that it seems to cost a little over half a million to buy and ship this much It ends up being really cheap, really common, and really small and that scared me by how simple of a risk this is for misuse. I’m hoping that anti-terrorism agencies are working to prevent this but since I didn’t see much coverage on this, I’m posting my notes here in case others were doing similar research.&lt;/p&gt;

&lt;p&gt;If you can, please consider donating to help those impacted. Choosing a charity is hard, but I noticed that &lt;a href="https://twitter.com/nntaleb/status/1291772262530637824"&gt;Nassim Nicholas Taleb recommended&lt;/a&gt; &lt;a href="https://www.seal-usa.org/BeirutEmergencyFund"&gt;Beirut Emergency Fund 2020&lt;/a&gt;, a co-worker recommended &lt;a href="http://www.redcross.org.lb/index.aspx?pageid=907"&gt;Lebanese Red Cross&lt;/a&gt;, and Google has a nice &lt;a href="https://donate.google.com/checkout?campaignid=5303526385319936&amp;amp;tab=1&amp;amp;hl=en-US&amp;amp;authUser=0"&gt;Donate with Google&lt;/a&gt; page set up with the Center for Disaster Philanthropy.&lt;/p&gt;

&lt;p&gt;This is unrelated to technology, but I think random researching outside of comfort areas is really important for design and debugging. Also, I think user empathy is really important for figuring out the solution so I frequently have to learn about whatever is important to my users. That being said, if this isn’t interesting, please skip.&lt;/p&gt;

&lt;h2 id="my-question"&gt;My question&lt;/h2&gt;

&lt;p&gt;My initial wondering was “what is ammonium nitrite and how big is 2,750 tonnes of it?” And that led to a chain of reasoning that made me worry more and more…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;How much space does 2,750 tonnes take up?&lt;/li&gt;
  &lt;li&gt;How much space does that take up?&lt;/li&gt;
  &lt;li&gt;How many shipping containers is that?&lt;/li&gt;
  &lt;li&gt;How much would it cost to buy that much?&lt;/li&gt;
  &lt;li&gt;How much would it cost to ship to that to a harbor near New York?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing here was too complicated but it ate up part of Sunday morning while my wife and I were watching the news. I work on trying to collect references for lines of reasoning and so I started bookmarking some sites as I answered each of these questions.&lt;/p&gt;

&lt;h2 id="breaking-down-the-arithmetic"&gt;Breaking down the arithmetic&lt;/h2&gt;

&lt;p&gt;There are many assumptions I made and I’m not experienced in chemistry or mining or export or shipping so I think that I’m likely quite a bit off in my calculations, so I figure I may be off by a power of 10. But that’s a big caveat before I start making naive calculations.&lt;/p&gt;

&lt;h3 id="how-big"&gt;How big?&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Ammonium_nitrate"&gt;Ammonium nitrate&lt;/a&gt; is commonly used as a fertilizer and as an industrial explosive. To figure out how much space this much would take up I want to multiply out by its density. According to wikipedia the density of ammonium nitrate is 1.725 grams / cm3, &lt;sup id="fnref:wikipedia_am"&gt;&lt;a class="footnote" href="#fn:wikipedia_am" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt; so to figure out how much space this takes up I need to convert this mass to a dimension.&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-calc"&gt;1 metric ton = 1,000,000 grams = 1,000 kilograms = 1 megagram
1,000,000 / 1.725 = 579710.144927536231884 cm3 = .5797 m3 = 20.47 cubic feet
2,750 * .5797 = 1594.175 m3
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;sup id="fnref:wikipedia_tonne"&gt;&lt;a class="footnote" href="#fn:wikipedia_tonne" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;So a single tonne of ammonium nitrate takes up .5797 m3 or 20.47 cubic feet.&lt;/p&gt;

&lt;p&gt;Why did I convert that to cubic feet? I wanted to try to think of that in car cargo size and those are displayed in cubic feet.&lt;/p&gt;

&lt;p&gt;So a BMW 330 Gran Turismo hatchback has a 18.4 cubic foot capacity with the seats up and 56.5 with the seats down. &lt;sup id="fnref:bmw_330gt_cargo_specs"&gt;&lt;a class="footnote" href="#fn:bmw_330gt_cargo_specs" rel="footnote"&gt;4&lt;/a&gt;&lt;/sup&gt; So it won’t fit a whole tonne with the seats up, but it can hold almost three with the seats down. Of course, the axles can’t bear even a half tonne so it’s moot for reality, but I’m now thinking of 2,750 tonnes in terms of hatchbacks.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Fortunately, not full of ammonium nitrate" src="/assets/images/bmw-3-series-gt-rear-quarter.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;So, the entire batch of ammonium nitrate in Beirut takes up 1594 m3. That’s too big to think of in hatchbacks, how many shipping containers is that?&lt;/p&gt;

&lt;p&gt;A shipping container, or an intermodal container, are those standard sized steel boxes that we see on trucks and stacked up in ports and is used for shipping pretty much everything for freight transport. They come in 20 foot and 40 foot versions and shipping is described in twenty-foot equivalent units or TEUs. This is one of those funny situations where the standard is in imperial units (kind of like &lt;a href="https://en.wikipedia.org/wiki/Tire_code"&gt;tire sizes&lt;/a&gt;) but the dimensions are 6.1m long, 2.6m high, and 2.9m wide and have an internal volume of 33.1 m3. &lt;sup id="fnref:wikipedia_tfe"&gt;&lt;a class="footnote" href="#fn:wikipedia_tfe" rel="footnote"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-calc"&gt;1594.175 / 33.1 = 48.16238670694864
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So 2,750 tonnes takes up 48.16 TEU shipping containers. Still kind of hard to visualize. How many does one of those cargo ships carry? Is 50 containers a lot?&lt;/p&gt;

&lt;p&gt;Modern container ships can carry over 23,000 TEUs. &lt;sup id="fnref:wikipedia_container_ship"&gt;&lt;a class="footnote" href="#fn:wikipedia_container_ship" rel="footnote"&gt;6&lt;/a&gt;&lt;/sup&gt; So 50 containers is just a fraction of the overall cargo.&lt;/p&gt;

&lt;p&gt;&lt;img alt="See if you can spot the .217% of the TEUs that contain 2,750 tonnes" src="/assets/images/loaded_container_ship.jpeg" /&gt;&lt;/p&gt;

&lt;p&gt;So I can kind of visualize 50 TEUs and the neat web site &lt;a href="http://www.bluebulbprojects.com/MeasureOfThings/results.php?amt=1500&amp;amp;comp=volume&amp;amp;p=1&amp;amp;sort=pr&amp;amp;unit=cm"&gt;The Measure of Things&lt;/a&gt; tells me that’s 3/4 the size of a hot air balloon.&lt;/p&gt;

&lt;p&gt;So big, but not humongous. Certainly something that the Joker or Simon Gruber could arrange to ship with 25-50 semi trucks.&lt;/p&gt;

&lt;h3 id="how-expensive"&gt;How expensive?&lt;/h3&gt;

&lt;p&gt;How much would this much cost? The price seems to vary depending on country, this chart from 2007 shows the cheapest price from Russia at $156/tonne. &lt;sup id="fnref:pricing"&gt;&lt;a class="footnote" href="#fn:pricing" rel="footnote"&gt;7&lt;/a&gt;&lt;/sup&gt; And the current retail price on Alibaba.com is $192-217/tonne. &lt;sup id="fnref:alibaba_price"&gt;&lt;a class="footnote" href="#fn:alibaba_price" rel="footnote"&gt;8&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The world’s total output was 21.6M tonnes in 2017 and the top five producing countries were Russia (9.9M), Egypt (4.3M), Uzbekistan (1.4M), the US (1.4M), and Poland (1.3M).&lt;/p&gt;

&lt;p&gt;So 2,750 seems like a purchasable amount. Assuming that the 2007 price from Russia is reasonable for a bulk price gets us to $429,000 as the raw cost of the material.&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-calc"&gt;156 x 2,750 = $429,000
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="how-much-to-ship"&gt;How much to ship?&lt;/h3&gt;

&lt;p&gt;So if a bad guy has 50 containers full of ammonium nitrate, how much does that cost to ship?&lt;/p&gt;

&lt;p&gt;An explosion in any US port would be terrible, but just to estimate prices I calculated shipping it to the Red Hook Terminal in Brooklyn, NY as a two mile radius from there would reach much of New York City.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ship.freightos.com/"&gt;Freightos.com&lt;/a&gt; shows that four quotes of 50 containers shipped from St. Petersburg, Russia (RULED) to New York (USNYC) range from $106,200-138,000 and will take 13-19 days.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So it seems like the total cost to purchase and ship 2,750 tonnes of ammonium nitrate is $567,000. That seems way too cheap to cause so much damage.&lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://www.cnn.com/2020/08/05/europe/lebanon-russian-ship-blast-intl/index.html"&gt;CNN&lt;/a&gt;, the fertilizer was on a Russian ship called the MVRhosus and was bound for Madagascar when it stopped in Beirut.&lt;/p&gt;

&lt;p&gt;This is one of those risks that I don’t know any way to practically cope with, so I have to trust that multiple government agencies are working every day making sure stuff like this doesn’t happen.&lt;/p&gt;

&lt;p&gt;But if someone is working on a Bond script, or an Austin Powers script, this might eventually show up in a story.&lt;/p&gt;

&lt;h2 id="all-the-calculations-together"&gt;All the calculations together&lt;/h2&gt;

&lt;pre&gt;&lt;code class="language-calc"&gt;$156 x 2,750 tonnes = $429,000
1,000,000 grams / 1.725 g/cm3 = 579710.144927536231884 cm3 = .5797 m3
2,750 tonnes * .5797 m3 = 1594.175 m3
1594.175 m3 / 33.1 m3/TEU = 48.16238670694864 TEU
$429,000 chemicals + $138,000 shipping = $567,000
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="unanswered-questions"&gt;Unanswered questions&lt;/h2&gt;

&lt;p&gt;Questions I didn’t find that definitely impact overall cost:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I’m not sure what mixture and ingredients are needed beyond raw ammonium nitrate.&lt;/li&gt;
  &lt;li&gt;I’m not sure if stacked containers will result in a similar explosion.&lt;/li&gt;
  &lt;li&gt;Not sure how much it costs to rent all those containers.&lt;/li&gt;
  &lt;li&gt;St. Petersburg may not be the best shipping port from Russia.&lt;/li&gt;
  &lt;li&gt;How hard it is to arrange customs forms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="related-reading"&gt;Related reading&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.plslogistics.com/blog/the-history-of-containers/#:~:text=The%20first%20standard%20shipping%20container,the%20country%20at%20that%20time.&amp;amp;text=So%2C%20Malcolm%20decided%20to%20make,with%20all%20its%20shipping%20assets."&gt;The History of Containers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="stuff-i-read-while-working-on-this-post"&gt;Stuff I read while working on this post&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.nytimes.com/interactive/2020/08/04/world/middleeast/beirut-explosion-damage.html"&gt;https://www.nytimes.com/interactive/2020/08/04/world/middleeast/beirut-explosion-damage.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.cnn.com/2020/08/05/europe/lebanon-russian-ship-blast-intl/index.html"&gt;https://www.cnn.com/2020/08/05/europe/lebanon-russian-ship-blast-intl/index.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://donate.google.com/checkout?campaignid=5303526385319936&amp;amp;tab=1&amp;amp;hl=en-US&amp;amp;authUser=0"&gt;https://donate.google.com/checkout?campaignid=5303526385319936&amp;amp;tab=1&amp;amp;hl=en-US&amp;amp;authUser=0&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.seal-usa.org/BeirutEmergencyFund"&gt;https://www.seal-usa.org/BeirutEmergencyFund&lt;/a&gt; (recommended by &lt;a href="https://twitter.com/nntaleb/status/1291772262530637824"&gt;Nassim Nicholas Taleb&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.redcross.org.lb/index.aspx?pageid=907"&gt;http://www.redcross.org.lb/index.aspx?pageid=907&lt;/a&gt; (recommended by a work colleague of mine)&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Ammonium_nitrate"&gt;https://en.wikipedia.org/wiki/Ammonium_nitrate&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/2020_Beirut_explosions"&gt;https://en.wikipedia.org/wiki/2020_Beirut_explosions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Tire_code"&gt;https://en.wikipedia.org/wiki/Tire_code&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.bluebulbprojects.com/MeasureOfThings/results.php?amt=1500&amp;amp;comp=volume&amp;amp;p=1&amp;amp;sort=pr&amp;amp;unit=cm"&gt;http://www.bluebulbprojects.com/MeasureOfThings/results.php?amt=1500&amp;amp;comp=volume&amp;amp;p=1&amp;amp;sort=pr&amp;amp;unit=cm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="references"&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;shipping container image from &lt;a href="https://www.businessinsider.com/map-of-global-shipping-interactive-2017-12"&gt;Business Insider&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;bmw image from &lt;a href="https://www.autocar.co.uk/car-review/bmw/3-series-gt-2013-2019"&gt;Autocar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="footnotes"&gt;Footnotes&lt;/h2&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:nytimes"&gt;
      &lt;p&gt;&lt;a href="https://www.nytimes.com/interactive/2020/08/04/world/middleeast/beirut-explosion-damage.html"&gt;https://www.nytimes.com/interactive/2020/08/04/world/middleeast/beirut-explosion-damage.html&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:nytimes"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:wikipedia_am"&gt;
      &lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Ammonium_nitrate"&gt;https://en.wikipedia.org/wiki/Ammonium_nitrate&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:wikipedia_am"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:wikipedia_tonne"&gt;
      &lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Tonne"&gt;https://en.wikipedia.org/wiki/Tonne&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:wikipedia_tonne"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:bmw_330gt_cargo_specs"&gt;
      &lt;p&gt;&lt;a href="https://www.caranddriver.com/bmw/3-series/specs/2019/bmw_3-series_bmw-3-series-gran-turismo_2019/402505"&gt;https://www.caranddriver.com/bmw/3-series/specs/2019/bmw_3-series_bmw-3-series-gran-turismo_2019/402505&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:bmw_330gt_cargo_specs"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:wikipedia_tfe"&gt;
      &lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Intermodal_container"&gt;https://en.wikipedia.org/wiki/Intermodal_container&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:wikipedia_tfe"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:wikipedia_container_ship"&gt;
      &lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Container_ship"&gt;https://en.wikipedia.org/wiki/Container_ship&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:wikipedia_container_ship"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:pricing"&gt;
      &lt;p&gt;&lt;a href="https://www.intratec.us/chemical-markets/ammonium-nitrate-price"&gt;https://www.intratec.us/chemical-markets/ammonium-nitrate-price&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:pricing"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:alibaba_price"&gt;
      &lt;p&gt;&lt;a href="https://m.alibaba.com/showroom/ammonium-nitrate-price-per-ton.html?beginPage=1"&gt;https://m.alibaba.com/showroom/ammonium-nitrate-price-per-ton.html?beginPage=1&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:alibaba_price"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>PREPEND</author><pubDate>Sat, 15 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/world_events/2020/08/scary_terrorism_math.html</guid></item><item><title>Morning Joy</title><link>https://www.dannyguo.com/blog/morning-joy</link><author>Danny Guo</author><pubDate>Sat, 15 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.dannyguo.com/blog/morning-joy</guid></item><item><title>Attribution</title><link>https://blog.talosintelligence.com/2020/08/attribution-puzzle.html</link><description>&lt;p&gt;Not long after I found an old piece on attribution &lt;a href="https://blog.thinkst.com/2013/02/thinkstscapes-2013-ah1-on-china-report.html"&gt;from Thinkst Applied Research&lt;/a&gt;, Cisco&amp;#8217;s Talos Intelligence group posted &lt;a href="https://blog.talosintelligence.com/2020/08/attribution-puzzle.html"&gt;an article on the same topic&lt;/a&gt;. Attribution is fraught, as both pieces explain. IP geolocation is woefully inaccurate, many of the tactics, techniques, and procedures tied to specific actors are either so common that they apply to several groups or so general that they might as well, and the proliferation of viable tool sets has made even this metric unreliable. At best, we can attribute activity with a degree of certainty&amp;#160;&amp;#8212;&amp;#160;but never complete confidence, and you should be circumspect of anyone who does.&lt;/p&gt;


                &lt;p&gt;&lt;a href="https://blog.talosintelligence.com/2020/08/attribution-puzzle.html"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Fri, 14 Aug 2020 23:10:38 GMT</pubDate><guid isPermaLink="true">https://blog.talosintelligence.com/2020/08/attribution-puzzle.html</guid></item><item><title>No more chips for you</title><link>https://stop.zona-m.net/2020/08/no-more-chips-for-you/</link><description>&lt;p&gt;But WHO is &amp;ldquo;you&amp;rdquo; here?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 14 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/no-more-chips-for-you/</guid></item><item><title>CopyOnWriteArrayList 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/08/14/CopyOnWriteArrayList.html</link><description>&lt;h1 id="copyonwritearraylist"&gt;CopyOnWriteArrayList&lt;/h1&gt;
&lt;p&gt;先看看百科上关于 &lt;a href="https://zh.wikipedia.org/wiki/%E5%AF%AB%E5%85%A5%E6%99%82%E8%A4%87%E8%A3%BD" title="COW 的介绍"&gt;COW 的介绍&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;写入时复制（英语：Copy-on-write，简称COW）是一种计算机程序设计领域的优化策略。其核心思想是，如果有多个调用者（callers）同时请求相同资源（如内存或磁盘上的数据存储），他们会共同获取相同的指针指向相同的资源，直到某个调用者试图修改资源的内容时，系统才会真正复制一份专用副本（private copy）给该调用者，而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的（transparently）。此作法主要的优点是如果调用者没有修改该资源，就不会有副本（private copy）被创建，因此多个调用者只是读取操作时可以共享同一份资源。
&lt;!--more--&gt;
简单来说，就是读取时直接读取不用加锁同步，写入数据时会&lt;strong&gt;复制一份副本&lt;/strong&gt;，然后将新的数据写入到副本中，然后再把副本替换成原来的数据。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;因此 CopyOnWriteArrayList 是&lt;strong&gt;线程安全&lt;/strong&gt;的，另外也允许 null  元素。&lt;/p&gt;

&lt;p&gt;这种方式导致了读取速度很快，写入速度较慢，&lt;strong&gt;适合多线程环境中经常读取但写入很少的场景。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;所以如果有个场景需要在多线程环境中使用，频繁读取，但写入次频率很低，例如黑名单白名单，每天更新一次，那就可以使用 CopyOnWriteArrayList 来实现。&lt;/p&gt;

&lt;p&gt;其中的迭代器是不允许对数据修改的，调用&lt;code class="language-plaintext highlighter-rouge"&gt;remove&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;set&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;add&lt;/code&gt;这些方法会直接抛异常。&lt;/p&gt;

&lt;p&gt;一般可以按照常规的 List 来使用，其中没有什么特殊的方法，就直接开始看源码吧。&lt;/p&gt;

&lt;p&gt;CopyOnWriteArrayList 下面简称 COWList。&lt;/p&gt;

&lt;h2 id="源码"&gt;源码&lt;/h2&gt;
&lt;p&gt;我们先看其中两个最重要的方法：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;getArray&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面定义的&lt;code class="language-plaintext highlighter-rouge"&gt;array&lt;/code&gt;变量就是 COWList 中存储数据的地方。
所有的读取写入操作都是通过对这个数组的操作。&lt;/p&gt;

&lt;p&gt;因此构造函数也是创建一个空的数组然后调用&lt;code class="language-plaintext highlighter-rouge"&gt;setArray&lt;/code&gt;方法设置数组。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CopyOnWriteArrayList&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;setArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;COWList 的优势之一就是即使在多线程环境中，读取也是不需要加锁的，所以效率很高，那么我们来看看读取方法是如何实现的：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getArray&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到这里直接通过索引读取了数组的值，没有加锁。这根我们使用&lt;code class="language-plaintext highlighter-rouge"&gt;Collections.synchronizedList&lt;/code&gt;方法获取到的&lt;code class="language-plaintext highlighter-rouge"&gt;SynchronizedList&lt;/code&gt;效率要高。&lt;/p&gt;

&lt;p&gt;可以看下&lt;code class="language-plaintext highlighter-rouge"&gt;SynchronizedList&lt;/code&gt;是如何实现读取及写入的：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;//SynchronizedList&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;对比一下显而易见，读取不加锁的话效率就高多了。&lt;/p&gt;

&lt;p&gt;那么 COWList 是如何实现多线程环境下的安全问题的呢，看下写入方法就明白了。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getArray&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;//复制数组&lt;/span&gt;
        &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;newElements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;newElements&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;setArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newElements&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到添加元素会加锁，加锁之后会将原数组复制到一个更大（&lt;code class="language-plaintext highlighter-rouge"&gt;len + 1&lt;/code&gt;）的数组中去，并将追加元素添加到数组末尾，完成操作后调用&lt;code class="language-plaintext highlighter-rouge"&gt;setArray&lt;/code&gt;方法设置新数组。&lt;/p&gt;

&lt;p&gt;所以写入的效率是很低的，需要进行一次数组复制操作，用 COWList 时应该尽量降低写入操作的频率，如果需要经常写入，那说明可能不适合用这个。&lt;/p&gt;</description><author>张可的博客</author><pubDate>Fri, 14 Aug 2020 18:14:27 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/08/14/CopyOnWriteArrayList.html</guid></item><item><title>ArrayList 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/08/14/ArrayList.html</link><description>&lt;h1 id="list"&gt;List&lt;/h1&gt;
&lt;p&gt;先看下 ArrayList 实现的接口 List 的相关概念。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;List 可以称为有序集合或者序列，通过整数索引访问元素&lt;/li&gt;
  &lt;li&gt;允许插入相同元素&lt;/li&gt;
  &lt;li&gt;一般来说也允许插入 null 值
&lt;!--more--&gt;
List 接口中还提供了一个特殊的迭代器：ListIterator&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="listiterator"&gt;ListIterator&lt;/h2&gt;
&lt;p&gt;ListIterator 专门为了 List 打造，在 Iterator 基础上还提供了插入和替换元素以及双向访问的功能。
我们来看下使用：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"7"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;ListIterator&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listIterator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasNext&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"7"&lt;/span&gt;&lt;span class="o"&gt;)){&lt;/span&gt;
        &lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;iterator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;previous&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h1 id="arraylist"&gt;ArrayList&lt;/h1&gt;
&lt;p&gt;Java 原生提供了数组数据结构，但由于本身设计存在诸多问题，例如无法扩容、类型不安全等，不够灵活，所以大部分时候可以使用 ArrayList 来替代，效率上没有太大的差异。&lt;/p&gt;

&lt;p&gt;ArrayList 是 List 接口可调整大小的数组实现。&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;size&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;isEmpty&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;get&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;set&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;iterator&lt;/code&gt;以及 &lt;code class="language-plaintext highlighter-rouge"&gt;listIterator&lt;/code&gt;方法调用的执行时间都是&lt;strong&gt;固定时间&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;add&lt;/code&gt;操作时间是&lt;strong&gt;摊销固定时间（amortized constant time）&lt;/strong&gt;，也就是添加 &lt;strong&gt;n&lt;/strong&gt; 个元素需要 &lt;strong&gt;O(n)&lt;/strong&gt; 的时间。其他操作都是&lt;strong&gt;线性时间&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;ArrayList 中有个 &lt;strong&gt;capacity&lt;/strong&gt; 参数用于描述 ArrayList 中数组的长度，&lt;code class="language-plaintext highlighter-rouge"&gt;add&lt;/code&gt;操作会先进行扩容，引起&lt;code class="language-plaintext highlighter-rouge"&gt;capacity&lt;/code&gt;的增长，这是个耗时操作。如果将会发生多次&lt;code class="language-plaintext highlighter-rouge"&gt;add&lt;/code&gt;操作，可以在此之前先调用&lt;code class="language-plaintext highlighter-rouge"&gt;ensureCapacity&lt;/code&gt;方法扩容，以此减小扩容的次数，提升性能。&lt;/p&gt;

&lt;p&gt;需要注意的是 ArrayList 是&lt;strong&gt;非线程安全&lt;/strong&gt;的，多线程环境下，如果希望修改其结构，必须进行同步，也可以使用 Collections 中的包装方法获取同步对象：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;(...));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;iterator 以及 listIterator 也被设计为 &lt;a href="https://en.wikipedia.org/wiki/Fail-fast" title="fail-fast"&gt;fail-fast&lt;/a&gt; 的，多线程环境下使用 iterator 将会直接抛出异常。&lt;/p&gt;

&lt;p&gt;ArrayList 长度&lt;strong&gt;默认为 0&lt;/strong&gt;，可以通过构造器设置初始长度。&lt;/p&gt;

&lt;p&gt;扩容机制是每次添加元素时会检测是否需要扩容，&lt;strong&gt;每次增加的长度为当前长度的一半&lt;/strong&gt;，可以通过&lt;code class="language-plaintext highlighter-rouge"&gt;ensureCapacity&lt;/code&gt;方法使其扩容到指定长度。&lt;/p&gt;

&lt;h2 id="源码"&gt;源码&lt;/h2&gt;
&lt;p&gt;我们先从构造函数开始看&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;//ArrayList 中存储数据的数组&lt;/span&gt;
&lt;span class="kd"&gt;transient&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;elementData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;elementData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;EMPTY_ELEMENTDATA&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Illegal Capacity: "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;initialCapacity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;elementData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DEFAULTCAPACITY_EMPTY_ELEMENTDATA&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到&lt;code class="language-plaintext highlighter-rouge"&gt;elementData&lt;/code&gt;默认长度是 &lt;strong&gt;0&lt;/strong&gt;，如果设置了默认长度就会初始化成改长度的数组。&lt;/p&gt;

&lt;p&gt;再来看看&lt;code class="language-plaintext highlighter-rouge"&gt;add&lt;/code&gt;方法：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ensureCapacityInternal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;++]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;注意这里的&lt;code class="language-plaintext highlighter-rouge"&gt;size&lt;/code&gt;字段表示当前 ArrayList 的实际长度，不代表&lt;code class="language-plaintext highlighter-rouge"&gt;elementData&lt;/code&gt;的长度。
&lt;code class="language-plaintext highlighter-rouge"&gt;add&lt;/code&gt;方法会先调用&lt;code class="language-plaintext highlighter-rouge"&gt;ensureCapacityInternal&lt;/code&gt;方法，传入的参数&lt;code class="language-plaintext highlighter-rouge"&gt;size+1&lt;/code&gt;并不代表本次的扩容长度，而是&lt;strong&gt;最小&lt;/strong&gt;扩容长度。
然后该方法会先判断是否需要进行扩容，判断依据就是当前数组是否还有空余空间添加新元素。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="c1"&gt;//minCapacity = size + 1&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minCapacity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;grow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minCapacity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;那么再看看扩容是如何实现的，可以先猜想下，既然内部使用数组来存储数据，但数组是不可变长度的，那么最可行的方案应该就是重新创建一个更大的数组，然后将数据拷贝进去，我们可以看看是不是这么做的。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;grow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;minCapacity&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;//右移一位等于整除2&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;minCapacity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minCapacity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;MAX_ARRAY_SIZE&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;//hugeCapacity 返回的最大值为 Integer.MAX_VALUE&lt;/span&gt;
        &lt;span class="n"&gt;newCapacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hugeCapacity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minCapacity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;elementData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elementData&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newCapacity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到每次扩容的长度是当前长度 + 当前长度的一半，也就是&lt;strong&gt;扩容 50%&lt;/strong&gt; 。
&lt;code class="language-plaintext highlighter-rouge"&gt;MAX_ARRAY_SIZE&lt;/code&gt;是&lt;code class="language-plaintext highlighter-rouge"&gt;Integer.MAX_VALUE - 8&lt;/code&gt;，一般来说数组长度不会超过这个值，但如果非要继续进行扩容将会扩张到 &lt;code class="language-plaintext highlighter-rouge"&gt;Integer.MAX_VALUE&lt;/code&gt;。&lt;/p&gt;

&lt;p&gt;那么既然可以扩张到&lt;code class="language-plaintext highlighter-rouge"&gt;Integer.MAX_VALUE&lt;/code&gt;为什么还要一个&lt;code class="language-plaintext highlighter-rouge"&gt;MAX_ARRAY_SIZE&lt;/code&gt;呢，代码里面的解释是一些 JVM 会在数组中添加一些保留字段，如果将数组长度扩张到&lt;code class="language-plaintext highlighter-rouge"&gt;Integer.MAX_VALUE&lt;/code&gt;可能会导致&lt;code class="language-plaintext highlighter-rouge"&gt;OutOfMemoryError&lt;/code&gt;。&lt;/p&gt;</description><author>张可的博客</author><pubDate>Fri, 14 Aug 2020 18:06:27 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/08/14/ArrayList.html</guid></item><item><title>How to Write a Unit Test for a Remote Procedural Call in Golang</title><link>https://bartlomiejmika.com/posts/2020/how-to-write-a-unit-test-for-a-remote-procedural-call-in-golang/</link><description>&lt;p&gt;Recently I have been learning about &lt;strong&gt;remote procedural calls&lt;/strong&gt; (RPCs) in *&lt;em&gt;Golang&lt;/em&gt; and realized I was unable to find an easy example on how to write a unit test for RPCs. In this post, I&amp;rsquo;ll explain how I figured out a solution.&lt;/p&gt;</description><author>Bartlomiej Mika</author><pubDate>Fri, 14 Aug 2020 06:14:55 GMT</pubDate><guid isPermaLink="true">https://bartlomiejmika.com/posts/2020/how-to-write-a-unit-test-for-a-remote-procedural-call-in-golang/</guid></item><item><title>What’s wrong with school?</title><link>https://nutcroft.mataroa.blog/blog/whats-wrong-with-school/</link><description>&lt;p&gt;There is constant chatter on the embarrassing quality of schools across the vast majority of our planet’s countries. This is a chatter-organising attempt in fourteen structured—yet not in order of priority—points of what and why.&lt;/p&gt;
&lt;p&gt;In an attempt to justify disagreements, this list is based mostly on my personal experience with the few schools I went to, in the one—Western, first world—country I went to. Surely, different schools do exist with different practices, yet I do imply that what follows is very common.&lt;/p&gt;
&lt;p&gt;Schools are awfully rubbish due to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Lack of student autonomy. Every part and limit of the student’s behaviour is defined a priori. Their exact location during school hours is predetermined. Periods of sitting and standing are decided almost by law. Predefined hours of being inside and outside. Predefined and forced single viewpoint: written in the approved book, expressed from the teacher, established by the legislator. Even further: students' thoughts are mandated to follow and adopt their teacher's thoughts at all times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Failure in diversity management. Not everyone has the same talents, skills, background, desires. Yet, not only is everything already defined, but it's also identical for all. Even if people’s characteristics coincide, the timing may not. Still, in the eyes of the educational system, same age means same person.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lack of teacher autonomy. Defining teaching material by the state might had been a good idea in the past, but now, all knowledge is available to everyone—for free—and that changes everything. The role of the teacher is—and has probably always been—nothing more than the role of a repeater. It doesn't have to be this way, and a usually small creative set of teachers demonstrate and prove this daily. Forging teacher homogeneity to shield students from bad teachers has resulted in the total restriction of teachers. Inescapably, this has lead to total lack of creativity and teaching becoming a lifeless transfer of information, as opposed to the achievement of quenching one's thirst for knowledge. It is undeniable: one cannot have the power for creation without also having the freedom for destruction.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lack of teacher quality assessment. Measuring is fundamental to improving. Absence of improvement inevitably leads to absence of skill.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lack of regard for the teacher's responsibility towards society. The importance of the work of the teacher is monumentally undervalued. High quality teachers are intrinsically connected to more educated society members. Extremely important propositions cascade from this. For instance, higher quality representative democracy due to better educated voters.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blatant ageism. Adult teachers teaching young kids, ad infinitum. Even kids teaching kids was too bizarre to consider.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pointless curricula size. The amount of knowledge “taught” to students in primary and secondary education is preposterous. Both in terms of a twelve-year educational system and in terms of continuous learning for six or seven hours per day everyday. The glaring evidence of such unsustainability cannot be overstated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pointless curricula content. The cybernetic network humanity is part of makes every piece of information available in a few seconds time. There is no point in learning information; there is point in learning fundamentals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Irrelevant methods of teaching. Lifeless lectures, indifferent presentations, eternal monologues, stressful exams, digitally-assisted learning, interactive learning; mostly rubbish. True learning happens alone; and usually with boring tools.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Total disregard for art. Virtually everything is revolving around STEM. Art, in any form, is completely disfavoured by everyone: teachers, students, parents, lawmakers. Art's timeless honesty perpetuates the human era since its inception, yet it was deemed unworthy for the intellectual foundation of new humans.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Partial disregard for the humanities. Along with its aforementioned conceptual subclass, human disciples have fallen out of favour, as being ineffective in building wealth—the core value of our &lt;a href="https://en.wikipedia.org/wiki/Imaginary_(sociology)"&gt;imaginary&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Total disregard for physical knowledge. Disturbingly small amount of school-approved time on exercising, sports, or any other bodily activity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Existence of homework. Even the most hard working professions allow for leisure time at home.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Limited societal framework. Students learning from teachers in a restricted facility for an extraneously-defined set of hours per day. School has been shaped as a silo, when it could have been shaped as an essential integrated part of everybody's—even non-parent non-student adults'—societal life.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description><author>nutcroft</author><pubDate>Fri, 14 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/whats-wrong-with-school/</guid></item><item><title>About</title><link>https://makedist.com/about/</link><description>Welcome to makedist.</description><author>Noah Watkins</author><pubDate>Fri, 14 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://makedist.com/about/</guid></item><item><title>Running Python scripts</title><link>https://voussoir.net/writing/running_python_scripts</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class="tag_link" href="/writing/tags/python"&gt;[python]&lt;/a&gt; &lt;a class="tag_link" href="/writing/tags/tutorial"&gt;[tutorial]&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Running Python scripts&lt;/h1&gt;&lt;ol id="table_of_contents"&gt;Table of contents&lt;li&gt;&lt;a href="#level_0_pythonexe_myfilepy"&gt;Level 0: python.exe myfile.py&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#level_1_python_myfilepy"&gt;Level 1: python myfile.py&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#level_2_myfilepy"&gt;Level 2: myfile.py&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#level_3_myfilepy_on_the_path"&gt;Level 3: myfile.py on the PATH&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#level_4_myfile"&gt;Level 4: myfile&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;In this document, &lt;code&gt;C:\python&lt;/code&gt; is the folder where you installed Python to. That's where &lt;code&gt;python.exe&lt;/code&gt; lives. &lt;code&gt;C:\code&lt;/code&gt; is a folder you created where you put all the &lt;code&gt;.py&lt;/code&gt; files that you make. Lastly, &lt;code&gt;C:\anywhere&lt;/code&gt; is anywhere else on your computer that is not one of these two locations.&lt;/p&gt;
&lt;p&gt;I am using Windows style prompts with &lt;code&gt;cwd&amp;gt;&lt;/code&gt;. For Linux users, this is the same as your &lt;code&gt;user:cwd$&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="level_0_pythonexe_myfilepy"&gt;Level 0: &lt;code&gt;python.exe myfile.py&lt;/code&gt;&lt;a class="header_anchor_link" href="#level_0_pythonexe_myfilepy"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this level, you are specifying the exact location of the Python executable and the exact location of the script.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\python&amp;gt; python.exe C:\code\myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\code&amp;gt; C:\python\python.exe myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\anywhere&amp;gt; C:\python\python.exe C:\code\myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="level_1_python_myfilepy"&gt;Level 1: &lt;code&gt;python myfile.py&lt;/code&gt;&lt;a class="header_anchor_link" href="#level_1_python_myfilepy"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this level, you are letting the system find Python, but specifying the exact location of the script.&lt;/p&gt;
&lt;p&gt;When you install Python, there is an option to add Python to your PATH. The PATH is a list of directories that your computer will search every time you type a command on the command prompt. This means that when you type &lt;code&gt;python&lt;/code&gt;, it will automatically find the python.exe in your installation folder. Windows users, type "environment variable" into your Windows search bar to open the settings menu and find the variable called PATH, or &lt;code&gt;echo %PATH%&lt;/code&gt; on the cmd to see what it looks like. Linux users, &lt;code&gt;echo $PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\code&amp;gt; python myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\anywhere&amp;gt; python C:\code\myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="level_2_myfilepy"&gt;Level 2: &lt;code&gt;myfile.py&lt;/code&gt;&lt;a class="header_anchor_link" href="#level_2_myfilepy"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this level, you are specifying the exact location of the script, but do not mention Python at all, because the system knows it is a Python file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Windows:&lt;/strong&gt; Ensure that &lt;code&gt;.py&lt;/code&gt; file extensions are associated with the python.exe or py.exe that you installed. This should happen automatically when you install Python, and you can always re-run the Python installer to reset these associations if they become broken.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\code&amp;gt; myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\anywhere&amp;gt; C:\code\myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux:&lt;/strong&gt; Add a shebang for your Python executable to the top of the script file, and mark the file as executable with &lt;code&gt;chmod +x myfile.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/code$ ./myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/anywhere$ /code/myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="level_3_myfilepy_on_the_path"&gt;Level 3: &lt;code&gt;myfile.py&lt;/code&gt; on the PATH&lt;a class="header_anchor_link" href="#level_3_myfilepy_on_the_path"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this level, you do not need to specify the exact path of the script ever.&lt;/p&gt;
&lt;p&gt;Add the directory that contains the script, &lt;code&gt;C:\code&lt;/code&gt;, to your PATH. Remember that PATH is a list of directories, not files. If you add &lt;code&gt;C:\code\myfile.py&lt;/code&gt;, it won't work. You have to add the directory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\anywhere&amp;gt; myfile.py&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="level_4_myfile"&gt;Level 4: &lt;code&gt;myfile&lt;/code&gt;&lt;a class="header_anchor_link" href="#level_4_myfile"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The final level is to run Python scripts without specifying Python, or the extension, or the file's location. At this level, Python scripts feel like native commands such as &lt;code&gt;dir&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;, and &lt;code&gt;cd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Both&lt;/strong&gt;: Add the directory that contains the script to your PATH.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Windows&lt;/strong&gt;: Add &lt;code&gt;.py&lt;/code&gt; to your PATHEXT variable, so Windows will understand that when you type &lt;code&gt;myfile&lt;/code&gt;, it should also search the PATH for &lt;code&gt;myfile.py&lt;/code&gt;. Use &lt;code&gt;where myfile&lt;/code&gt; to double check that your file appears, and there is not another program with the same name taking priority.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux&lt;/strong&gt;: Keep the shebang at the top of the file, and rename the file to remove the &lt;code&gt;.py&lt;/code&gt; extension. Use &lt;code&gt;which myfile&lt;/code&gt; to double check that it is the top result.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C:\anywhere&amp;gt; myfile&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The only way to get better than this is to have a mind-controlled computer where you don't have to type anything.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/running_python_scripts/running_python_scripts.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/f2e054a12370f7dc74328690ee21eb9821863db1"&gt;&lt;time datetime="2020-08-20T10:50:48-07:00"&gt;2020-08-20&lt;/time&gt; Replace level 2.5 with 3, then 3 with 4.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/bb10ae9b2dbecdb6668ddccddde5407fe438ac1a"&gt;&lt;time datetime="2020-08-13T14:46:40-07:00"&gt;2020-08-13&lt;/time&gt; Add running_python_scripts.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Fri, 14 Aug 2020 00:46:40 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/running_python_scripts</guid></item><item><title>A Guide to Commonly Used React Component Libraries</title><link>https://maxrozen.com/guide-to-component-ui-libraries-react</link><description>There are a *lot* of React Component libraries to choose from. This guide attempts to put them all on one page.</description><author>Max Rozen</author><pubDate>Fri, 14 Aug 2020 00:37:42 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/guide-to-component-ui-libraries-react</guid></item><item><title>Wineries in the Beqaa Valley</title><link>https://zef.studio/journal/beqaa-valley-wine</link><description>Visiting Wineries in the Beqaa Valley</description><author>Zef Houssney</author><pubDate>Thu, 13 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://zef.studio/journal/beqaa-valley-wine</guid></item><item><title>The Bigger the Tos</title><link>https://rjp.is/blogging/posts/2020/08/the-bigger-the-tos/</link><description>In which we recreate an infographic.</description><author>infrequent oscillations</author><pubDate>Thu, 13 Aug 2020 14:32:21 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/08/the-bigger-the-tos/</guid></item><item><title>LinkedList 使用与分析</title><link>https://0xzhangke.github.io/computer/2020/08/13/LinkedList.html</link><description>&lt;h1 id="linkedlist"&gt;LinkedList&lt;/h1&gt;
&lt;p&gt;实现了 &lt;strong&gt;List&lt;/strong&gt; 以及 &lt;strong&gt;Deque&lt;/strong&gt; 的&lt;strong&gt;双向链表&lt;/strong&gt;，元素允许为 null，所以 LinkedList 同时具备 List 以及 Deque 的特性。
跟 ArrayList 一样，LinkedList 也是&lt;strong&gt;非线程安全&lt;/strong&gt;的，可以使用包装方法获取同步对象：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;synchronizedList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;(...));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;iterator&lt;/code&gt;以及&lt;code class="language-plaintext highlighter-rouge"&gt;listIterator&lt;/code&gt;同样也被设计为 &lt;a href="https://en.wikipedia.org/wiki/Fail-fast" title="fail-fast"&gt;fail-fast&lt;/a&gt;。
&lt;!--more--&gt;&lt;/p&gt;
&lt;h2 id="使用特性"&gt;使用特性&lt;/h2&gt;
&lt;p&gt;LinkedList 内部实现上是个&lt;strong&gt;链表&lt;/strong&gt;，所以可以把它当作&lt;strong&gt;链表&lt;/strong&gt;使用。&lt;/p&gt;

&lt;p&gt;LinkedList 同样还可以代替 Stack 类当做&lt;strong&gt;栈&lt;/strong&gt;来使用（官方也推荐这么做）。&lt;/p&gt;

&lt;p&gt;但不合适作为 &lt;strong&gt;List&lt;/strong&gt; 使用，List 相关的方法会比较耗时，性能低。&lt;/p&gt;

&lt;p&gt;链表和栈相关的操作基本都可以在&lt;strong&gt;固定时间&lt;/strong&gt;内完成，但是 List 特性的操作，也就是通过索引访问元素的方法&lt;code class="language-plaintext highlighter-rouge"&gt;get&lt;/code&gt;需要 &lt;strong&gt;O(n)&lt;/strong&gt; 的时间，不推荐使用。&lt;/p&gt;

&lt;h2 id="公开方法"&gt;公开方法&lt;/h2&gt;
&lt;p&gt;因为双端队列也是基于队列的，所以 LinkedList 中的方法大体可以分为三种：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;列表方法&lt;/li&gt;
  &lt;li&gt;队列方法&lt;/li&gt;
  &lt;li&gt;双端队列方法&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;下面分别看下。&lt;/p&gt;

&lt;h3 id="列表方法"&gt;列表方法&lt;/h3&gt;
&lt;p&gt;列表方法比较简单，这里就不赘述了，可以看 ArrayList 那一节文章。&lt;/p&gt;

&lt;h3 id="队列"&gt;队列&lt;/h3&gt;
&lt;p&gt;队列是一种先进先出（FIFO）的数据结构，Java 中的接口 Queue 描述了队列这种数据结构。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style="text-align: left;"&gt;方法名&lt;/th&gt;
      &lt;th style="text-align: left;"&gt;描述&lt;/th&gt;
      &lt;th style="text-align: left;"&gt;备注&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;add(e)&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;将元素插入队列&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;未超出容量限制则添加成功返回 true，否则抛出 IllegalStateException&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;offer(e)&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;将元素插入队列&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;未超出容量限制的情况下添加，否则返回 false&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;remove()&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;返回并删除队列的头&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;队列为空:NoSuchElementException&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;poll()&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;返回并删除队列的头&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;队列为空返回 null&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;element()&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;返回队列的头&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;队列为空:NoSuchElementException&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;peek()&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;返回队列的头&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;队列为空返回 null&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;我们可以将上表按照功能分为三类：插入、移除、检索。
每种操作又提供了两种方法：抛出异常或返回特殊值。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style="text-align: left;"&gt;操作&lt;/th&gt;
      &lt;th style="text-align: left;"&gt;抛出异常&lt;/th&gt;
      &lt;th style="text-align: left;"&gt;返回特殊值&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;插入&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;add(e)&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;offer(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;移除&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;remove()&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;poll()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;检索&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;element()&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;peek()&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;上面就是队列中提供的方法了，Java 大概是考虑到使用方便问题，所以给每种方法都提供了抛出异常或者返回特殊值的方式，也导致方法数量多了一倍，而对于双端队列来说，上述的每种方法又会多出两个，看起来很多，但我们只要知道本质上就是上述的三种操作就行，其他的都是变种而已。&lt;/p&gt;

&lt;h2 id="双端队列"&gt;双端队列&lt;/h2&gt;
&lt;p&gt;作为双端队列，比队列多出的特性将通过给队列中的每个操作方法提供两个变种方法来实现，比如队列中的 add 方法，双端队列中将提供&lt;code class="language-plaintext highlighter-rouge"&gt;addFirst&lt;/code&gt;和&lt;code class="language-plaintext highlighter-rouge"&gt;addLast&lt;/code&gt;方法，用于将元素添加到&lt;strong&gt;头&lt;/strong&gt;或者&lt;strong&gt;尾&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;由于双端队列的特性导致还可以很轻易的实现&lt;strong&gt;栈&lt;/strong&gt;的功能，可以用来替换 Stack 类来使用，所以 Deque 中又提供了两个用于实现栈结构的方法。&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style="text-align: left;"&gt;方法名&lt;/th&gt;
      &lt;th style="text-align: left;"&gt;描述&lt;/th&gt;
      &lt;th style="text-align: left;"&gt;备注&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;push(E e)&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;将元素压入栈顶&lt;/td&gt;
      &lt;td style="text-align: left;"&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style="text-align: left;"&gt;pop()&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;弹出栈的顶部元素&lt;/td&gt;
      &lt;td style="text-align: left;"&gt;列表为空抛出 NoSuchElementException&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Deque 还提供了从后向前遍历的&lt;code class="language-plaintext highlighter-rouge"&gt;descendingIterator&lt;/code&gt;的迭代器，元素将从最后一个开始遍历到第一个元素。&lt;/p&gt;

&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;下面来总结一下。
LinkedList 作为队列（&lt;strong&gt;FIFO&lt;/strong&gt;）使用时的方法：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;队列方法&lt;/th&gt;
      &lt;th&gt;等效的双端队列方法&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;add(e)&lt;/td&gt;
      &lt;td&gt;addLast(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;offer(e)&lt;/td&gt;
      &lt;td&gt;offerLast(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;remove()&lt;/td&gt;
      &lt;td&gt;removeFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;poll()&lt;/td&gt;
      &lt;td&gt;pollFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;element()&lt;/td&gt;
      &lt;td&gt;getFirst()&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;peek()&lt;/td&gt;
      &lt;td&gt;peekFirst()&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;LinkedList 作为堆栈（&lt;code class="language-plaintext highlighter-rouge"&gt;index&lt;/code&gt;）使用时的方法：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;堆栈方法&lt;/th&gt;
      &lt;th&gt;等效的双端队列方法&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;push(e)&lt;/td&gt;
      &lt;td&gt;addFirst(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;pop(e)&lt;/td&gt;
      &lt;td&gt;removeFirst(e)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;peek()&lt;/td&gt;
      &lt;td&gt;peekFirst()&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id="源码"&gt;源码&lt;/h2&gt;
&lt;p&gt;我们先看看链表的节点是如何定义的：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;因为是双向链表，所以每个节点除了保存下一个节点的引用外，还保存了上一个节点的引用。
所以与 ArrayList 不同的是，LinkedList 并不是使用数组存储数据，而是通过上面 &lt;strong&gt;Node 形成的链表来存储&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;我们先来通过一个简单的&lt;code class="language-plaintext highlighter-rouge"&gt;add&lt;/code&gt;方法看看实现：&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;linkLast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;linkLast&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
    &lt;span class="n"&gt;modCount&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;主要就调用了&lt;code class="language-plaintext highlighter-rouge"&gt;linkLast&lt;/code&gt;方法将元素添加到链表的末尾，这就是个链表的操作。
除了&lt;code class="language-plaintext highlighter-rouge"&gt;linkLast&lt;/code&gt;之外还有&lt;code class="language-plaintext highlighter-rouge"&gt;linkFirst&lt;/code&gt;用于将元素添加到链表头部。
诸如&lt;code class="language-plaintext highlighter-rouge"&gt;addFirst&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;push&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;offer&lt;/code&gt;之类的添加元素的操作最终都是通过上面两个方法实现的。&lt;/p&gt;

&lt;p&gt;再来看看移除操作&lt;code class="language-plaintext highlighter-rouge"&gt;poll&lt;/code&gt;:&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;poll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unlinkFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;unlinkFirst&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// assert f == first &amp;amp;&amp;amp; f != null;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// help GC&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;--;&lt;/span&gt;
    &lt;span class="n"&gt;modCount&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;使用&lt;code class="language-plaintext highlighter-rouge"&gt;unlinkFirst&lt;/code&gt;方法将元素从链表顶部移除，对应的还有&lt;code class="language-plaintext highlighter-rouge"&gt;unlinkLast&lt;/code&gt;方法。
同样，类似&lt;code class="language-plaintext highlighter-rouge"&gt;removeFirst&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;pop&lt;/code&gt;,&lt;code class="language-plaintext highlighter-rouge"&gt;pollFirst&lt;/code&gt;等操作也是通过上面两个方法实现的。&lt;/p&gt;

&lt;p&gt;上面的两种操作都是直接对链表的头尾操作，都可以在&lt;strong&gt;固定时间复杂度&lt;/strong&gt;内完成，实现也比较简单。
但考虑到 LinkedList 还实现了 List 接口，具备了 List 的特性，例如通过下标获取到指定值，这个实现就比较复杂了，也会消耗掉 &lt;strong&gt;O(n)&lt;/strong&gt; 的时间。&lt;/p&gt;
&lt;div class="language-java highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;E&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;checkElementIndex&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--)&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;get&lt;/code&gt;方法通过调用&lt;code class="language-plaintext highlighter-rouge"&gt;node&lt;/code&gt;方法获取到指定索引的值，由于链表的特性使然，无法直接通过索引获取到元素，需要从端点开始逐个向内遍历，直到遍历到指定索引再将元素返回。
&lt;code class="language-plaintext highlighter-rouge"&gt;node&lt;/code&gt;方法考虑到性能问题，在遍历前会先判断&lt;code class="language-plaintext highlighter-rouge"&gt;index&lt;/code&gt;值靠前还是靠后，然后选择是从头还是尾开始遍历，充分利用了双向链表的特性。&lt;/p&gt;

&lt;p&gt;好了，上面几个方法就是 LinkedList 源码中最具有代表性的几个方法了。&lt;/p&gt;</description><author>张可的博客</author><pubDate>Thu, 13 Aug 2020 13:00:03 GMT</pubDate><guid isPermaLink="true">https://0xzhangke.github.io/computer/2020/08/13/LinkedList.html</guid></item><item><title>Maybe it is time to stay away from Ancestry.com</title><link>https://stop.zona-m.net/2020/08/maybe-it-is-time-to-stay-away-from-ancestry.com/</link><description>&lt;p&gt;On the other hand&amp;hellip; what could possibly go wrong now?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 13 Aug 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/maybe-it-is-time-to-stay-away-from-ancestry.com/</guid></item><item><title>All chatbots fail this simple question</title><link>https://xosh.org/dumb-chatbots/</link><description>Try asking any chatbot something along the lines of
What did I just ask/tell you? What was my last/previous message? All of them fail. All of them.
GPT-3 is equally dumb smooth talker who can jump into any discussion, clever to detect the pattern of discussion and generate next sentences.</description><author>XOSH.ORG</author><pubDate>Thu, 13 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xosh.org/dumb-chatbots/</guid></item><item><title>More news from CloudHaven</title><link>https://stop.zona-m.net/2020/08/more-news-from-cloudhaven/</link><description>&lt;p&gt;More interesting news from your &amp;ldquo;Sovereign Home in the Cloud&amp;rdquo;.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 13 Aug 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/more-news-from-cloudhaven/</guid></item><item><title>Realtime Offline-First Chat App in 100 Seconds</title><link>https://www.swyx.io/realtime-offline-first-chat-app-in-100-seconds-with-amplify-datastore-react-and-graphql-47d4</link><description>A quick demo of how easy it is to add realtime, offline persistence to an app with Amplify DataStore</description><author>swyx's site RSS Feed</author><pubDate>Thu, 13 Aug 2020 01:27:32 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/realtime-offline-first-chat-app-in-100-seconds-with-amplify-datastore-react-and-graphql-47d4</guid></item><item><title>Degoogling</title><link>https://blog.flurdy.com/2020/08/degoogling.html</link><description>Degoogling myself</description><author>flurdy’s ranting</author><pubDate>Thu, 13 Aug 2020 00:12:00 GMT</pubDate><guid isPermaLink="true">https://blog.flurdy.com/2020/08/degoogling.html</guid></item><item><title>A Developer's Guide to Startup Fundraising</title><link>https://www.swyx.io/brief-guide-to-startup-fundraising-terminology-7k2</link><description>A Brief Guide to Startup Fundraising Terminology for Beginners</description><author>swyx's site RSS Feed</author><pubDate>Wed, 12 Aug 2020 03:21:55 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/brief-guide-to-startup-fundraising-terminology-7k2</guid></item><item><title>Moves, copies and clones in Rust</title><link>https://hashrust.com/blog/moves-copies-and-clones-in-rust/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Moves and copies are fundamental concepts in Rust. These might be completely new to programmers coming from garbage collected languages like Ruby, Python or C#. While these terms do exist in C++, their meaning in Rust is subtly different. In this post I'll explain what it means for values to be moved, copied or cloned in Rust. Let's dive in.&lt;/p&gt;
&lt;h2 id="moves"&gt;Moves&lt;/h2&gt;
&lt;p&gt;As shown in &lt;a href="https://hashrust.com/blog/memory-safety-in-rust-part-2/"&gt;&lt;em&gt;Memory safety in Rust - part 2&lt;/em&gt;&lt;/a&gt;, assigning one variable to another transfers the ownership to the assignee:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//v1 is the new owner&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, &lt;code&gt;v&lt;/code&gt; is moved to &lt;code&gt;v1&lt;/code&gt;. But what does it mean to &lt;em&gt;move&lt;/em&gt; &lt;code&gt;v&lt;/code&gt;? To understand that, we need to see how a &lt;a href="https://doc.rust-lang.org/std/vec/struct.Vec.html" rel="external"&gt;&lt;code&gt;Vec&lt;/code&gt;&lt;/a&gt; is laid out in memory:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="vector memory layout" src="https://hashrust.com/blog/moves-copies-and-clones-in-rust/vector-layout.svg" /&gt;&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;Vec&lt;/code&gt; has to maintain a dynamically growing or shrinking buffer. This buffer is allocated on the heap and contains the actual elements of the &lt;code&gt;Vec&lt;/code&gt;. In addition, a &lt;code&gt;Vec&lt;/code&gt; also has a small object on the stack. This object contains some housekeeping information: a pointer to the buffer on the heap, the capacity of the buffer and the length (i.e. how much of the capacity is currently filled).&lt;/p&gt;
&lt;p&gt;When the variable &lt;code&gt;v&lt;/code&gt; is moved to &lt;code&gt;v1&lt;/code&gt;, the object on the stack is bitwise copied:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="what happens when a vector is moved" src="https://hashrust.com/blog/moves-copies-and-clones-in-rust/vector-layout-moved.svg" /&gt;&lt;/p&gt;
&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
        What has essentially happened in the previous example is a shallow copy. This is in stark contrast to C++, which makes a deep copy when a vector is assigned to another variable.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;p&gt;The buffer on the heap stays intact. This is indeed a move: it is now &lt;code&gt;v1&lt;/code&gt;'s responsibility to drop the heap buffer and &lt;code&gt;v&lt;/code&gt; can't touch it:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v's length is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;span class="z-comment"&gt;//error: borrow of moved value: `v`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This change of ownership is good because if access was allowed through both &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;v1&lt;/code&gt; then you will end up with two stack objects pointing to the same heap buffer:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="if two vectors  shared a buffer" src="https://hashrust.com/blog/moves-copies-and-clones-in-rust/vector-layout-shared-buffer.svg" /&gt;&lt;/p&gt;
&lt;p&gt;Which object should drop the buffer in this case? Because that is not clear, Rust prevents this situation from arising at all.&lt;/p&gt;
&lt;p&gt;Assignment is not the only operation which involves moves. Values are also moved when passed as arguments or returned from functions:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//v is first moved into print_len's v1&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//and then moved into v2 when print_len returns it&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_len&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; print_len&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v1's length is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    v1&lt;/span&gt;&lt;span class="z-comment"&gt;//v1 is moved out of the function&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or assigned to members of a struct or enum:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Numbers&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    nums&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//v moved into nums field of the Numbers struct&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; n&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Numbers&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span class="z-variable"&gt; nums&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;enum&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; NothingOrString&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-type"&gt;    Nothing&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    Str&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;String&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; s&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; String&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; &amp;quot;I am moving soon&amp;quot;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;to_string&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//s moved into the enum&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; nos&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; NothingOrString&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;Str&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-variable"&gt;s&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's all about moves. Next let's take a look at copies.&lt;/p&gt;
&lt;h2 id="copies"&gt;Copies&lt;/h2&gt;
&lt;p&gt;Remember this example from above?:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v's length is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;span class="z-comment"&gt;//error: borrow of moved value: `v`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What happens if we change the type of the variables &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;v1&lt;/code&gt; from &lt;code&gt;Vec&lt;/code&gt; to &lt;code&gt;i32&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 42&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span class="z-comment"&gt;//compiles fine, no error!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is almost the same code. Why doesn't the assignment operator move &lt;code&gt;v&lt;/code&gt; into &lt;code&gt;v1&lt;/code&gt; this time? To see that, let's take a look at the memory layout again:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="i32 layout" src="https://hashrust.com/blog/moves-copies-and-clones-in-rust/i32-layout.svg" /&gt;&lt;/p&gt;
&lt;p&gt;In this example the values are contained entirely in the stack. There is nothing to own on the heap. That is why it is ok to allow access through both &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;v1&lt;/code&gt; — they are completely independent copies.&lt;/p&gt;
&lt;p&gt;Such types which do not own other resources and can be bitwise copied are called &lt;code&gt;Copy&lt;/code&gt; types. They implement the &lt;a href="https://doc.rust-lang.org/std/marker/trait.Copy.html" rel="external"&gt;&lt;code&gt;Copy&lt;/code&gt; marker trait&lt;/a&gt;. All primitive types like integers, floats and characters are &lt;code&gt;Copy&lt;/code&gt;. Structs or enums are not &lt;code&gt;Copy&lt;/code&gt; by default but you can derive the &lt;code&gt;Copy&lt;/code&gt; trait:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;#[derive(&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Copy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Clone&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    y&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;#[derive(&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Copy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Clone&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;enum&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; SignedOrUnsignedInt&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    Signed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;    Unsigned&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;u32&lt;/span&gt;&lt;span&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
&lt;code&gt;Clone&lt;/code&gt; in the derive clause is needed because &lt;code&gt;Copy&lt;/code&gt; is defined like this: &lt;code&gt;pub trait Copy: Clone {}&lt;/code&gt;
    &lt;/aside&gt;
&lt;/div&gt;
&lt;p&gt;For &lt;code&gt;#[derive(Copy, Clone)]&lt;/code&gt; to work, all the members of the struct or enum must be &lt;code&gt;Copy&lt;/code&gt; themselves. For example, this will not work:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//error:the trait `Copy` may not be implemented for this type&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//because its nums field does not implement `Copy`&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;#[derive(&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Copy&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Clone&lt;/span&gt;&lt;span&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Numbers&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    nums&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can of course also implement &lt;code&gt;Copy&lt;/code&gt; and &lt;code&gt;Clone&lt;/code&gt; manually:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;struct&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    x&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;    y&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;//no method in Copy because it is a marker trait&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;impl&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Copy&lt;/span&gt;&lt;span class="z-keyword"&gt; for&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Point&lt;/span&gt;&lt;span&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;impl&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Clone&lt;/span&gt;&lt;span class="z-keyword"&gt; for&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword"&gt;    fn&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; clone&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;&amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;self&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; -&amp;gt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Point&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-operator"&gt;        *&lt;/span&gt;&lt;span class="z-variable"&gt;self&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In general, any type that implements &lt;a href="https://doc.rust-lang.org/std/ops/trait.Drop.html" rel="external"&gt;&lt;code&gt;Drop&lt;/code&gt;&lt;/a&gt; cannot be &lt;code&gt;Copy&lt;/code&gt; because &lt;code&gt;Drop&lt;/code&gt; is implemented by types which own some resource and hence cannot be simply bitwise copied. But &lt;code&gt;Copy&lt;/code&gt; types should be trivially copyable. Hence, &lt;code&gt;Drop&lt;/code&gt; and &lt;code&gt;Copy&lt;/code&gt; don't mix well.&lt;/p&gt;
&lt;p&gt;And that's all about copies. On to clones.&lt;/p&gt;
&lt;h2 id="clones"&gt;Clones&lt;/h2&gt;
&lt;p&gt;When a value is moved, Rust does a shallow copy; but what if you want to create a deep copy like in C++? To allow that, a type must first implement the &lt;a href="https://doc.rust-lang.org/std/clone/trait.Clone.html" rel="external"&gt;&lt;code&gt;Clone&lt;/code&gt; trait&lt;/a&gt;. Then to make a deep copy, client code should call the &lt;code&gt;clone&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;clone&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//ok since Vec implements Clone&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt;&amp;quot;v's length is &lt;/span&gt;&lt;span class="z-punctuation z-definition z-interpolation"&gt;{}&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string"&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;());&lt;/span&gt;&lt;span class="z-comment"&gt;//ok&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This results in the following memory layout after the &lt;code&gt;clone&lt;/code&gt; call:&lt;/p&gt;
&lt;p class="img-p"&gt;&lt;img alt="cloned vector memory layout" src="https://hashrust.com/blog/moves-copies-and-clones-in-rust/vector-layout-cloned.svg" /&gt;&lt;/p&gt;
&lt;p&gt;Due to deep copying, both &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;v1&lt;/code&gt; are free to independently drop their heap buffers.&lt;/p&gt;
&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
The &lt;code&gt;clone&lt;/code&gt; method doesn't always create a deep copy. Types are free to implement &lt;code&gt;clone&lt;/code&gt; any way they want, but semantically it should be close enough to the meaning of duplicating an object. For example, &lt;a href="https://doc.rust-lang.org/std/rc/struct.Rc.html"&gt;&lt;code&gt;Rc&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://doc.rust-lang.org/std/sync/struct.Arc.html"&gt;&lt;code&gt;Arc&lt;/code&gt;&lt;/a&gt; increment a reference count instead.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;p&gt;And that's all about clones.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post I took a deeper look at semantics of moves, copies and clones in Rust. I have tried to capture the nuance in meaning when compared with C++.&lt;/p&gt;
&lt;p&gt;Rust is great because it has great defaults. For example, the assignment operator in Rust either moves values or does trivial bitwise copies. In C++, on the other hand, an innocuous looking assignment can hide loads of code that runs as part of overloaded assignment operators. In Rust, such code is brought into the open because the programmer has to explicitly call the &lt;code&gt;clone&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;One could argue that both languages make different trade-offs but I like the extra safety guarantees Rust brings to the table due to these design choices.&lt;/p&gt;</description><author/><pubDate>Wed, 12 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hashrust.com/blog/moves-copies-and-clones-in-rust/</guid></item><item><title>Packaging Small Clojure Apps</title><link>https://mschaef.com/packaging_small_clojure_apps</link><description>&lt;p&gt;Like a lot of engineers, I have a handful of personal projects I keep around for various reasons. Some are useful and some are just for fun, but none of them get the same sort of investment as a funded commercial effort. The consequence of this is that it's all the more important to keep things as simple as possible, to focus the investment where it counts. Part of the way I achieve that is that I've spent some initial time putting together a standard packaging approach. I know, I know - &lt;em&gt;"standard packaging approach"&lt;/em&gt; doesn't sound like &lt;em&gt;"fun personal project"&lt;/em&gt; - but getting the packaging out of the way makes it easier to focus on the actual fun part - building out functionality. It's for that reason that I've also successfully used variants of this approach on smaller commercial projects too. Hopefully, this will be useful to you too.&lt;/p&gt;&lt;p&gt;Setting the state, the top level view is this:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Uberjar packaging of single binaries using &lt;a href="https://leiningen.org/"&gt;Leiningen&lt;/a&gt; and a few plugins.&lt;/li&gt;&lt;li&gt;Standard scripts and tools for packaging and install.&lt;/li&gt;&lt;li&gt;Use of existing Linux mechanisms for service control.&lt;/li&gt;&lt;li&gt;A heavy tendancy toward &lt;a href="https://12factor.net/"&gt;12 Factor&lt;/a&gt; principles.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;What this gets you is a good local interactive development story and easy deployment to a server. I've also gotten it to work with Client side code too, using &lt;a href="https://figwheel.org/"&gt;Figwheel&lt;/a&gt;&lt;/p&gt;&lt;p&gt;What it doesn't get you is direct support for large numbers of processes or servers.  Modern hardware is fast and capable, so you may not have those requirements, but if you do, you'll need something heavier weight, to reduce both management overhead and costs. (In my &lt;a href="https://projectdabl.com/"&gt;day job&lt;/a&gt;, we've done some amazing things with &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;.)&lt;/p&gt;&lt;p&gt;The example project I'm going to use is the engine for this blog, &lt;a href="https://github.com/mschaef/rhinowiki"&gt;Rhinowiki&lt;/a&gt;. It's useful, but simple enough to be used as a model for a packaging approach. If you're also interested in strategies for managing apps with read/write persistance (SQL) and rich client code, I have a couple other programs packaged this way with those features. Even with these, the essentials of the packaging strategy are exactly the same as what I describe here:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/mschaef/toto"&gt;Toto&lt;/a&gt; - Web app with persistance  to an embedded SQL database managed with  &lt;a href="https://github.com/mschaef/sql-file"&gt;sql-file&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/mschaef/metlog"&gt;Metlog&lt;/a&gt; - Single Page App done  with a Clojure back end, &lt;a href="https://reagent-project.github.io/"&gt;Reagent&lt;/a&gt;,  &lt;a href="https://clojurescript.org/"&gt;ClojureScript&lt;/a&gt;, and &lt;a href="https://figwheel.org/"&gt;Figwheel&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Everything begins with a traditional &lt;a href="https://github.com/mschaef/rhinowiki/blob/master/project.clj"&gt;&lt;code&gt;project.clj&lt;/code&gt;&lt;/a&gt;, and the project can be started locally with the usual &lt;code&gt;lein run&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;Once running, &lt;code&gt;main&lt;/code&gt; immediately writes a herald log message at &lt;code&gt;info&lt;/code&gt; level:&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;(&lt;span class="hljs-keyword"&gt;defn&lt;/span&gt; &lt;span class="hljs-title"&gt;-main&lt;/span&gt; [&amp;amp; args]
  (&lt;span class="hljs-name"&gt;log/info&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;Starting Rhinowiki&amp;quot;&lt;/span&gt; (&lt;span class="hljs-name"&gt;get-version&lt;/span&gt;))
  (&lt;span class="hljs-name"&gt;&lt;span class="hljs-built_in"&gt;let&lt;/span&gt;&lt;/span&gt; [config (&lt;span class="hljs-name"&gt;load-config&lt;/span&gt;)]
    (&lt;span class="hljs-name"&gt;log/debug&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;config&amp;quot;&lt;/span&gt; config)
    (&lt;span class="hljs-name"&gt;webserver/start&lt;/span&gt; (&lt;span class="hljs-symbol"&gt;:http-port&lt;/span&gt; config)
                     (&lt;span class="hljs-name"&gt;blog/blog-routes&lt;/span&gt; (&lt;span class="hljs-name"&gt;blog/blog-init&lt;/span&gt; config)))
    (&lt;span class="hljs-name"&gt;log/info&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;end run.&amp;quot;&lt;/span&gt;)))
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;This immediately lets you know the process has started, logs are working, and which version of the code is running. These are usually the first things verified after an install, so it's good to ensure they happen early on. This is particularly useful for software that's not interactive or running on slow hardware. (I've run some of this code on Raspberry Pi hardware that takes ten or so seconds to get to the startup herald.)&lt;/p&gt;&lt;p&gt;The way the version is acquired is interesting too. The call to &lt;code&gt;get-version&lt;/code&gt; is really a macro invocation and not a function call.&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;(&lt;span class="hljs-keyword"&gt;defmacro&lt;/span&gt; &lt;span class="hljs-title"&gt;get-version&lt;/span&gt; []
  &lt;span class="hljs-comment"&gt;;; Capture compile-time property definition from Lein&lt;/span&gt;
  (&lt;span class="hljs-name"&gt;System/getProperty&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;rhinowiki.version&amp;quot;&lt;/span&gt;))

&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;Because macros are evaluated at compile time, the macroexpansion of &lt;code&gt;get-version&lt;/code&gt; has access to JVM properties defined at build time by Leiningen.&lt;/p&gt;&lt;p&gt;The next step is to pull in configuration settings using Anatoly Polinsky's &lt;a href="cprop"&gt;https://github.com/tolitius/cprop&lt;/a&gt; library. &lt;code&gt;cprop&lt;/code&gt; can do more than what I use it for here, but here, I use it to load a single EDN config file. &lt;code&gt;cprop&lt;/code&gt; lets the name of that file be identified at startup via a system proprety, making it possible to define a file for each server, as well as a local config file specified in: &lt;code&gt;project.clj&lt;/code&gt;.&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;&lt;span class="hljs-symbol"&gt;:jvm-opts&lt;/span&gt; [&lt;span class="hljs-string"&gt;&amp;quot;-Dconf=local-config.edn&amp;quot;&lt;/span&gt;]
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;I've also found it useful to minimize the number and power of configuration settings. Every setting that changes is a risk that something will break when you promote code. Every setting that doesn't change is a risk of introducing a bug in the settings code.&lt;/p&gt;&lt;p&gt;I also dump the configugration to a log very early in the startup process.&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;(&lt;span class="hljs-name"&gt;log/debug&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;config&amp;quot;&lt;/span&gt; config)
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;Given the importance of configuration settings, it's occasionally important to be able to inspect the settings in use at run-time. However, this log is written at &lt;code&gt;debug&lt;/code&gt; level, so it doesn't normally print. This reduces the risk of accidentally revealing secret keys in the log stream. Depending on the importance of those keys, there is also much more you can do to protect them, if preventing the risk is worth the effort.&lt;/p&gt;&lt;p&gt;After all that's done, &lt;code&gt;main&lt;/code&gt; transfers control over to the actual application:&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;(&lt;span class="hljs-name"&gt;webserver/start&lt;/span&gt; (&lt;span class="hljs-symbol"&gt;:http-port&lt;/span&gt; config)
                 (&lt;span class="hljs-name"&gt;blog/blog-routes&lt;/span&gt; (&lt;span class="hljs-name"&gt;blog/blog-init&lt;/span&gt; config)))
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;With a configurable application running, the next step is to get it packaged in a way that lets us predictably install it elsewhere. The strategy here is a two step approach: build the code as an uberjar and include the uberjar in a self-contained &lt;code&gt;.tar.gz&lt;/code&gt; as an installation pacakge.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The installer package contains everything needed to install the  software (the one exception being the JVM itself).&lt;/li&gt;&lt;li&gt;The package name includes the version number of the software:  &lt;code&gt;rhinowiki-0.3.3.tar.gz&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Files in the installation package all have a prefix  (&lt;code&gt;rhinowiki-install&lt;/code&gt;, in this case) to confine the installation  files to a single directory when installing. This is to make it easy  to avoid crosstalk between multiple installers and delete installation  directories after you're done with an installation.&lt;/li&gt;&lt;li&gt;There is an &lt;a href="/?tag=idempotence"&gt;idempotent&lt;/a&gt; installation script  (&lt;a href="https://github.com/mschaef/rhinowiki/blob/master/pkg/install.sh"&gt;&lt;code&gt;install.sh&lt;/code&gt;&lt;/a&gt;)  at the root of the package. Running this script either creates or  updates an installation.&lt;/li&gt;&lt;li&gt;The software is installed as a  &lt;a href="https://github.com/mschaef/rhinowiki/blob/master/pkg/rhinowiki"&gt;Linux service&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The net result of this packaging in an installation/upgrade process that works like this:&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="bash"&gt;&lt;pre&gt;tar xzvf rhinowiki-0.3.3.tar.gz
&lt;span class="hljs-built_in"&gt;cd&lt;/span&gt; rhinowiki-install
&lt;span class="hljs-built_in"&gt;sudo&lt;/span&gt; service rhinowiki stop
&lt;span class="hljs-built_in"&gt;sudo&lt;/span&gt; ./install.sh
&lt;span class="hljs-built_in"&gt;sudo&lt;/span&gt; service rhinowiki start
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;To get to this point, I use the &lt;a href="https://leiningen.org/"&gt;Leiningen&lt;/a&gt; &lt;code&gt;release&lt;/code&gt; task and the &lt;a href="https://github.com/technomancy/lein-tar"&gt;&lt;code&gt;lein-tar&lt;/code&gt;&lt;/a&gt; plugin, both originally by Phil Hagelberg. There's a &lt;a href="https://github.com/mschaef/rhinowiki/blob/master/package.sh"&gt;wrapper script&lt;/a&gt;, but the essential command is &lt;code&gt;lein clean &amp;amp;&amp;amp; lein release $RELEASE&amp;#95;LEVEL&lt;/code&gt;. This instructs Leiningen to execute a series of tasks listed in the &lt;a href="https://github.com/mschaef/rhinowiki/blob/master/project.clj#L42"&gt;&lt;code&gt;release-tasks&lt;/code&gt; key in &lt;code&gt;project.clj&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;I've had to modify Leiningen's default list of release tasks, in two ways: I skip signing of tagged releases in git, and I invoke &lt;code&gt;lein-tar&lt;/code&gt; rather than &lt;code&gt;deploy&lt;/code&gt;. However, the full task list needs to be [completely restated in &lt;code&gt;project.clj&lt;/code&gt;](https://github.com/mschaef/rhinowiki/blob/master/project.clj#L42), so it's a lengthy setting.&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;&lt;span class="hljs-symbol"&gt;:release-tasks&lt;/span&gt; [[&lt;span class="hljs-string"&gt;&amp;quot;vcs&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;assert-committed&amp;quot;&lt;/span&gt;]
                [&lt;span class="hljs-string"&gt;&amp;quot;change&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;version&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;leiningen.release/bump-version&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;release&amp;quot;&lt;/span&gt;]
                [&lt;span class="hljs-string"&gt;&amp;quot;vcs&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;commit&amp;quot;&lt;/span&gt;]
                [&lt;span class="hljs-string"&gt;&amp;quot;vcs&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;tag&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;--no-sign&amp;quot;&lt;/span&gt; ]
                [&lt;span class="hljs-string"&gt;&amp;quot;tar&amp;quot;&lt;/span&gt;]
                [&lt;span class="hljs-string"&gt;&amp;quot;change&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;version&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;leiningen.release/bump-version&amp;quot;&lt;/span&gt;]
                [&lt;span class="hljs-string"&gt;&amp;quot;vcs&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;commit&amp;quot;&lt;/span&gt;]
                [&lt;span class="hljs-string"&gt;&amp;quot;vcs&amp;quot;&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;push&amp;quot;&lt;/span&gt;]]
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;The configuration for &lt;code&gt;lein-tar&lt;/code&gt; is more straightforward - include the plugin, and specify a few options. The options request that the packaged output be written in the project root, include an uberjar, and extract into an install directory rather than just CWD.&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;&lt;span class="hljs-symbol"&gt;:plugins&lt;/span&gt; [[lein-ring &lt;span class="hljs-string"&gt;&amp;quot;0.9.7&amp;quot;&lt;/span&gt;]
          [lein-tar &lt;span class="hljs-string"&gt;&amp;quot;3.3.0&amp;quot;&lt;/span&gt;]]

&lt;span class="hljs-comment"&gt;;; ...&lt;/span&gt;

&lt;span class="hljs-symbol"&gt;:tar&lt;/span&gt; {&lt;span class="hljs-symbol"&gt;:uberjar&lt;/span&gt; &lt;span class="hljs-literal"&gt;true&lt;/span&gt;
      &lt;span class="hljs-symbol"&gt;:format&lt;/span&gt; &lt;span class="hljs-symbol"&gt;:tar-gz&lt;/span&gt;
      &lt;span class="hljs-symbol"&gt;:output-dir&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;
      &lt;span class="hljs-symbol"&gt;:leading-path&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;rhinowiki-install&amp;quot;&lt;/span&gt;}
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;Give the uberjar a specific fixed name:&lt;/p&gt;&lt;div class="codeblock"&gt;&lt;code class="clojure"&gt;&lt;pre&gt;&lt;span class="hljs-symbol"&gt;:uberjar-name&lt;/span&gt; &lt;span class="hljs-string"&gt;&amp;quot;rhinowiki-standalone.jar&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/code&gt;&lt;/div&gt;&lt;p&gt;And populate it with a few files additional to the uberjar itself - &lt;code&gt;lein-tar&lt;/code&gt; accepts these files in &lt;a href="https://github.com/mschaef/rhinowiki/tree/master/pkg"&gt;&lt;code&gt;pkg/&lt;/code&gt;&lt;/a&gt; at the root of the project directory hierarchy. These files include everything else needed to install the application - a configuration map for &lt;code&gt;cprop&lt;/code&gt;, an install script, a service script, and log configuration.&lt;/p&gt;&lt;p&gt;The install script is the last part of the process. It's an &lt;a href="/?tag=idempotence"&gt;idempotent&lt;/a&gt; script that, when run on a server as &lt;code&gt;sudo&lt;/code&gt;, guarantees that the application is installed. It sets up users and groups, copies files from the package to wherever they belong, and uses &lt;a href="http://manpages.ubuntu.com/manpages/xenial/man8/update-rc.d.8.html"&gt;&lt;code&gt;update-rc.d&lt;/code&gt;&lt;/a&gt; to ensure that the service scripts are correctly installed.&lt;/p&gt;&lt;p&gt;This breaks down the packaging and installation process to the following:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;./package.sh&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;scp&lt;/code&gt; package tarball to server and &lt;code&gt;ssh&lt;/code&gt; in&lt;/li&gt;&lt;li&gt;Extract the package - &lt;code&gt;tar xzvf rhinowiki-0.3.3.tar.gz&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Change into the expanded package directory - &lt;code&gt;cd rhinowiki-install&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Stop any existing instances of the service - &lt;code&gt;sudo service rhinowiki stop&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Run the install script - &lt;code&gt;sudo ./install.sh&lt;/code&gt;&lt;/li&gt;&lt;li&gt;(Re)Start the service - &lt;code&gt;sudo service rhinowiki start&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;At this point, I've sketched out the approach end to end, and I hope it's evident that this can be used in fairly simple scenarios.  Before I close, let me also talk about a few sharp edges to be aware of. Like every other engineering approach, this packaging strategy has tradeoffs, and some of these tradeoffs require specific compromises.&lt;/p&gt;&lt;p&gt;The first is that this approach requires dependencies (notably the JVM) to be manually installed on target servers. For smaller environments, this can be acceptable, for larger numbers of target VM's, almost definately not.&lt;/p&gt;&lt;p&gt;The second is that there's nothing about persistance in this approach. It either needs to be managed externally, or the entire persistance story needs to be internal to the deployed uberjar. This is why I wrote &lt;a href="https://github.com/mschaef/sql-file"&gt;&lt;code&gt;sql-file&lt;/code&gt;&lt;/a&gt;, which provides a built in SQL database with schema migration support. Another approach is just to handle it altogether externally, which is what I do for Rhinowiki. The Rhinowiki store is a git repository, and it's managed out of band with respect to the deployment of Rhinowiki itself.&lt;/p&gt;&lt;p&gt;But these are both specific problems that can be managed for smaller applications. Often times, it's worth the costs associated with these problems, to gain the benefits of reducing the number of software components and moving pieces. If you're in a situation like that, I hope you give this approach a try and find it useful. Please let me know if you do.&lt;/p&gt;</description><author>Mike Schaeffer</author><pubDate>Wed, 12 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://mschaef.com/packaging_small_clojure_apps</guid></item><item><title>Seastar's deleter utility</title><link>https://makedist.com/posts/2020/08/12/seastars-deleter-utility/</link><description>A souped up tool for building RAII objects.</description><author>Noah Watkins</author><pubDate>Wed, 12 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://makedist.com/posts/2020/08/12/seastars-deleter-utility/</guid></item><item><title>On Work, Money and PURPOSE, Part 1</title><link>https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-1/</link><description>&lt;p&gt;What do we REALLY mean by &amp;ldquo;work&amp;rdquo;?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 11 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/on-work-money-and-purpose-part-1/</guid></item><item><title>How I fixed one hardware issue with another one</title><link>https://ounapuu.ee/posts/2020/08/11/how-i-fixed-one-hardware-issue-with-another-one/</link><description>Two issues make a solution after all.</description><author>./techtipsy</author><pubDate>Tue, 11 Aug 2020 19:08:14 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/08/11/how-i-fixed-one-hardware-issue-with-another-one/</guid></item><item><title>Multiple urls for a git remote</title><link>https://heitorpb.github.io/bla/git-multiple-remotes/</link><description>How to use multiple git remotes for easier repository management.</description><author>Heitor's log</author><pubDate>Tue, 11 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://heitorpb.github.io/bla/git-multiple-remotes/</guid></item><item><title>Come and say hi</title><link>https://sonnet.io/posts/hi/</link><description>&lt;blockquote&gt;
&lt;p&gt;Are you working on something new, exciting or weird?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Are you learning about a new piece of tech or just looking for someone to bounce off an idea that has been haunting you for some time?&lt;/p&gt;
&lt;p&gt;Brilliant!&lt;/p&gt;
&lt;p&gt;I'm available throughout the week for a &lt;a href="https://calendly.com/hey_hey" rel="noopener" target="_blank"&gt;coffee and a chat&lt;/a&gt; about ideas big and small. There's no specific format to this—ask me any question and I'll see if I can help, free of charge.&lt;/p&gt;
&lt;p&gt;I also have a &lt;a href="https://calendly.com/hey_hey/60min" rel="noopener" target="_blank"&gt;bi-weekly 2h slot&lt;/a&gt; which I use for pair programming and mentoring sessions with friends, old and new.&lt;/p&gt;
&lt;p&gt;Should none if this suit you, feel free to call me for a &lt;a href="https://calendly.com/hey_hey/3-minute-rant"&gt;delicious 3 minute rant&lt;/a&gt;. It's simple: you rant, I listen.&lt;/p&gt;
&lt;p&gt;We spend the remaining 7 minutes staring into the void, contemplating the pointlessness of our endeavors and the strange pleasure of hyperventilation.&lt;/p&gt;
&lt;p&gt;A few days later I might text you back with a solution to your problem.&lt;/p&gt;
&lt;p&gt;Honestly though, I'm just curious to see who you are and what you've been up to.&lt;/p&gt;
&lt;p&gt;&lt;a class="post__cta" href="https://calendly.com/hey_hey" rel="noopener" target="_blank"&gt;Come and say hi&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="topics"&gt;Example topics&lt;/h3&gt;
&lt;p&gt;(In no specific order)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Product Development, from MVP to enterprise (prototyping workflows and scale)&lt;/li&gt;
&lt;li&gt;Privacy, the impact of AdTech on our society&lt;/li&gt;
&lt;li&gt;Design Thinking, Human-Centred Design&lt;/li&gt;
&lt;li&gt;Photography (film, digital, medium and small format)&lt;/li&gt;
&lt;li&gt;Mental health&lt;/li&gt;
&lt;li&gt;The Web Platform (browsers, standards, Google being an utter &lt;span title="It's an ass"&gt;🐴&lt;/span&gt;, the history of the Web)&lt;/li&gt;
&lt;li&gt;Emerging Technologies (AR, VR, ML/NLP)&lt;/li&gt;
&lt;li&gt;Pair programming (I'd love to &lt;a href="https://calendly.com/hey_hey/60min"&gt;pair with you&lt;/a&gt; on your own problem)&lt;/li&gt;
&lt;li&gt;Agile/XP, TDD, pair programming&lt;/li&gt;
&lt;li&gt;AdTech, Pharma, Publishing, SaaS&lt;/li&gt;
&lt;li&gt;Software Engineering (web, mobile, AR, backend, game-dev, infra)&lt;/li&gt;
&lt;li&gt;Linguistics incl. NLP&lt;/li&gt;
&lt;li&gt;Game Development (Unity, C#, web) and Game Design (methodologies and tools)&lt;/li&gt;
&lt;li&gt;How to make an amazing Cacio e Pepe (and why 🇮🇹 + 🇰🇷 = ❤️)&lt;/li&gt;
&lt;li&gt;How to draw poorly but regularly&lt;/li&gt;
&lt;li&gt;Being &lt;s&gt;an engineer, lead, CTO or consultant&lt;/s&gt; confused human working for Startups, scale-ups and enterprise&lt;/li&gt;
&lt;li&gt;Remote work, living abroad&lt;/li&gt;
&lt;/ul&gt;</description><author>Rafał Pastuszak</author><pubDate>Tue, 11 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://sonnet.io/posts/hi/</guid></item><item><title>5 Q&amp;amp;A's on Writing and Selling My First Book</title><link>https://www.swyx.io/5-q-a-s-on-writing-and-selling-my-first-book-18d1</link><description>I answered some questions from someone planning to write their first book</description><author>swyx's site RSS Feed</author><pubDate>Tue, 11 Aug 2020 02:24:57 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/5-q-a-s-on-writing-and-selling-my-first-book-18d1</guid></item><item><title>How to use SVGs in your React App</title><link>https://maxrozen.com/how-to-use-svg-react-app</link><description>Using SVG icons instead of PNG or JPG has a few performance benefits, but they're not always straightforward to use. Here's how you do it.</description><author>Max Rozen</author><pubDate>Tue, 11 Aug 2020 00:37:42 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/how-to-use-svg-react-app</guid></item><item><title>Restarting after a COVID-full spring, and summer</title><link>https://stop.zona-m.net/2020/08/restarting-after-a-covid-full-spring-and-summer/</link><description>&lt;p&gt;One post at a time. Please help.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 10 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/08/restarting-after-a-covid-full-spring-and-summer/</guid></item><item><title>Data Paradigms in TCL: Associative Arrays vs Dictionaries</title><link>https://jmthornton.net/blog/p/tcl-paradigms</link><description>Understanding the fundamental differences between TCL's associative arrays and dictionaries, and when to use each.</description><author>Blog by Jade Michael Thornton</author><pubDate>Mon, 10 Aug 2020 18:00:00 GMT</pubDate><guid isPermaLink="true">https://jmthornton.net/blog/p/tcl-paradigms</guid></item><item><title>A brand new RSS feed appeared!</title><link>https://explog.in/rss.html#org649b812</link><description>&lt;p&gt;
    This structure of this blog is almost completely maintained by hand: I
    manually add entries to the index page, often going back to edit
    existing posts, and several entries are perennial -- such as my Book
    list, as well as the syntopical collections on different sets of
    books.
    &lt;/p&gt;

    &lt;p&gt;
    That makes it fairly tricky to automate an RSS feed: at the same time,
    enough (4) people have directly reached out to request one. Instead of
    spending a lot of time building automation that will will inevitably
    frustrate me, I've decided to maintain it by hand instead (with &lt;code&gt;ox-rss&lt;/code&gt;
    for exports). That means that there aren't going to be any entries for
    my older posts unless I happen to go back and significantly rewrite &amp;amp; update them.
    &lt;/p&gt;

    &lt;p&gt;
    If you happen to be new -- welcome! -- and I hope you find the content
    worth your time; and I'd love any feedback. A semi-curated selection:
    &lt;/p&gt;

    &lt;p&gt;
    &lt;b&gt;On Emacs&lt;/b&gt;
    &lt;/p&gt;
    &lt;ul class="org-ul"&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/writingsetup.html"&gt;My writing setup&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/tmux.html"&gt;Using Tmux with Emacs&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/poet.html"&gt;Building poet, my Emacs theme&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://explog.in/config.html"&gt;The configuration behind the blog&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;
    &lt;b&gt;On Software engineering&lt;/b&gt;
    &lt;/p&gt;
    &lt;ul class="org-ul"&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/debugging.html"&gt;Metacognition on Debugging&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/units.html"&gt;Always! include units&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/nbstyle.html"&gt;A style guide for computational notebooks&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/settrace.html"&gt;Using Python's &lt;code&gt;settrace&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;
    &lt;b&gt;On Books&lt;/b&gt;
    &lt;/p&gt;
    &lt;ul class="org-ul"&gt;
    &lt;li&gt;&lt;a href="https://explog.in/books/index.html"&gt;Almost everything I've read for the past several years&lt;/a&gt;
    &lt;ul class="org-ul"&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/books2016.html"&gt;Favorites from 2016&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href="https://explog.in/notes/books2017.html"&gt;Favorites from 2017&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;&lt;/li&gt;
    &lt;li&gt;[Extremely rough] &lt;a href="https://explog.in/books/thinking.html"&gt;Books on thinking&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;
    Drop me a note by &lt;a href="mailto:bhalla.kunal@gmail.com"&gt;email&lt;/a&gt; or &lt;a href="https://twitter.com/kunalbhalla"&gt;Twitter&lt;/a&gt; in case you have any advice,
    comments or feedback!
    &lt;/p&gt;</description><author>RSS</author><pubDate>Mon, 10 Aug 2020 03:52:00 GMT</pubDate><guid isPermaLink="true">https://explog.in/rss.html#org649b812</guid></item><item><title>Let’s implement a Bloom Filter</title><link>https://onatm.dev/2020/08/10/let-s-implement-a-bloom-filter/</link><description>I am planning to create a series of blog posts that includes some literature research, implementation of various data structures and our journey of creating a distributed datastore in distrentic.io.</description><author>Onat Mercan’s Blog</author><pubDate>Mon, 10 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://onatm.dev/2020/08/10/let-s-implement-a-bloom-filter/</guid></item><item><title>Educated</title><link>https://olshansky.info/book/educated/</link><description>Olshansky's review of Educated by Tara Westover</description><author>🦉 olshansky 🦁</author><pubDate>Mon, 10 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/educated/</guid></item><item><title>A Theory of Water - Religion, Enlightenment, and non-causal Reality</title><link>http://spirals.blog/articles/water/</link><description>&lt;blockquote&gt;
&lt;p&gt;Be water, my friend&lt;br /&gt;
&lt;a href="https://www.youtube.com/watch?v=cJMwBwFj5nQ"&gt;– Bruce Lee (Youtube video)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What you’re about to read, if you’re religious, atheist, or agnostic, may trigger something in you. It certainly has for me. It might be positive; it might be negative. I cannot say. What I can say, and what I hope you receive as my intention, is that the source of this very writing is love. A love driven by a desire for awareness and wisdom for this earth.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I was raised by two very different belief systems. My father, in his brilliance, taught me the values of science, rationality and reason, relentless discovery, and above all, the aspiration to intelligence. My mother instilled qualities that took many years for me to understand and manifest. She showed a path for creation, art, peace, oneness, and a fickle description of love that always seems to elude us.&lt;/p&gt;
&lt;p&gt;Yeah, childhood was interesting.&lt;/p&gt;
&lt;p&gt;On the one hand, my mother introduced me to many non-religious (and religious) interpretations of the word “God,” while my dad questioned how such a concept could even exist. Circular arguments, re-writing of the Bible and other scriptures for the benefit of nation-states, and sheer ignorance. Not to mention a petty, narcissistic invisible force that would drown the world if it didn’t worship him (or so his interpretation was/is).&lt;/p&gt;
&lt;p&gt;He had a point, and as a child/teenager, followed this line of thinking dogmatically. My mother’s views seemed “airy-fairy,” not based on any truth I could perceive, and some were pretty wacky. But as I grew older, I relaxed my absolutistic thinking, looked past the hatred and claims of “truth” on all sides, and tried to understand where everyone was coming from.&lt;/p&gt;
&lt;h2&gt;Non-Casual Reality&lt;/h2&gt;
&lt;p&gt;For the overwhelming majority of us, life is linear or “causal”. A &lt;em&gt;causes&lt;/em&gt; B, then C. I got the promotion &lt;em&gt;because I&lt;/em&gt; worked hard. He left me &lt;em&gt;because he&lt;/em&gt; couldn’t deal with &lt;strong&gt;me&lt;/strong&gt; standing up for myself. World War 2 started because Hitler invaded Poland.&lt;/p&gt;
&lt;p&gt;For our brains to cope with reality, we need simple explanations to deal with the messy soup of what is going on around us. If we didn’t have clear, simple reasons for things, it would be immeasurably confronting to recognize patterns, make predictions, plan for the future, or explain to children why they shouldn’t hit their siblings. We &lt;em&gt;need&lt;/em&gt; to draw lines from event to event to explain the very existence in which we live. Or so we think.&lt;/p&gt;
&lt;p&gt;When one begins to truly peel back the layers of our world, and seek to understand what’s going on under the surface, something very dramatic changes. Causes, as you would imagine, become very complex.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Did you get the promotion because you worked hard? Or was it also because the person above you was fired, the company had a good year with extra revenue, and they needed someone to expand into a new market? Did he really leave because you stood up for yourself? Or was it also the fact that you have no job, and his grandfather just died, and he was too emotionally insecure to talk about it with you, so decided it was best to just be with his family? Casual perception is an easy scapegoat in hindsight because it’s simpler.&lt;/p&gt;
&lt;p&gt;As we seek to improve our awareness of ourselves, others, and the world, we see the nuances. It becomes challenging to pinpoint &lt;em&gt;exactly&lt;/em&gt; what &lt;em&gt;caused&lt;/em&gt; some &lt;strong&gt;thing&lt;/strong&gt; (though not always). We begin to see everything as a dense, highly-interconnected web of people, animals, objects, emotions, beliefs, “isms”, technologies, “energies” and perspectives. It becomes impossible to separate one’s Self from this networked mess we call reality.&lt;/p&gt;
&lt;p&gt;This awareness can emerge from &lt;a href="https://spirals.blog/articles/psychedelics-and-meditation/"&gt;meditation or psychedelics&lt;/a&gt;, religious experiences, spiritual awakenings, study of the sciences, deepening of empathy, and many other things. They all share one thing common. They loosen our absolutistic, &lt;em&gt;&lt;strong&gt;causal&lt;/strong&gt;&lt;/em&gt; view on reality. We see the world as fluid.&lt;/p&gt;
&lt;p&gt;Water.&lt;/p&gt;
&lt;h2&gt;Jesus, Buddha, Mohammad, and Einstein&lt;/h2&gt;
&lt;p&gt;There are many individuals throughout humanity’s rich and colored history who have, through some means or another, discovered this beautiful perspective. There are many today, and there will be many more.&lt;/p&gt;
&lt;p&gt;To be a “Buddha”, literally translates to “Enlightened One”. It’s not a person. The Christians sometimes refer to this concept as “Christ Consciousness”. There are many others. Each faith, culture, and system has its own word for it, and a collection of practices, understandings or truths about it. They’re all equally beautiful, and they each lead, when taken from a place of love and intelligence to a place in which one sees the world as fluid.&lt;/p&gt;
&lt;p&gt;Einstein himself subscribed to the idea of Spinoza’s “God”, a strange and perplexing notion that every thing and one of us is a derivation of an infinite “organism”. There is good reason to look into the merger of scientific thought and the idea of “oneness”. Not from a suspension of logic, but a leaning into chaos, awareness, and love.&lt;/p&gt;
&lt;h2&gt;Water to Ice&lt;/h2&gt;
&lt;p&gt;In Dharmic tradition, there is a phrase, “Once one has tasted the fruits of enlightenment, one feels instantly compelled to share it with others.”&lt;/p&gt;
&lt;p&gt;There’s a beauty and power we receive from viewing the world as water. Conversations have more angles in which we could interpret them. People may be seen in different lights. Ideas take on new forms, and our creativity emerges boundless. These are all things best enjoyed with others.&lt;/p&gt;
&lt;p&gt;And herein lies the problem of water. It’s next to impossible to translate, illustrate, or convince others of this wondrous perspective and the fruits it bears. Many have tried. Perhaps the most recent rendition of this is “A New Earth” by Ekart Tole. It is almost as if we try to take a 4K 60fps YouTube video and convert it to a cassette tape. It might get some of the audio across, but we lose the visual, much of the definition of its sound, and the very &lt;em&gt;essence&lt;/em&gt; of what made that video special. We lose information.&lt;/p&gt;
&lt;p&gt;To extend our metaphor of water, we might say that things become more “static” the more we digress in explanation, that these descriptions become ice. While the intention is often that of love, wisdom, purity, and awareness, these are drastically difficult perspectives to elucidate in others, especially those of a closed mind, or who have not experienced such states. Our water becomes frozen. Our fluid understanding becomes causal again.&lt;/p&gt;
&lt;p&gt;Often, the way many teachers attempt to explain these “truths”, “paths” and “perspectives” is through stories and metaphor. For those who are well on their way to letting go of the egoic Self, union with God, or profound conceptualization of metaphysical reality – these stories may serve as inspiring lampposts up a winding mountain road. For those who are absolutistic in their thinking, less empathetic, driven by a base fear, or through just plain misinterpretation, these stories become “truth”. They become literal.&lt;/p&gt;
&lt;h2&gt;Battle of the Ice Sculptures&lt;/h2&gt;
&lt;p&gt;There are a near-infinite number of ways one could try to describe “oneness”/non-causality/enlightenment/holiness. And there are a near-infinite number of ways these ideas could be misinterpreted.&lt;/p&gt;
&lt;p&gt;When we forget that all these roads lead back to the same place, and especially when we feel the road is &lt;em&gt;&lt;strong&gt;THE only Road&lt;/strong&gt;&lt;/em&gt;, we grow protective of our perspective. We seek to defend our water that subsequently froze, fighting others over &lt;em&gt;which way&lt;/em&gt; the ice should have formed.&lt;/p&gt;
&lt;p&gt;The problem is, it will freeze differently each time. One teacher may say that God is in us all, and we must explore our relationship with Him through ourselves (a very Islamic idea in which there is no entity between you and God). Others claim that God is distinct from us, infinitely more powerful than us, and we must live in service to Him. Others say there is no god, and that life is just energy and matter. Or a deterministic, mathematical equation of incomprehensible complexity, creating the illusion of free will and perceived reality.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;My fellow humans, why do we fight so? Can we not melt our ice? We are all saying the same thing deep down. Treat others how you would like to be treated (The Golden Rule). Be inquisitive and curious, driven by intellect and knowledge and wisdom. Spread love and inspiration to all and every thing we interact with.&lt;/p&gt;
&lt;p&gt;Followers of religion, atheists, and scientists alike do agree on one thing. Our knowledge of this reality is infinitesimally minute, and that we are all a part of it. We are all more connected than we could possibly imagine. We are all humans, seeking truth and a better life. There is more than one way to see things.&lt;/p&gt;
&lt;p&gt;If you are holding ice, in whatever shape or form, see how it drips around the edges. It wants to be fluid and free. It wants to join the rivers and the oceans, merging itself with everything else there is.&lt;/p&gt;
&lt;p&gt;Dear human, you are precisely that. A beautiful, intelligent, marvelous being of this world that is designed and destined to connect your mind, body, and soul to this world.&lt;/p&gt;
&lt;p&gt;Be water, my friend.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 09 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/water/</guid></item><item><title>Notes on Installing Sony XAV-AX100 in a 2010 Prius</title><link>https://andrewferguson.net/2020/08/08/notes-on-installing-sony-xav-ax100-in-a-2010-prius/</link><description>Parts Sony XAV-AX100 &amp;#8212; $240 Metra 95-8226B Dash Kit for Toyota Prius 2010 Double DIN (Black)&amp;#8212; $15 Metra TYTO-01 JBL Amplifier Interface Harness &amp;#8212; $40 Axxess AX-TOYCAM2-6V Toyota Back-Up Camera Retain/Add-On with 6 Volt Turn on &amp;#8212; $11 Metra 70-8114 Steering Wheel Control Wire Harness with RCA for 2003-Up Select Toyota/Scion/Lexus Vehicles &amp;#8212; $7 Note:&amp;#8230;&amp;#160;&lt;a class="" href="https://andrewferguson.net/2020/08/08/notes-on-installing-sony-xav-ax100-in-a-2010-prius/" rel="bookmark"&gt;Read More &amp;#187;&lt;span class="screen-reader-text"&gt;Notes on Installing Sony XAV-AX100 in a 2010 Prius&lt;/span&gt;&lt;/a&gt;</description><author>Andrew Ferguson dot NET</author><pubDate>Sun, 09 Aug 2020 01:07:35 GMT</pubDate><guid isPermaLink="true">https://andrewferguson.net/2020/08/08/notes-on-installing-sony-xav-ax100-in-a-2010-prius/</guid></item><item><title>Bubbly parasympathetic thinking</title><link>http://dimitarsimeonov.com/2020/08/08/bubbly-parasympathetic-thinking</link><description>&lt;p&gt;When you sigh, where all that extra air come from? Have you ever realized you’re holding your breath unconsciously only for it to end with a deep exhale? Happened to me a couple weeks ago. I was driving and I noticed that from time to time I would be thinking about the other cars and the more I thought the shallower I breathed. Then, the driving situation would simplify and I would switch to “autopilot” cruising and release a single sigh and feel a little bit more relaxed.&lt;/p&gt;

&lt;p&gt;It is not that the situation on the road was stressful, or dangerous. It was  normal evening, and traffic was not heavy. It wasn’t stressing me. In fact, I was relaxing after a day of work and packing and excited to go on a short backpacking trip.  Yet, the mere act of thinking was enough to make me hold my breath a bit.&lt;/p&gt;

&lt;p&gt;And this isn’t the first time I noticed that pattern. During meditation, I’ve noticed a slight buildup of held up breath when my mind is wandering, and then  I’ve noticed myself releasing that breath when I remember I am actually meditating and focus on the object of my meditation. By releasing the held up breath I was releasing the wandering thoughts. Or vice versa. I don’t know which causes which to happen, but the correlation is clear.  Thinking correlates with holding breath and relaxing my mind correlates with relaxation of my breathing.&lt;/p&gt;

&lt;p&gt;It is natural to hold breath in situations which are stressful, our bodies do that subconsciously through the sympathetic nervous system. That the “fight or flight” response. So for me, if thinking correlates holding breath, and holding breath correlates with the “fight or flight” response, then by the transitive property thinking correlates with the fight or flight mode. This is not the mode we’re supposed to be for a long time, as it wears us out much faster. Intense sympathetic stress happens when chased by a wild animal (favorite pastime), or experiencing a stressful situation at work or in our relationships. The mere act of thinking does not create as intense response, sometimes it results in a mild sympathetic response.&lt;/p&gt;

&lt;p&gt;Which brings me to the topic of “parasympathetic thinking” (PST) - which I call the type of thinking which doesn’t result is such breath holding or engaging of the sympathetic system. Parasympathetic thinking is hard to maintain and is fleeting. In moments after a deep exhale or minutes of meditation, our minds still think but without being forced by our conscious mind to go in a certain direction. In such moments, when we’ve relaxed our bodies and our minds, we can experience ideas and emotions which couldn’t get to the front stage before, when we forced our minds to write code, or do taxes, or take care of a baby.&lt;/p&gt;

&lt;p&gt;Parasympathetic thinking is allowing the suppressed thoughts to come up forward in our consciousness.&lt;/p&gt;

&lt;p&gt;Parasympathetic thinking (PST) is more creative, because during PST we allow our brain to present to us the ideas which it came up with. PST is thinking out of the box. When you’re trying to be creative, try relaxing and exhaling, and see if it helps.&lt;/p&gt;

&lt;p&gt;Paradoxically, PST is effortless, as in we can’t force ourselves to be in PST. Sometimes we have a lot of other stress, and a handful of deep exhales won’t help us detach. I once went on a vacation for a week, hiking though beautiful national parks, and during a lot of the hiking my mind was preoccupied with some issues at work. PST is not a switch that we easily flip, but when we do succeed in engaging PST, we do so by canceling our effort. QED the paradox.&lt;/p&gt;

&lt;p&gt;I called it a switch to flip, but PST is not clear cut ON/OFF, it is rather a spectrum between, on one hand having focused and directed attention, where we don’t allow anything to bubble up, and on the other hand having a diffused and “bubbly” consciousness.&lt;/p&gt;

&lt;p&gt;What I’ve also noticed that some important personal topics of my life are often bubbly. I experience them stronger when I’m further along the PST spectrum. Accessing PST via meditation or other forms of relaxation often helps me connect with these topics and find a happier path in life. I should note thought, that not all bubbly thoughts are important - most are just random. Sometimes I can make my mind more bubbly, but I cannot force the important topics to bubble up.&lt;/p&gt;

&lt;p&gt;Parasympathetic thinking is not a scientific concept. There are other, more precise scientific concepts such as “vagus nerve” and “shadow work”, which cover aspects of PST with much more rigor than this blog post. The parasympathetic system can be triggered by slow abdominal breathing, via the vagus nerve, but the state of relaxation is not exactly the bubbly thinking I mean by PST. Yet, PST is definitely a useful enough concept for me to get a better understanding of my thinking, to be more creative and to better balance my stress levels.&lt;/p&gt;

&lt;p&gt;I can use it without knowing exactly how it works.&lt;/p&gt;</description><author>D13V</author><pubDate>Sun, 09 Aug 2020 00:53:07 GMT</pubDate><guid isPermaLink="true">http://dimitarsimeonov.com/2020/08/08/bubbly-parasympathetic-thinking</guid></item><item><title>What cryptocurrency and Modern Monetary Theory get wrong about money</title><link>https://mebassett.info/changing-money</link><description>Politicians on the Left and Right are betting on new theories about money to bring about the change they seek, but both are neglecting ideas from classical economics that could help us prepare for economic disruptions ranging from the current pandemic to the coming AI revolution. .</description><author>Essays by Matthew Eric Bassett</author><pubDate>Sat, 08 Aug 2020 19:20:00 GMT</pubDate><guid isPermaLink="true">https://mebassett.info/changing-money</guid></item><item><title>Why is Backblaze tracking me?</title><link>https://www.gingerlime.com/2020/why-is-backblaze-tracking-me/</link><description>&lt;p&gt;This is a follow-up to my previous post: hey.com is onto something with its tracking-pixel blocker. I mentioned contacting Backblaze about their email tracking there. I didn&amp;#8217;t think too much of it at the time, and honestly (or naively?) was expecting some kind of a &amp;#8220;Oh, yes, you&amp;#8217;re right, there&amp;#8217;s no need to track those&amp;#8230;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://www.gingerlime.com/2020/why-is-backblaze-tracking-me/"&gt;Why is Backblaze tracking me?&lt;/a&gt; appeared first on &lt;a href="https://www.gingerlime.com"&gt;Gingerlime&lt;/a&gt;.&lt;/p&gt;</description><author>Gingerlime</author><pubDate>Sat, 08 Aug 2020 14:34:19 GMT</pubDate><guid isPermaLink="true">https://www.gingerlime.com/2020/why-is-backblaze-tracking-me/</guid></item><item><title>Text to "Go String" Tool</title><link>https://donatstudios.com/gostring</link><description>&lt;p&gt;Go &lt;a href="https://github.com/golang/go/issues/32590"&gt;currently lacks&lt;/a&gt; any sort of heredoc or similar syntax, and it's backtick syntax cannot contain backticks. This can make correctly encoded creating go strings, particularly for large strings that contain many backticks, a bit of a challenge.&lt;/p&gt;
&lt;p&gt;Here's a tool to safely encode any given input to Go string.  It's written in Go using Go's own string encoder and compiled with WASM.&lt;/p&gt;
&lt;p&gt;The code as well as a CLI version of it are available on &lt;a href="https://github.com/donatj/gostring"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;fieldset&gt;
 

&lt;center&gt;&lt;small&gt;&lt;a href="https://github.com/donatj/gostring" target="_blank"&gt;Fork my source on GitHub!&lt;/a&gt;&lt;/small&gt;&lt;/center&gt;
&lt;/fieldset&gt;</description><author>Donat Studios</author><pubDate>Sat, 08 Aug 2020 09:14:19 GMT</pubDate><guid isPermaLink="true">https://donatstudios.com/gostring</guid></item><item><title>2020-08-08</title><link>https://ho.dges.online/pictures/2020-08-08/</link><description/><author>ho.dges.online</author><pubDate>Sat, 08 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/pictures/2020-08-08/</guid></item><item><title>Design Thinking and Life</title><link>https://trigonaminima.github.io/2020/08/design-viz-tool/</link><description>At the start of July 2020, I enrolled in a Coursera course on Design Thinking called Design Thinking for Innovation. Today, I’ve finally finished it. This post is a brief description of what I learned and my final submission about the reflection on one of the four design tools covered in the course that I employed in a challenge/problem of my choice.</description><author>Playground</author><pubDate>Sat, 08 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://trigonaminima.github.io/2020/08/design-viz-tool/</guid></item><item><title>Warehouse Explosion in Lebanon</title><link>https://zef.studio/journal/lebanon-warehouse-explosion</link><description>Photos and experiences from my time in Lebanon.</description><author>Zef Houssney</author><pubDate>Fri, 07 Aug 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://zef.studio/journal/lebanon-warehouse-explosion</guid></item><item><title>Headspace: Block All The Things!</title><link>http://evantravers.com/articles/2020/08/07/headspace-block-all-the-things/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/08/allthethings.jpg" /&gt;&lt;/p&gt;&lt;p&gt;JG wrote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As far as I know, Headspace blocks the opening of applications via the hyper key, right? I was wondering if there is a way to block the opening of applications at all?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pretty much as soon as I had finished the series on Hammerspoon, I knew I wanted to take the Headspace project further. At that point, it would block opening or switching to an application via the Hyper shortcuts I had defined earlier, but if you opened an application via Finder, Spotlight, or another launcher like &lt;a href="https://www.alfredapp.com/"&gt;Alfred&lt;/a&gt;… I could get around my little system.&lt;/p&gt;
&lt;p&gt;My fingers started building the new neural pathways to get around my own boundaries &lt;em&gt;immediately&lt;/em&gt;. So it's time to… BLOCK ALL THE THINGS! * ahem *&lt;/p&gt;
&lt;p&gt;I had actually taken a couple stabs at the universal blocking before I finished the blog post. I had a pretty good idea that I'd be using the &lt;code&gt;hs.application.watcher&lt;/code&gt; to track what applications had launched, but I could &lt;em&gt;not&lt;/em&gt; get it to work.&lt;/p&gt;
&lt;p&gt;After a &lt;em&gt;lot&lt;/em&gt; of back and forth and some debugging, I eventually realized that I was tripping over Lua's garbage collection. I had instantiated the watcher, but in the local context of a lua module&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;1&lt;/a&gt;&lt;/sup&gt;. This meant that after the function had been called first time, the watcher's object was garbage collected and destroyed.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;2&lt;/a&gt;&lt;/sup&gt; I eventually &amp;quot;hoisted&amp;quot; the watcher out to the global namespace like this:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;module&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- ...&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;if&lt;/span&gt; &lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;watcher_enabled&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;watcher&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;watcher&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app_name&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;event&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hsapp&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;event&lt;/span&gt; &lt;span&gt;==&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;watcher&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launched&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;local&lt;/span&gt; &lt;span&gt;app_config&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;applications&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;hsapp&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bundleID&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;if&lt;/span&gt; &lt;span&gt;not&lt;/span&gt; &lt;span&gt;allowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app_config&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;notify&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;Blocked &amp;quot;&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;hsapp&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;Current headspace: &amp;quot;&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;headspace&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;hsapp&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;kill&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- ...&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;return&lt;/span&gt; &lt;span&gt;module&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another advantage to this migration is that now &lt;code&gt;headspace.lua&lt;/code&gt; is not dependent at all on &lt;code&gt;hyper.lua&lt;/code&gt;. You can trigger the Headspace UI any way you like. I have thought about rewriting it as an official Hammerspoon Spoon, but I am not sure if anyone really wants that.&lt;/p&gt;
&lt;p&gt;While I was working on it, I added another feature: you can now define a teardown function for a space. The teardown function fires when the space is exited, and I use it to &amp;quot;undo&amp;quot; things. For instance, when I enter my &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/2c03bb10c11b7c16b68ab94e2c475c31f52e8afc/spaces/communicate.lua"&gt;Communication space&lt;/a&gt;, I filter Things.app to the set of to-dos related to communicating. When I leave Communication, I want to see my normal &amp;quot;Today&amp;quot; view, and that's easy enough to implement.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;funcs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;agendaFor&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;setup&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=anytime&amp;amp;filter=@Work,Agenda%20For&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;teardown&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=today&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I've been using the new Headspace for the past month or so, and it has been really stable. I may end up choosing to use a non-native notification method eventually, just as I tend to turn on Do Not Disturb mode, which effectively blocks Headspace from telling me what it's doing. As it is, I haven't made any major changes to it in a while, mostly just aesthetic changes to the time tracker and adjusting the blocking lists for various spaces.&lt;/p&gt;
&lt;p&gt;If you want to give Headspace a try, you can! Here is a minimum viable init.lua for starting to tinker and build your &lt;strong&gt;own&lt;/strong&gt; setup.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download the following files to your Hammerspoon directory (usually &lt;code&gt;~/.hammerspoon&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/evantravers/hammerspoon-config/2ae895b1fad99b5615a85e7b048b4faca9f091b6/headspace.lua"&gt;headspace.lua&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/evantravers/hammerspoon-config/2ae895b1fad99b5615a85e7b048b4faca9f091b6/toggl.lua"&gt;toggl.lua&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/evantravers/hammerspoon-config/2ae895b1fad99b5615a85e7b048b4faca9f091b6/secrets.lua"&gt;secrets.lua&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You'll need to set up your toggl secrets in a &lt;code&gt;.secrets.json&lt;/code&gt; in that same Hammerspoon folder. Use this as a guide:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-json" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;toggl&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;wouldntyouliketoknow&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;projects&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;communications&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;lt;communications id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;deep&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;lt;deep id&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Here's a minimimum viable init.lua, together with some commentary on what is going on:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;-- load in all secrets&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;secrets&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'secrets'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;secrets&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'.secrets.json'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- instantiate the config table that will be passed to the headspace module&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- define some applications to block... yours will be different, here's just a place to start.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;applications&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'org.mozilla.firefox'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;bundleID&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'org.mozilla.firefox'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'com.tinyspeck.slackmacgap'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;bundleID&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'com.tinyspeck.slackmacgap'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;tags&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'communication'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'com.apple.iChat'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;bundleID&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'com.apple.iChat'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;tags&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'communication'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'distraction'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- instantiate tables for headspace spaces&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- instantiating them early means that you can use `table.insert` to add&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- more later.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;spaces&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;funcs&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- I store the API id of my toggl projects in a the `.secrets.json`&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projects&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;secrets&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toggl&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projects&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- setup spaces&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- I recommend having at _least_ two... one for shallow and one that blocks&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- distractions for &amp;quot;deep&amp;quot; work. Take what I have here and make it your&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- own.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;spaces&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;text&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Deep&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;subText&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Work deeply on focused work&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;image&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;imageFromAppBundle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.apple.finder'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;toggl_proj&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projects&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;deep&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;blacklist&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'distraction'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'communication'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;funcs&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'deep'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;funcs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;deep&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;setup&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=anytime&amp;amp;filter=@Work,$High&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;teardown&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=today&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;spaces&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;text&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Communication&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;subText&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Intentionally engage with Slack and Email.&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;image&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;imageFromAppBundle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.tinyspeck.slackmacgap'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;whitelist&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'communication'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;launch&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'communication'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;toggl_proj&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projects&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;communication&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;funcs&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'agendaFor'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;funcs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;agendaFor&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;setup&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=anytime&amp;amp;filter=@Work,Agenda%20For&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;teardown&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;things:///show?id=today&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- instantiate headspace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;headspace&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'headspace'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- enable the watcher to start the blocking&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;headspace&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;enable_watcher&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- start the module's setup&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;headspace&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- bind the Space Choosing UI to a key.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- Here I'm just using `⌘⌥+k`.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;hotkey&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'cmd'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'alt'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'k'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;headspace&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;choose&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That's it! I did some smoke testing on my own system to make sure that this works, but I am (most likely) forgetting &lt;em&gt;something&lt;/em&gt;. I realize that this is still really confusing, so if you want to give this a whirl, please &lt;a href="/contact"&gt;reach out&lt;/a&gt; and I'll be happy to help you. 🙏&lt;/p&gt;
&lt;p&gt;You can always take more inspiration from &lt;a href="https://github.com/evantravers/hammerspoon-config/"&gt;my ever evolving configuration at my github&lt;/a&gt;.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;You can see the change &lt;a href="https://github.com/evantravers/hammerspoon-config/commit/285703adb2d86925b63f115b93208ebf1a9061ae"&gt;here&lt;/a&gt;. &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;The symptom of this problem was the blocking function would execute correctly &lt;em&gt;once&lt;/em&gt;, then stop working. This was because after the module was loaded, the GC would destroy the watcher object. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Fri, 07 Aug 2020 18:27:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/08/07/headspace-block-all-the-things/</guid></item><item><title>Showing Up Even When You're Not Feeling It</title><link>https://zenhabits.net/feeling-it/</link><description>&lt;p&gt;Leo Babauta, in &lt;a href="https://zenhabits.net/feeling-it/"&gt;&lt;em&gt;Showing Up Even When You&amp;#8217;re Not Feeling It&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Most of us have an expectation that we should feel in the mood to do something. We should be excited, rested, focused. And when we do it, it should be easy, comfortable, fun, pleasurable. Something like that. That results, predictably, in running from the things that feel hard, overwhelming, uncomfortable.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will not always feel like taking the hard road, but achieving success means defining a goal, making a plan to accomplish it, and then applying unmitigated daily discipline until you get there. &lt;a href="https://zacs.site/blog/there-is-no-shortcut.html"&gt;There is no shortcut&lt;/a&gt;, life hack, or trick; grind.&lt;/p&gt;


                &lt;p&gt;&lt;a href="https://zenhabits.net/feeling-it/"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Fri, 07 Aug 2020 17:54:46 GMT</pubDate><guid isPermaLink="true">https://zenhabits.net/feeling-it/</guid></item><item><title>Daddy, did you really need to buy an electric car?</title><link>https://svedic.org/tech/daddy-did-you-really-need-electric-car</link><description>I made a mistake: I bought an electric car. EV articles I have read on Hacker News and Reddit didn&amp;#8217;t prepare me for a dozen EV infrastructure problems in my part of the EU. Anecdotes below explain lessons I learned &amp;#8230; &lt;a href="https://svedic.org/tech/daddy-did-you-really-need-electric-car"&gt;Continue reading &lt;span class="meta-nav"&gt;&amp;#8594;&lt;/span&gt;&lt;/a&gt;</description><author>Svedic.org</author><pubDate>Fri, 07 Aug 2020 16:36:13 GMT</pubDate><guid isPermaLink="true">https://svedic.org/tech/daddy-did-you-really-need-electric-car</guid></item><item><title>Goodbye Ubuntu, Hello Debian my old friend</title><link>https://blog.herlein.com/post/debian-again/</link><description>&lt;p&gt;Ubuntu just went too far with the snap crap.  Back to Debian!&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Fri, 07 Aug 2020 14:10:43 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/debian-again/</guid></item><item><title>USB audio devices on FreeBSD</title><link>https://www.davidschlachter.com/misc/freebsd-usb-audio</link><description>Hardware support and configuration for USB audio devices, such as the Behringer UMC22 sound card, on FreeBSD.</description><author>David Schlachter</author><pubDate>Fri, 07 Aug 2020 03:49:00 GMT</pubDate><guid isPermaLink="true">https://www.davidschlachter.com/misc/freebsd-usb-audio</guid></item><item><title>A/B testing and Multi-armed bandits</title><link>https://bytepawn.com/ab-testing-and-multi-armed-bandits.html</link><description>&lt;p&gt;Multi-armed bandits minimize regret when performing A/B tests, trading off between exploration and exploitation. Monte Carlo simulations shows that less exploration yields less statistical significance.&lt;br /&gt;&lt;br /&gt; &lt;img alt="Epsilon-greedy" src="/images/mab_epsg_ps.png" style="width: 400px;" /&gt;&lt;/p&gt;</description><author>Bytepawn - Marton Trencseni</author><pubDate>Fri, 07 Aug 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://bytepawn.com/ab-testing-and-multi-armed-bandits.html</guid></item><item><title>The Beginner Bubble</title><link>https://voussoir.net/writing/beginner_bubble</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;The Beginner Bubble&lt;/h1&gt;&lt;ol id="table_of_contents"&gt;Table of contents&lt;li&gt;&lt;a href="#introduction"&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#why_generous_interpretation"&gt;Why - generous interpretation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#why_critical_interpretation"&gt;Why - critical interpretation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#case_studies"&gt;Case studies&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="#escape_the_bubble"&gt;Escape the bubble&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;a class="header_anchor_link" href="#introduction"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The internet has made self-taught learning more accessible than ever before. I am a strong proponent of self-teaching and using the internet to learn about anything you're interested in. But, the nature of internet learning also has its drawbacks, one of which I'm deeming the beginner bubble.&lt;/p&gt;
&lt;p&gt;I think many people have had the experience of discovering a niche website written by a single, passionate person with an educational quality that puts textbooks to shame. Take for example &lt;a href="https://ciechanow.ski/lights-and-shadows/"&gt;Bartosz Ciechanowski - Lights and Shadows&lt;/a&gt;, a phenomenal rundown of the mechanics of light with beautiful interactive modules.&lt;/p&gt;
&lt;p&gt;These kinds of websites are great, but they're hard to come by when you're intentionally looking for them. You'll see comments like "I wish I had found this when I was in school!". Outreach is hard for creators, and sifting through SEO and blogspam is hard for learners. Instead, we tend to compromise and use a common arena like Youtube instead of specialized websites and webrings. I would say that Youtube has become the de-facto home of internet learning in many ways, but it suffers greatly from the beginner bubble.&lt;/p&gt;
&lt;p&gt;If I were to make a graph depicting the quantity of learning resources available to learners of different skill levels for a topic, which I have, then it would look like this, which it does:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/writing/beginner_bubble/graph.svg" /&gt;&lt;/p&gt;
&lt;p&gt;There seems to be an endless supply of "for beginners", "intro to", and "how to get started with" tutorials online, and a very quick taper into obscurity beyond that. I am not saying that there are literally zero learning resources for advanced and expert learners, but take a quick dive into search queries like
&lt;a href="https://www.youtube.com/results?search_query=programming+oop"&gt;programming oop&lt;/a&gt;,
&lt;a href="https://www.youtube.com/results?search_query=git+basics"&gt;git basics&lt;/a&gt;, or
&lt;a href="https://www.youtube.com/results?search_query=learn+hangul"&gt;learn hangul&lt;/a&gt;
and behold the open floodgates. Now, try again with
&lt;a href="https://www.youtube.com/results?search_query=advanced+python"&gt;advanced Python&lt;/a&gt; (the first things I see on the page are decidedly still beginner-level: "Overview of Python &amp;amp; How it Works", "Advanced Python 01 - lists / 02 - tuples", ...),
&lt;a href="https://www.youtube.com/results?search_query=advanced+korean+grammar"&gt;advanced Korean grammar&lt;/a&gt; (notice, it's still mostly vocab lists or unhelpful vlogs).
Higher level learning materials exist, but the number of beginner lessons is so totally dwarfing as to get my attention and provoke this article.&lt;/p&gt;
&lt;h2 id="why_generous_interpretation"&gt;Why - generous interpretation&lt;a class="header_anchor_link" href="#why_generous_interpretation"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's start by giving everyone the benefit of the doubt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Never heard of it&lt;/strong&gt;: Any topic worth teaching will have some level of pre-requisite knowledge. It is difficult to give a meaningful lesson on Python to someone who doesn't know the basic concept of programming — it will devolve into a lesson on the basic concept of programming that just so happens to be demonstrated in Python. This prerequisite chain continues down to "what is a computer" and so on. So, creating lessons for &lt;em&gt;Never heard of it&lt;/em&gt;s is difficult because the creator must assume some level of background knowledge, and every creator may pick a different threshold. By virtue of creating a "Basics of Python, lesson 1", the creator inherently skips over people who have never heard of programming. That's not a bad thing, because nobody on the internet is obligated to create something they don't want to, and most likely there are others out there who will teach the basics of programming.&lt;/p&gt;
&lt;p&gt;Not to mention, learners won't be seeking out learning material for topics they've &lt;em&gt;literally&lt;/em&gt; never heard of. In order to access that demographic, the creator either has to present basic lessons on many topics and gain a "general learning" or "pop science" subscriber base, or hope that by sharing and word of mouth their lessons will reach the people who will be interested.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Beginner&lt;/strong&gt;: Beginner level resources are the most numerous because of multiple natural tendencies by both the learners and creators.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Learners don't need very specific information and will be happy with anything as long as it's appropriate for their skill level. Each individual creator will have a different idea as to what they should put in their "beginner level" lessons, and the learner will use material from several creators to eventually get a well-rounded beginner-level understanding.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Learners need some time to decide whether or not they want to pursue the field further. They are probably searching for beginner materials just test the waters. After that, learners either drop out or spend more time with hands-on learning, reducing the demand for more advanced tutorial content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creators will usually start their lesson series by teaching the basics, instead of going straight for the advanced topics. Though they may continue to create higher level material too, others will stop creating, so the quantity of beginner resources will be the largest of all categories by default. Again, no one has an obligation to create if they don't want to, so someone who tries making tutorials may find they don't want to continue, and that's ok.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creators who create for the beginner level will all start out in roughly the same place, then later branch out to fulfill specific niches. There comes a point where "Intermediate lesson on topic X" would be better titled "Beginner lesson on more advanced topic Y". For example, a first lesson on machine learning might require intermediate programming skills, but is better described as "Basics of machine learning" than a clumsy "Using intermediate programming to do machine learning". Learning materials will have a tendency to describe themselves as the basics of something rather than the intermediates of something. Thus, the bubble is partly a result of labeling.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Intermediate&lt;/strong&gt;: I was careful to title the graph using the phrase "available to" and not "made for", because ultimately no matter how much content is made on the internet, discoverability and searchability is a critical factor in actually reaching anybody. One reason Intermediate material availability is low is that at this level, learning materials are specific enough, and require domain-specific keywords, that simply searching for "intermediate X tutorials" probably won't help the learner find what they're looking for. Any resources that are titled so simply probably contain a smattering of information bordering on beginner-intermediate but without the depth and specificity the learner actually wants. Learners must know some keywords to access what they need, which is difficult when you don't know what you don't know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Expert&lt;/strong&gt;: In addition to the searchability issue, the supply of expert-level lessons is low simply because the demand is low. Experts don't need lessons because they grow through actual experience and they know how to learn from source-level material. An expert programmer doesn't need tutorials on how to use a library because they can read the documentation or source code. An expert artist doesn't need more drawing lessons because they can establish their own style and innovate new techniques.&lt;/p&gt;
&lt;h2 id="why_critical_interpretation"&gt;Why - critical interpretation&lt;a class="header_anchor_link" href="#why_critical_interpretation"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It's time to get critical of the situation, because I've noticed behaviors and patterns from creators that don't line up with the generous interpretation. Although the beginner bubble is the observable, physical product of creator behavior, I feel that creator behavior itself can often be described as a beginner &lt;a href="https://en.wikipedia.org/wiki/Tar_pit"&gt;tar pit&lt;/a&gt;. From the point of view of an internet creator with less-than-noble goals, it is best if the audience remains stuck at the beginner level.&lt;/p&gt;
&lt;p&gt;To start with, I accept the fact that the beginner audience is simply the largest audience. I believe what I said about learners and creators dropping out, and learners not needing as many tutorials as they advance. There's nothing wrong with that being true. I don't think the resource graph should be flat. However, I've noticed some creators who stay in the beginner bubble far longer than necessary. I find myself trying to assess whether the creator is genuinely passionate about teaching their subject and helping learners advance their skills, or whether they just make lessons for youtube views, ad dollars, book sales, course sales, etc.&lt;/p&gt;
&lt;p&gt;The bubble continues to balloon, because:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anyone can do it&lt;/strong&gt;: The barrier to entry for publishing online is getting lower and lower. Overall, that's a good thing, but it also means that creators can start teaching before they are anything more than a beginner themselves. Some people are just a little too eager to start explaining things to others, and during their second week of learning about a topic will happily make tutorials for everything they learned in their first week. At this stage, the creator lacks the big picture context that would allow them to make smart decisions about what to teach or omit. Their lessons will be regurgitations of whatever lessons they've received, without understanding how the information actually pieces together. I have had to resist this urge many times, and I've failed many others.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Those who can, do&lt;/strong&gt;: And those who can't, talk about doing. The only people capable of creating expert-level teaching material are the experts, and where are they? They're out practicing their craft, of course; continuing to hone their skills and furthering their career doing what they're an expert at. Real experts don't have as much time to faff about with internet tutorials as people who like to pretend that they're experts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;They can sell you stuff&lt;/strong&gt;: Not only are beginners the largest demographic, they are disproportionately more willing to spend on resources than learners at higher skill levels. This is partly because they haven't reached the moment of disillusionment that learning requires significant time and effort and not just the buying of books, and partly because they cannot yet assess the quality of the resource being sold to them. If a beginner buys a low quality resource that's difficult to learn from, they might think the topic is just hard. Higher level learners will have better BS detectors and less patience for low quality material.&lt;/p&gt;
&lt;p&gt;Scammers around the world prey on the ignorant, and "educational" scammers are no different. You can find videos online of magical polyglots spitting phrases in a dozen languages they supposedly learned to fluency in six months each. And for just $14.99, you can have access to their course showing how they got there.&lt;/p&gt;
&lt;p&gt;Here's a quote I discovered on &lt;a href="https://news.ycombinator.com/item?id=23451264"&gt;hn&lt;/a&gt; which is half relevant and all poignant:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Writing for money and reservation of copyright are, at bottom, the ruin of literature. No one writes anything that is worth writing, unless he writes entirely for the sake of his subject. What an inestimable boon it would be, if in every branch of literature there were only a few books, but those excellent! This can never happen, as long as money is to be made by writing. It seems as though the money lay under a curse; for every author degenerates as soon as he begins to put pen to paper in any way for the sake of gain. The best works of the greatest men all come from the time when they had to write for nothing or for very little.&lt;/p&gt;
&lt;p&gt;If the reader wishes to study any subject, let him beware of rushing to the newest books upon it, and confining his attention to them alone, under the notion that science is always advancing, and that the old books have been drawn upon in the writing of the new. They have been drawn upon, it is true; but how? The writer of the new book often does not understand the old books thoroughly, and yet he is unwilling to take their exact words; so he bungles them, and says in his own bad way that which has been said very much better and more clearly by the old writers, who wrote from their own lively knowledge of the subject&lt;/p&gt;
&lt;p&gt;Arthur Schopenhauer, "On Authorship"&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Immunity to criticism&lt;/strong&gt;: Resources for beginners will naturally need to smooth over some details to keep the lesson understandable, but that becomes decreasingly acceptable as you reach expert level materials. Creators who can't teach the fine details or don't want to deal with criticism will find safety in the beginner tar pit. As long as the lesson is labeled as "for beginners", then it becomes immune to any criticisms that details are missing, edge cases aren't covered, specifics are left vague, and examples feel artificial. You'll hear "&lt;em&gt;I know I skipped over that, I just wanted to keep it simple&lt;/em&gt;".&lt;/p&gt;
&lt;p&gt;Not only are beginner resources more immune to criticism, but they attract less criticism in the first place since the audience, by design, consists of people who know little on the subject. It doesn't matter if the magical polyglot horribly mangles the pronunciation of their dozen languages if the listener doesn't know the right pronunciation either. You don't have to be very skilled to impress at this level, which feels good for the creator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I'm different&lt;/strong&gt;: I know I'm a jerk for raining on people's parades, but as I swim through a seemingly endless supply of Lesson Ones, it's clear to me that the majority of creators on the internet are fantastically, myopically unaware of just how many people have already beat them to the punch, or just don't care. It is somewhat mind boggling to me that people don't stop to think "I wonder if anyone else has already made a tutorial about this" before making their own and tossing it onto the mountainous heap. Or they do think about it, but decide that their version is somehow different and special. More realistically, they didn't actually look at what already exists, because they're here to be Mr Teacher, not to learn what's already out there.&lt;/p&gt;
&lt;p&gt;Sure, again, we remind ourselves that anyone can make whatever they want. I'm going to stop adding that disclaimer now. It's true that teaching others is a great way to help oneself learn, so maybe a lot of it boils down to that. Still, it's fascinating to me from a sociology point of view that creators either don't consider or realize the oceanic scale of the internet, and the fact that their idea has probably already been done and done better &lt;a class="footnote_link" href="#footnote_text_1" id="footnote_link_1" title="[1] The brain has not yet become accustomed to the light which the internet has shone upon it: it's very, very hard to come up with anything original."&gt;[1]&lt;/a&gt;; or they do realize that but go ahead with it anyway.&lt;/p&gt;
&lt;p&gt;Is it for ego, to have &lt;em&gt;their&lt;/em&gt; name on the page and not someone else's? Is it for practice, to get comfortable writing and speaking and editing? Is it because they'd rather spend 3 hours making their own tutorial than 20 minutes reading another and just sharing that link? Do they genuinely think they bring something new to the table, even on basic and rote topics? But, wait a minute, none of these desires require that we stay in the tar pit — couldn't we get the same ego boost and speaking practice and enjoyment of creation by making something besides another Lesson One? Something actually unique? &lt;a class="footnote_link" href="#footnote_text_2" id="footnote_link_2" title="[2] inb4 this article is not unique either."&gt;[2]&lt;/a&gt; The answer is most obviously yes, and yet here we are. The number of collective man-hours spent spinning our wheels on remaking the same Lesson Ones is disappointing. I'm not asking for people to be robotic and completely deferential to the anonymous mass of the internet, with only one tutorial in the whole world for any given subject, but the situation has got my mind turning and I'm becoming increasingly self-aware about whether I'm being novel enough in what I publish.&lt;/p&gt;
&lt;p&gt;When I am programming, I often find situations where there is an existing tool to do what I need, but I would rather have the enjoyment and control of making my own. This is surely similar, though I would note that I publish them without making any false gestures that I'm doing it for the benefit of some audience. I publish them because its free and easy and doesn't bother anyone else since my repos get no visitors anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low commitment&lt;/strong&gt;: When it comes to beginner-level information, there's never a single correct order to present the many concepts. Knowledge is a web without a clear starting point. It is natural that a teacher will present many ideas which at first seem unrelated, and the connections become clear as the lessons progress. However, if the creator is not committed to helping learners grow their knowledge web, they have the option of instead continuously bouncing around their repertoire of beginner lessons without actually developing the connections. If the learner doesn't perceive the connections, and every lesson is presented to them as if it were novel, they may not realize they're being held in the tar pit when they could be advancing.&lt;/p&gt;
&lt;p&gt;Contrast that with someone who shows, say, how to build a house from the ground up, or how to go &lt;a href="https://www.nand2tetris.org/"&gt;from Nand to Tetris&lt;/a&gt;. In those cases, there's a clear starting point (empty lot, nand) and a clear ending point (house, tetris), and if the creator doesn't reach the ending point it will be obvious to every onlooker. Abandonment and unfinished business is more apparent at the expert level. Creators who aren't confident or committed in their teaching can stay in the tar pit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audience pull&lt;/strong&gt;: My tone in this section largely paints these beginner-level resource creators as malicious — as intentionally trying to keep learners stuck in the tar pit for their own personal gain. And for the scammer types that's true, but I must clarify that some creators wind up staying in the tar pit without consciously choosing to. Take for example a creator who makes a couple of beginner lessons, then starts receiving comments and emails from learners requesting a lesson on some other beginner topic. Repeat a few times. The problem is that the collective intelligence of the requests never really rises because the audience churns and new beginners make new requests, and randos on the internet are very bad at using search bars for some reason, so they wind up requesting the same things over and over again. For the creator, it feels good to be getting recognition, and they'll want to please the crowd by fulfilling those requests, without putting their foot down about the direction they want to take their creation. Plus, again, beginners are the biggest audience, creating disproportional feedback towards beginner level topic requests.&lt;/p&gt;
&lt;p&gt;&lt;a class="footnote_text" href="#footnote_link_1" id="footnote_text_1"&gt;[1]&lt;/a&gt; The brain has not yet become accustomed to the light which the internet has shone upon it: it's very, very hard to come up with anything original.&lt;/p&gt;
&lt;p&gt;&lt;a class="footnote_text" href="#footnote_link_2" id="footnote_text_2"&gt;[2]&lt;/a&gt; inb4 this article is not unique either.&lt;/p&gt;
&lt;h2 id="case_studies"&gt;Case studies&lt;a class="header_anchor_link" href="#case_studies"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://youtube.com/channel/UC5r3WHrX4Z7peSYpDlgktGw/videos"&gt;Talk To Me In Korean&lt;/a&gt; is the inspiration for this article. With over 1,600 videos already on the channel and some dozens of courses on the site, they continue to astound me by releasing videos like &lt;a href="https://www.youtube.com/watch?v=TUSNTV7VkcI"&gt;How to make Korean sentences (for absolute beginners)&lt;/a&gt;. In the past six months, they have greatly ramped up production on their "Live Korean Class" series, which are hour-long meanders through a general topic. The individual teaching moments that occur throughout the livestreams will of course be valuable to somebody, but with such low information density, searchability, and conciseness of theme, they are useless to someone serious about learning the language. These are for people who want to feel like they spent an hour studying, without putting in an hour's effort.&lt;/p&gt;
&lt;p&gt;Every couple of weeks they publish a video reminding you to buy their books.&lt;/p&gt;
&lt;p&gt;TTMIK's best product is undoubtedly Iyagi, a now-defunct podcast which totaled 145 episodes of pure, no-English, normal-speed Korean speech plus full transcripts. At one point, all the episodes were freely available and I downloaded them. Now they're behind a paywall, because TTMIK realized that their podcast from 8-10 years ago is of higher value than the hours and hours of video they make now. Their &lt;a href="https://www.youtube.com/watch?v=cP55GAFNCx8" title="Princess Service"&gt;old videos&lt;/a&gt; are pretty hilarious, too. As always, it's the business that spoiled the product.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.duolingo.com/"&gt;Duolingo&lt;/a&gt; has a &lt;a href="https://old.reddit.com/r/languagelearning/search?q=duolingo&amp;amp;restrict_sr=on&amp;amp;include_over_18=on&amp;amp;sort=relevance&amp;amp;t=all"&gt;reputation&lt;/a&gt; for people using it to study on a daily basis, sometimes for months or years, without making significant meaningful progress. Yes, we can blame the learners for only using a single resource, and only using it for a few minutes a day. But Duolingo's reputation in this regard far overshadows any similar examples I can think of. There's clearly something about Duolingo's formula that encourages the learner to feel as if they're being productive without actually helping them out of the bubble. Part of that comes down to their advertising, and part of it is their UI's positive tone and encouragement without reminders to study harder with other resources too.&lt;/p&gt;
&lt;p&gt;Forgive me if I don't provide too many other case studies of bad examples. I don't actually want to bully individuals, and these days I don't read / watch enough tutorial content to know names of popular creators. TTMIK just brought it out of me. Let's share some positives instead.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/channel/UCG-KntY7aVnIGXYEBQvmBAQ"&gt;Thomas Frank&lt;/a&gt; has created a respectable channel and I am happy for his success. Spreading the word about learning and motivation is nothing but a good thing. You can tell, though, that his video topics tend to repeat, probably partially as a result of fan requests. For a general topic like "college level studying" of course I expect everything to stay rather basic and widely applicable, but I think Frank's channel is a good example of the pressure to publish exceeding the number of new topics to explore in the space.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://youtube.com/channel/UC7ynjArlSFuXW23ssZAknyA/videos"&gt;GO! Billy Korean&lt;/a&gt; is a great guy and I admire his passion for teaching. He usually doesn't get into highly advanced lessons, but he gets into intermediates with his language and culture trends videos. He even goes through the effort of cutting down his live 2-hour classes into 12-minute abridged versions, which I know for a fact is not a quick thing to do. His videos are straight to the point and he very, very rarely mentions his paid books or patreon. His primary lesson videos are short enough and well-titled. My only criticism is that he seems to have put a hold on his primary series of 113 episodes to start a new &lt;a href="https://www.youtube.com/watch?v=uOlcIBtaplQ"&gt;beginner course&lt;/a&gt;, which is a bit of a circle back into the tar pit.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://youtube.com/channel/UCgHxZ3lZwfxQcr-P6HuU7mA/videos"&gt;ultimateKOREAN&lt;/a&gt; is a champion of lesson quality. How often do you see actual bibliographic citations in a youtube video description? Although the specific dialogues that he teaches with are often above my level, his explanations give me clear insight on what I should look out for as I continue to learn. He is careful to note that grammar taught in textbooks is not the same as grammar used in real life, and always presents multiple possible reasons why a certain grammar construction would be used. In the comments of &lt;a href="https://www.youtube.com/watch?v=Lzi1jzpT6XI"&gt;A deep look at 잖아&lt;/a&gt;, he says "I love doing this but at the same time I somewhat feel discouraged when other channels get more views for less informative content". Please show him your appreciation.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://youtube.com/channel/UCivA7_KLKWo43tFcCkFvydw/videos"&gt;Ben Krasnow aka Applied Science&lt;/a&gt; doesn't make 'lessons' per se, but he is undeniably a natural teacher. Everything he does is filled with genuine interest and the utmost respect for the viewers. He knows exactly how to progress the viewer's understanding from Never Heard of It to a reasonable understanding (for a sub-30 minute video) without ever dumbing down the scientific terminology. When he's experimenting with something, he always points out room for improvement and possible future applications to stimulate the imagination.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://youtube.com/channel/UCYO_jab_esuFRV4b17AJtAw/videos"&gt;3Blue1Brown&lt;/a&gt; makes animated math videos and &lt;a href="https://github.com/3b1b/manim"&gt;publishes the code he makes them with&lt;/a&gt;. His goal is to clear away the magical haze that blocks peoples' understanding of math by showing how complicated systems can be represented with clear, intuitive visuals. His lessons are awesome and he's awesome.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://youtube.com/channel/UC2bkHVIDjXS7sgrgjFtzOXQ/videos"&gt;Bill Hammack aka The Engineer Guy&lt;/a&gt; is a clear communicator who shows the fascinating internals and design of things we take for granted, often with a poetic bent. It's hard to pick a single best video, so check out &lt;a href="https://www.youtube.com/watch?v=wI-qAxKJoSU"&gt;Nitinol&lt;/a&gt;, &lt;a href="https://www.youtube.com/watch?v=RMjtmsr3CqA"&gt;Plastic injection molding&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=hUhisi2FBuw"&gt;Aluminum cans&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://youtube.com/channel/UC1T4KJG1L_kTrP9RcdU5Csw/videos"&gt;Ian LaSpina aka Knyght Errant&lt;/a&gt; participates in Medieval Living History events and makes videos about medieval culture, arms, and armor. Although I never considered myself to be very interested in history, I was absolutely absorbed by his &lt;a href="https://www.youtube.com/watch?v=mSjmxMfEtvE"&gt;Palazzo Ducale Bascinet video&lt;/a&gt; and quickly &lt;a href="https://git.voussoir.net/voussoir/ycdl#easily-watch-every-video-on-the-channel"&gt;binged&lt;/a&gt; his whole channel.&lt;/p&gt;
&lt;h2 id="escape_the_bubble"&gt;Escape the bubble&lt;a class="header_anchor_link" href="#escape_the_bubble"&gt; (§)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To creators who are passionate about teaching: Know that there is an audience who desires higher level learning material. Know that a thoughtful and powerful lesson maintains its value and rewatchability for a long time, although the overall view count will be lower than the cheap stuff. Rewatching well-presented lessons is a pleasure in itself, and I frequently rewatch videos on the channels mentioned here just for fun. Know that as the creator, your channel is your ship to steer and you don't need to be pulled back by audience requests.&lt;/p&gt;
&lt;p&gt;To creators who are passionate about making money: Nothing I can say will change your mind.&lt;/p&gt;
&lt;p&gt;To learners: Recognize when you are being held in a tar pit. Diversify your learning sources so as to know the strengths and weaknesses of each. Encourage creators who do good work, because they need to hear your appreciation. Support them on patreon etc. if you want to go the extra mile.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/beginner_bubble/beginner_bubble.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/3475cb0abf63172e6392487ffaf41755f71a18e3"&gt;&lt;time datetime="2023-09-18T21:01:09-07:00"&gt;2023-09-18&lt;/time&gt; Replace github links with git.voussoir.net.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/dfea7417b29e5d258162add171917e3e564569f3"&gt;&lt;time datetime="2021-01-02T23:39:47-08:00"&gt;2021-01-02&lt;/time&gt; Fix typo "his goal it to".&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/99ce0997616aacb5f052ea89cdb2a08e9b710402"&gt;&lt;time datetime="2020-09-19T19:37:02-07:00"&gt;2020-09-19&lt;/time&gt; Add link to Lights and Shadows.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/bf989111ff8e6bc1c7252f28accc094bb14635cb"&gt;&lt;time datetime="2020-08-28T16:53:23-07:00"&gt;2020-08-28&lt;/time&gt; Add link to an old TTMIK video.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/7fee5d031f01199acf70db5b8923fab037332ca5"&gt;&lt;time datetime="2020-08-10T20:46:22-07:00"&gt;2020-08-10&lt;/time&gt; Rename voussoir/YoutubeChannelDownloader -&amp;gt; voussoir/ycdl.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/56bbc1b95acc9d2c85c97878779196797f50a031"&gt;&lt;time datetime="2020-08-06T14:34:30-07:00"&gt;2020-08-06&lt;/time&gt; Add beginner_bubble.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Fri, 07 Aug 2020 00:34:30 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/beginner_bubble</guid></item><item><title>Pull to Waste Your Life</title><link>http://evantravers.com/articles/2020/08/06/pull-to-waste-your-life/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/08/magic_thread.png" /&gt;&lt;/p&gt;&lt;p&gt;I read a short story twenty years ago… yet it has stayed with me. It's called &lt;a href="http://www.davidgaultiere.com/the-magic-thread/"&gt;&lt;em&gt;The Magic Thread&lt;/em&gt;&lt;/a&gt;, I first read it in The collection of short stories called &lt;em&gt;The Book of Virtues&lt;/em&gt;&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;You &lt;strong&gt;should&lt;/strong&gt; go read it, but here is the gist: a young man is given a dangerous magic gift&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;2&lt;/a&gt;&lt;/sup&gt;: a silver ball that slowly emits a shining thread. When the thread is pulled… time &lt;em&gt;actually&lt;/em&gt; flies by! Bored of a day at school… he gives the thread a little tug and suddenly recess is here. He's tired of waiting to be old enough to marry… a harder tug and he's standing at the altar… he's tired of making a small salary… a yank and he's middle aged, a partner at the firm. Before too long he's left an old man with no memories… and the thread is too short to pull any more. He considers the cost, talking to the old woman who gave him the ball:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Your magic ball is a wonderful thing. I have never had to suffer or wait for anything in my life. And yet it has all passed so quickly. I feel that I have had no time to take in what has happened to me, neither the good things nor the bad. Now there is so little time left. I dare not pull the thread again for it will only bring me to my death. I do not think your gift has brought me luck.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The story is supposedly a French fable, I haven't been able to trace the origin or translator&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-4" id="fnref-4"&gt;3&lt;/a&gt;&lt;/sup&gt;. The moral was simply about impatience and the importance of treasuring the moments. When it was reprinted in 1993, &lt;a href="http://nokiamuseum.info/category/launching-year/1993/"&gt;cell phones could not even play snake&lt;/a&gt; and they cost a fortune to operate. When this short story was likely written there was very little of the current swath of time-draining technology. No Candy Crush, no binging of seasons of serialized fiction, no infinity pools of influencers spewing content algorithmically calculated to keep us scrolling… the tale was written to warn about simple daydreaming and sleeping our day away.&lt;/p&gt;
&lt;p&gt;I do not think William Bennett imagined that only two decades after he included this fable in his anthology every human, seven years or older, would have &lt;em&gt;actual&lt;/em&gt; magic devices in their pockets. We have a blessing and a curse, with no stern warning of the danger. His idyllic fable now reads as a dystopian sci-fi warning.&lt;/p&gt;
&lt;p&gt;I think about Peter and his silver ball every time I &amp;quot;pull down to refresh&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-3" id="fnref-3"&gt;4&lt;/a&gt;&lt;/sup&gt;…&amp;quot; and half an hour disappears without a whimper… or a useful memory of what I have consumed. At the end of our days there will be no old magic woman to take away the ball and give us the second chance to try again… just hours of empty time without meaningful memories and a full browser history.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;I've had a terrible dream, Mother. I dreamed that I was old and sick and that my life had passed like the blinking of an eye with nothing to show for it. Not even any memories.&amp;quot;&lt;/p&gt;
&lt;p&gt;His mother laughed and shook her head.&lt;/p&gt;
&lt;p&gt;&amp;quot;That will never happen,&amp;quot; she said…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yikes.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;William J. Bennett. &lt;em&gt;Book of Virtues&lt;/em&gt;. Simon and Schuster, 1993. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/The_Monkey%27s_Paw"&gt;The Monkey's Paw&lt;/a&gt; is a story about some people who get what they wish for... with a twist. It's a trope now. &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-4"&gt;
&lt;p&gt;&lt;a href="https://scifi.stackexchange.com/questions/33743/identify-a-story-about-a-magic-string-box"&gt;A StackExchange question trying to find the same thing…&lt;/a&gt; &lt;a class="footnote-backref" href="#fnref-4"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-3"&gt;
&lt;p&gt;Here I'm referring to the common mobile UX affordance of pulling down from the top of the screen to refresh… Six months ago, I deleted Instagram off my phone. A week ago… I blocked twitter and instagram's URLs from my phone browser. I still struggle. 😔 &lt;a class="footnote-backref" href="#fnref-3"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Thu, 06 Aug 2020 19:23:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/08/06/pull-to-waste-your-life/</guid></item><item><title>My Thoughts on Eric Weinstein's Thoughts on Pia Kalani's Thoughts</title><link>https://josh.works/my-thoughts-on-erics-thoughts-on-pias-thoughts</link><description>&lt;h2 id="context-for-two-sentances"&gt;Context for two sentances&lt;/h2&gt;

&lt;p&gt;It’s August 8, 2020.&lt;/p&gt;

&lt;p&gt;The news is full of coronavirus, schools, employment, police brutality, a vaccine, elections, &lt;em&gt;so much politics&lt;/em&gt;, China, Tik-Tok, the Twitter-dm-hack-bitcoin-scam-or-was-it-dm-content hack happened.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tiger King&lt;/em&gt;, &lt;em&gt;Cheer&lt;/em&gt;, &lt;em&gt;Filthy Rich&lt;/em&gt; are some of the most-watched shows in America, run on Netflix. &lt;em&gt;Hamilton&lt;/em&gt; came out on Disney+ six weeks ago, and I’ve not heard about civil unrest, protests, riots or anything in a week or so.&lt;/p&gt;

&lt;p&gt;My wife and I are trying to buy a house in Denver. We just looked at a small property that was adorable for many reasons, closely related to the themes expounded upon in &lt;a href="https://www.strongtowns.org/"&gt;Strong Towns&lt;/a&gt;, &lt;a href="https://granolashotgun.com/"&gt;Granola Shotgun&lt;/a&gt;, and &lt;a href="https://www.goodreads.com/book/show/39644188-order-without-design"&gt;Order Without Design: How Markets Shape Cities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The property will likely sell to someone for $500,000, but we feel strongly that it does not justify this price, and we will therefore not purchase it.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This quote I want you to read comes from a podcast episode recorded April 21. I listened to the podcast episode a few days ago.&lt;/p&gt;

&lt;p&gt;I’ve never really listened to any Eric Weinstein before, but the guest was an author I find interesting. I’ve read two of the author’s books twice, and I rarely re-read books.&lt;/p&gt;

&lt;p&gt;Here’s the whole episode: &lt;a href="https://play.pocketcasts.com/podcasts/93e73600-7ea8-0137-f540-17da1cd0d495"&gt;The Portal ep 31: Ryan Holliday&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before the episode starts, though, Eric Weinstein shares a thought he had. I found it striking, and wanted to see if others might find it striking as well.&lt;/p&gt;

&lt;p&gt;Here’s what he said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It occurred to me […] that the two older generations of Americans who are to duke it out in the race for the Presidency share a single purpose:&lt;/p&gt;

  &lt;p&gt;Their common goal [is]: stop the future from arriving at essentially any cost to future generations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;The purpose for this goal is: that they could live out their remaining days in as close to the style to which they’d become as accustomed to [in the 50’s through 70s] as is actually possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This quote maybe wouldn’t have stuck out to me in isolation, but I’d heard it after some context building he did.&lt;/p&gt;

&lt;p&gt;So, I’ll share that context with you, so you can consider the above quote in context.&lt;/p&gt;

&lt;p&gt;I tried to find a transcrip of this episode, and found &lt;a href="https://moses.land/transcript-ryan-holiday-and-eric-weinstein-on-the-portal-episode-31/"&gt;this&lt;/a&gt; machine-generated transcript. It was a giant blob of text, no line breaks, no formatting, so I’ve edited that version here.&lt;/p&gt;

&lt;p&gt;As I edited it, I’ve made a few modifications for clarity &lt;em&gt;and I inject my own thoughts&lt;/em&gt;. I mark my own thoughts clearly, but it seems the easiest way to share the context.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="3-minutes-from-the-opening-of-the-portal-episode-31"&gt;3 minutes from the opening of &lt;em&gt;The Portal, Episode 31&lt;/em&gt;&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Josh: I’m quoting Eric from the podcast episode now. These are all his words, or his recounting of his conversation with his wife/others:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eric (00:02:27)&lt;/strong&gt;
For the last month I’ve spent nearly all of my time at home with my family and many of the better thoughts I’ve been exploring during this time are due to my collaborator and wife, Pia Malaney.&lt;/p&gt;

&lt;p&gt;Pia is the economist who currently runs CIGS, the &lt;a href="https://cigs-inet.org/"&gt;Center for Innovation, Growth and Society&lt;/a&gt;, which she co-founded with INET, the Institute for New Economic Thinking.&lt;/p&gt;

&lt;p&gt;Very early on, I was fumbling to try to understand the most likely effects of the virus and she said something clarifying which I wish I had repeated to you all when it was fresh, she said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I think in a way the virus can be thought of as representing the future.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don’t know. Maybe I’m dense, but I didn’t catch it the first time so I asked her to clarify. She was surprised that this wasn’t obvious to me so she spelled her position out:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Think about it this way, take all of the seemingly varied issues we discussed constantly over the dinner table and at conferences.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;“All of them?” I replied with the slightly teasing voices. I assumed she was speaking with hyperbole.&lt;/p&gt;

&lt;p&gt;Without an ounce of self doubt in a voice that I have learned to fear over many years of collaboration, she said brightly:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Why yes, pretty much all of them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;She continued:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Let’s start with&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;surveillance&lt;/li&gt;
    &lt;li&gt;monopolies&lt;/li&gt;
    &lt;li&gt;automation,&lt;/li&gt;
    &lt;li&gt;telecommuting&lt;/li&gt;
    &lt;li&gt;next generation warfare&lt;/li&gt;
    &lt;li&gt;UBI&lt;/li&gt;
    &lt;li&gt;future of work&lt;/li&gt;
    &lt;li&gt;the retail apocalypse&lt;/li&gt;
    &lt;li&gt;online dating&lt;/li&gt;
    &lt;li&gt;antivaxxers&lt;/li&gt;
    &lt;li&gt;the student debt crisis&lt;/li&gt;
    &lt;li&gt;supply chain vulnerability&lt;/li&gt;
    &lt;li&gt;green tech and climate change&lt;/li&gt;
    &lt;li&gt;urban homelessness&lt;/li&gt;
    &lt;li&gt;college equivalency certificates&lt;/li&gt;
    &lt;li&gt;biohacking,&lt;/li&gt;
    &lt;li&gt;the retreat from globalization,&lt;/li&gt;
    &lt;li&gt;collapse of mainstream journalism&lt;/li&gt;
    &lt;li&gt;Chinese ascendance&lt;/li&gt;
    &lt;li&gt;social engineering&lt;/li&gt;
    &lt;li&gt;Saudi modernization and the move away from fossil fuels in the Kingdom&lt;/li&gt;
    &lt;li&gt;inclusive stakeholding&lt;/li&gt;
    &lt;li&gt;political realignment and the problem of gerontocracy and the end of naive capitalism underpinned by U. Chicago-style economics&lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;in fact, pretty much all the things we’ve used [the Center for Innovation, Growth, and Society] to explore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;“Okay”, I said nervously&lt;/p&gt;

&lt;p&gt;“Well”, she continued,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;you know that tired tech expression &lt;code class="language-plaintext highlighter-rouge"&gt;the future is already here it just isn’t evenly distributed&lt;/code&gt;?&lt;/p&gt;

  &lt;p&gt;Across the board, this virus is accelerating that unifying future that was already headed our way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And recapitulating that moment, where agent Kujan drops the Kobayashi coffee mug in &lt;em&gt;The Usual Suspects&lt;/em&gt;, a forest spontaneously emerged for me, from the confusion of the trees I had seen previously.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Josh: I didn’t know this reference, as I was editing this transcript, I looked it up. I’ve not seen the movie, so looked up the scene.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The description is: &lt;code class="language-plaintext highlighter-rouge"&gt;The Ending of Usual Suspects when agent Kujan finds out who Keyser Soze is. One of the best scenes from the previous decade.&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;back to Eric:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eric (00:04:20)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All of these seemingly disparate phenomena were suddenly revealed as closely related:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Americans were actually calling for their own surveillance only they were calling it “contact tracing”.&lt;/li&gt;
  &lt;li&gt;The retail apocalypse which had been building slowly suddenly became a matter of a government decree creating an ever more imposing monopoly for the world’s now richest human.&lt;/li&gt;
  &lt;li&gt;He in turn, owns and controls the only paper to take down a US president, consolidating control over our sense-making apparatus.&lt;/li&gt;
  &lt;li&gt;Most supposedly “essential” face-to-face office work was revealed to be illusory, as easily monitored-and-recorded telecommuting replaced the high-carbon commute&lt;/li&gt;
  &lt;li&gt;the demand for fossil fuels in turn evaporated pushing oil futures into radical states of contango.&lt;/li&gt;
  &lt;li&gt;Social distancing solved the problem of unwanted #MeTo toxic male touch a sexless Zoom dating put the hurt on “Netflix and chilling”.&lt;/li&gt;
  &lt;li&gt;Indeed, nearly UBI-like payments were going out to newly-unemployed former workers who were expected to sit at home on couches, as universities effectively all-but-confessed that they could deliver the same value through distance learning by not rebaiting extortionary tuition.&lt;/li&gt;
  &lt;li&gt;China, through an emasculated World Health Organization, seemingly began inducing our own US institutions like the CDC and Surgeon General’s office to impart deadly “magical thinking” to Americans about the ineffectiveness of masks for healthy people.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This all came as if some kind of twisted revenge for the &lt;a href="https://en.wikipedia.org/wiki/Boxer_Rebellion"&gt;Boxer Rebellion&lt;/a&gt; where Chinese believe swords and martial arts made them invulnerable to Western high-tech warfare.&lt;/p&gt;

&lt;p&gt;Spontaneous protests broke out in cities across the country, as masked protesters fought mysterious rules that communicated that one may &lt;em&gt;not&lt;/em&gt; peaceably assemble, in contradition to the First Amendment.&lt;/p&gt;

&lt;p&gt;We were also not allowed to contradict public health authorities, who are clearly covering for a level of Baby Boomer and Silent Generation incompetence to keep the manufacturer and storage of essential goods and services within national boundaries and out of the hands of strategic rivals who think nothing of blatantly lying to us in matters of life, death and statistics.&lt;/p&gt;

&lt;p&gt;I reasoned, however, that there were clearly too many different things happening in such a situation, for the sudden arrival of the future to lack a single ideology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eric (00:6:28)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And so it occurred to me (and to Peter Thiel as well, who I called immediately) that the two older generations of Americans who were to duke it out in the race for the presidency shared a single purpose.&lt;/p&gt;

&lt;p&gt;Their common goal was “to stop the future from arriving at essentially any cost to future generations” so that they could live out the remaining days in as close to the style to which they’d become accustomed in childhood and young adulthood as was actually possible.&lt;/p&gt;

&lt;p&gt;And what did they use to accomplish this? Well, it was a combination of three ingredients:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;political control&lt;/li&gt;
  &lt;li&gt;a seemingly inexplicably indifference to the world of trouble that they would finally leave to their descendants after their demise.&lt;/li&gt;
  &lt;li&gt;a reliance on 75 years of astonishingly good luck, which can partially be explained as a rational universal fear of the future after:
    &lt;ul&gt;
      &lt;li&gt;two world wars&lt;/li&gt;
      &lt;li&gt;totalitarian atrocities&lt;/li&gt;
      &lt;li&gt;the 1918 pandemic&lt;/li&gt;
      &lt;li&gt;the Great Depression&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is related to Francis Fukuyama’s theory of &lt;a href="https://en.wikipedia.org/wiki/Francis_Fukuyama#The_End_of_History_and_the_Last_Man"&gt;The End of History&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To [Boomers and Silent Generation members who held] this way of thinking what was happening was simple.&lt;/p&gt;

&lt;p&gt;The magic trick of holding back nearly all aspects of our true future required all three elements to be in place &lt;em&gt;simultaneously&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And nothing had changed with respect to the first two. In fact, all that it occurred was that their luck had finally run out with the COVID virus.&lt;/p&gt;

&lt;p&gt;To my generation, and the ones that followed that past version of the post-war American Dream was like a mesmerizing rumor and tale that the older generations had repeatedly and vividly wielded to cast a spell.&lt;/p&gt;

&lt;p&gt;This spell intimidated many of us from demanding answers and a say our own future.&lt;/p&gt;

&lt;p&gt;The spell they cast said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If you can’t get a second home in your 30s from a paper route, a low cost education or a life in public service, then perhaps you should wait your turn and let the elders who made it work lead for a little while longer, until the younger generations can prove that they’re ready to assume adult responsibilities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was a magical spell indeed, which blinded those of us who are forced to repeat “Okay Boomer” to explain our seeming relative inability to earn and lead in the presence of elders who could out-earn us in their prime.&lt;/p&gt;

&lt;p&gt;And this was even under the weight of multiple divorce settlements, or three-Martini lunches, and without the extensive training and apprenticeships that we seem to require.&lt;/p&gt;

&lt;p&gt;Well, that spell is now broken for me, watching our supposed leaders contend with a true pandemic.&lt;/p&gt;

&lt;p&gt;The Silent and Boomer generations, lacking any kind of precedent now look like incompetent adults.&lt;/p&gt;

&lt;p&gt;I suppose it is theoretically possible that the rest of us former gritty latchkey kids and Digital Natives would not fare better, but we could scarcely do worse.&lt;/p&gt;

&lt;p&gt;In fact, our elders are revealed not as go-getters or “can-do” leaders but as creatures of The System, who simply held back confronting the inevitable future for decades because its shape and form are indeed terrifying.&lt;/p&gt;

&lt;p&gt;And it wasn’t really the virus that was accelerating the terrifying future across the board.&lt;/p&gt;

&lt;p&gt;Any worldwide crisis of sufficient depth would have done it.&lt;/p&gt;

&lt;p&gt;The world has always been caught up in escalating plagues, wars, depressions and conflicts. The Coronavirus was ushering in the future simply because it was the first piece of early 20th-century-scale bad luck to fall into our new millennium characterized as it is by fragility.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I’ve got some thoughts that I’ll jot down at some point.&lt;/p&gt;

&lt;p&gt;But as I collect my thoughts, how about you? What’s your gut reaction to this?&lt;/p&gt;</description><author>Josh Thompson</author><pubDate>Thu, 06 Aug 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/my-thoughts-on-erics-thoughts-on-pias-thoughts</guid></item><item><title>How To Write A Letter of Recommendation for Yourself</title><link>https://josh.works/how-to-write-a-letter-of-recommendation-for-yourself</link><description>&lt;p&gt;I meet regularly with early-career software developers. A few recurring meetings, 1x/week, plus ad-hoc calls as needed with others.&lt;/p&gt;

&lt;p&gt;A question came up recently:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;My three-month internship is close to wrapping up. The Co-founder/CEO/lead developer of the consulting company I’m at likes me, said he wishes he could hire me but cannot, because they don’t have enough work in the pipeline.&lt;/p&gt;

  &lt;p&gt;He said he’d write me a letter of recommendation, and asked me to draft it for him.&lt;/p&gt;

  &lt;p&gt;How do I write my own letter of recommendation, for my first real software development job?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Feels like a trap, huh?&lt;/p&gt;

&lt;p&gt;&lt;img alt="who are you?" src="/images/office-hours-tufts.jpeg" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://admissions.tufts.edu/blogs/jumbo-talk/post/the-office-hours/"&gt;&lt;em&gt;source&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or, maybe they know you. They know you &lt;em&gt;too well&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img alt="untrustworthy" src="images/recommendation-warning.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blacklawyermagic.wordpress.com/"&gt;&lt;em&gt;source&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I explained a few concepts that we wanted to “speak to” in the letter. I’ll explain.&lt;/p&gt;

&lt;p&gt;The software developer that I meet with mentioned that the CEO’s advice on the next job included “be able to speak to low liability”.&lt;/p&gt;

&lt;p&gt;I wanted to dig into this “liability” piece.&lt;/p&gt;

&lt;h2 id="how-much-does-a-bad-hire-cost"&gt;How much does a bad hire cost?&lt;/h2&gt;

&lt;p&gt;What’s the biggest risk in hiring?&lt;/p&gt;

&lt;p&gt;It’s &lt;em&gt;the risk of a bad hire&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;How much does it cost to make a bad hire?&lt;/p&gt;

&lt;p&gt;I would conservatively estimate that it costs $100,000 and nine months of your life. Here’s how the math works from a hiring manager’s point of view:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Spend a month and 25 hours of labor dev team manager labor to find/interview the candidate(s) and winnow the applicants down to someone to make an offer.  (the hiring manager would prefer to be doing &lt;em&gt;literally anything else but hiring&lt;/em&gt;.)&lt;/li&gt;
  &lt;li&gt;Extend an offer, wait 2-6 more weeks before the new candidate starts. It can be painful to wait another six weeks, because the team is currently short-staffed, and has been for a long time. That’s why they’re hiring!&lt;/li&gt;
  &lt;li&gt;Start date! Start paying $150,000/yr or $3000/week for your shiny new employee.&lt;/li&gt;
  &lt;li&gt;Pay $12,000 for the first month of them working, figuring out your dev environment, ticket management, who knows what parts of the codebase, and a few easy bug fixes.&lt;/li&gt;
  &lt;li&gt;Start getting nervous. Employee not batting it out of the park like you’d hoped. Maybe still onboarding, give it another month (and $12,000 in payroll expense).&lt;/li&gt;
  &lt;li&gt;OK. Three months in and another $36,000 in payroll later, you’re pretty sure there’s a problem.&lt;/li&gt;
  &lt;li&gt;Start the pre-Performance Improvement Plan work. Talk to their team, their manager, them. Why is it not working? Why is the team &lt;em&gt;working slower&lt;/em&gt; with this new team member, instead of working faster? &lt;em&gt;Not only are you wasting five figures of payroll, the rest of your expensive dev team is producing less as well!&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Pre-PIP work is over. Another $5k in payroll gone forever. Now it’s time to give the formal PIP, which everyone knows is “beginning the firing process”&lt;/li&gt;
  &lt;li&gt;Two more months and $24,000 in payroll later, you fire the employee.&lt;/li&gt;
  &lt;li&gt;You feel relief with having gotten rid of the bad employee. You’re thrilled that you can get back to normal work.&lt;/li&gt;
  &lt;li&gt;Check the clock and balance sheet. It took you nine months and $100k to get to where you were at step 1.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Add up the time/expense:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;1-2 months to to find/hire a candidate.&lt;/li&gt;
  &lt;li&gt;7-8 months (and $84K-$96k) to hire, trial them, try to help them be successful, give up on that plan, and fire them.&lt;/li&gt;
  &lt;li&gt;Many hours spent thinking about this specific problem, talking with others about it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There’s nine months of your life. That’s 9 months of time, sure, but it’s also 9 months of &lt;a href="https://en.wikipedia.org/wiki/Opportunity_cost"&gt;opportunity cost&lt;/a&gt;. What if you’d hired a great candidate? They’d be rapidly approaching their first year on the job, and everyone would be happy about it, instead of this disaster you’ve had to deal with.&lt;/p&gt;

&lt;p&gt;Here’s the really scary part: To large organizations (1000+ employees), &lt;em&gt;wasting $100k is meaningless compared to the wasted time and mis-directed effort&lt;/em&gt;. The entire organization is more annoyed at having &lt;em&gt;lost the time of a productive software developer&lt;/em&gt;. They don’t care that they lit a giant pile of money on fire, &lt;em&gt;they’re annoyed that their competitor is getting new features out the door and gaining marketshare and the future of their $x,000,000 company hangs in the balance&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Oh, and the good managers, not only do they want to be wise with money and build features/gain market-share…&lt;/p&gt;

&lt;p&gt;They want to see their team flourish.&lt;/p&gt;

&lt;p&gt;Being fired is a life-defining moment. (I speak from experience)&lt;/p&gt;

&lt;p&gt;If you’re a kind and empathetic person, &lt;em&gt;it’s particularly unpleasent to fire someone and it feels like a personal failure&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You want to work for a kind and empathetic manager. (They’re not common, but they’re not impossible to find.)&lt;/p&gt;

&lt;p&gt;So, tailor your letter to speak to the concerns of a kind and empathetic manager. This manager would:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Want to see you do well&lt;/li&gt;
  &lt;li&gt;Want to see you develop your skills and competencies&lt;/li&gt;
  &lt;li&gt;Want you to make meaningful contributions to the product&lt;/li&gt;
  &lt;li&gt;Want a healthy team dynamic&lt;/li&gt;
  &lt;li&gt;Want you to voice concerns and observations as relevant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And much more&lt;/p&gt;

&lt;h2 id="a-primary-goal-for-an-early-career-software-developer-telegraph-low-liability"&gt;A Primary-goal for an early-career software developer: Telegraph Low Liability&lt;/h2&gt;

&lt;p&gt;First, when I say &lt;code class="language-plaintext highlighter-rouge"&gt;telegraph low liability&lt;/code&gt; I mean it in the &lt;a href="https://en.wikipedia.org/wiki/Telegraphing_(sports)"&gt;sports definition&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In sporting terminology, to &lt;strong&gt;telegraph&lt;/strong&gt; is to unintentionally alert an opponent to one’s immediate situation or intentions. The sporting use of the term &lt;em&gt;telegraph&lt;/em&gt; draws a direct comparison with the communication device of the same name. “Telegraphing” always refers to a reflexive physical action rather than a protracted or intellectual give-away. For example, a boxer rotating his shoulders to throw a hook would be telegraphing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should aim to “telegraph” that you’re a low-liability hire &lt;em&gt;without ever saying it so explicitely&lt;/em&gt;. It’s a subtle thing, best communicated incidentally, not directly.&lt;/p&gt;

&lt;p&gt;Five years ago, I wrote &lt;a href="/so-you-want-to-work-remotely"&gt;So you want to work remotely…&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quoting myself:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;First, there’s the matter of framing how you go about working remotely. Obviously you want to work remotely, but put yourself in the shoes of a prospective employer. They don’t care if you work remotely or not - they want you to do great work for them and make them an effective, profitable organization.&lt;/p&gt;

  &lt;p&gt;Companies that hire remotely tend to be younger, agile-er, and smaller. So every employee matters. Making a bad hire can be catastrophic in terms of money and &lt;a href="https://en.wikipedia.org/wiki/Opportunity_cost"&gt;opportunity cost&lt;/a&gt;. Your job is to make it very, very obvious that hiring YOU is a great decision. In fact, you want to be so good at what you do that passing up on you is a terrible decision.&lt;/p&gt;

  &lt;p&gt;[…]&lt;/p&gt;

  &lt;p&gt;When you can walk someone down the path from “Hire me” to “I’ll help you make &lt;code class="language-plaintext highlighter-rouge"&gt;$x00,000/year&lt;/code&gt; more than you would otherwise”, &lt;em&gt;you’re talking their language&lt;/em&gt;. You’re &lt;em&gt;telegraphing&lt;/em&gt; that you understand their concerns without ever stating their concern explicitly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To bring it full circle, here’s how I would go about &lt;em&gt;drafting&lt;/em&gt; a CEO’s Letter of Recommendation &lt;em&gt;for me&lt;/em&gt;. If you find this idea uncomfortable, don’t worry about it. That’s a sign of psychological health, that you don’t love putting flattering words &lt;em&gt;about yourself&lt;/em&gt; into other people’s mouths.&lt;/p&gt;

&lt;h2 id="six-steps-to-draft-a-self-promotional-letter-of-recommendation-that-a-friendly-boss-requested"&gt;Six Steps To Draft A Self-Promotional Letter Of Recommendation That A Friendly Boss Requested&lt;/h2&gt;

&lt;p&gt;Normally, that’s a good aversion to have. For this particular situation, you’ll have to bite the bullet and move on. I’m not going to give you the actual words (how could I?) but I’ll explain my process. I’ll include comments throughout:&lt;/p&gt;

&lt;h3 id="1-draft-the-openingclosing"&gt;1. Draft the opening/closing&lt;/h3&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;Hi there,         
# I find it easier to strike a natural tone when thinking relatively
# informally. So, I draft documents, even if they'll end up being 
# formal, informally. 
             
             
Sincerely, 
- Boss's name, Title, Company
# Yes, I write the closing right after the opening.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id="2-provide-1-general-introductioncontext-sentence"&gt;2. Provide 1 general introduction/context sentence&lt;/h3&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;Hi there,

# Establish the relationship. This helps readers contextualize 
# what comes next
I met {person I am recommending} {n months ago} because 
 {internship|coffee meeting|event|etc}.

Sincerely,
- Boss's name, Title, Company
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id="3-say-a-complementary-thing-about-yourself"&gt;3. Say a complementary thing about yourself&lt;/h3&gt;

&lt;p&gt;This is the first uncomfortable sentence you’ll have to write:&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;Hi there,

I met {Zaniyah} {a few months ago} because {she and I crossed paths
at a local Ruby meetup}.

# No gushing required. A claim of "I would hire this 
# person if I could" is plenty strong social signaling. 
I wish I could hire them myself, but don't have the budget and work
lined up to utilize them to their full potential. 

Sincerely,
- Boss's name, Title, Company
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id="4-share-an-anecdote-that-touches-on-the-potential-you-show"&gt;4. Share an anecdote that touches on the potential you show&lt;/h3&gt;

&lt;p&gt;This can be hard to think of an anecdote. It might take a few attempts to feel good about the one you’ve chosen and how you speak of it. Just write something down, see how you feel, delete it, write something else down, etc.&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;Hi there,

I met {Zaniyah} {a few months ago} because {she and I crossed paths 
at a local Ruby meetup}.

I wish I could hire her myself, but don't have the budget and work 
lined up to utilize her to their full potential. 

# add a punchy positive story
When she started at {company}, one of the first things she did was 
make many updates to our onboarding documentation. 

It was rather out-of-date, and the team hadn't had new hires in a 
while. 

Any time she ran into friction or trouble, she would hunt down the 
answer, and immediately update the documentation so the next 
person would have a smoother process.

Sure enough, the next hire spent half the time she did getting 
up and running.

# If possible, generalize from that story to a stable attribute 
# that informs your work:
She brings a similar attention to detail and thoughtfullness about 
"the next person" to all of the work that she does. 

Sincerely,
- Boss's name, Title, Company
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id="5-add-a-sentence-offering-to-speak-further-about-you"&gt;5. Add a sentence offering to speak further about you&lt;/h3&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;Hi there,

I met {Zaniyah} {a few months ago} because {she and I crossed paths 
at a local Ruby meetup}.

I wish I could hire her myself, but don't have the budget and work 
lined up to utilize her to his full potential. 

# add a punchy positive story
When she started at {company}, one of the first things she did was 
make many updates to our onboarding documentation. 

It was rather out-of-date, and the team hadn't had new hires in a 
while. 

Any time she ran into friction or trouble, she would hunt down the 
answer, and immediately update the documentation so the next 
person would have a smoother process.

Sure enough, the next hire spent half the time she did getting 
up and running.

She brings a similar attention to detail and thoughtfullness about 
"the next person" to all of the work that she does. 

# `An offer to provide evidence` is functionally the same as 
# `evidence`, so:
I'd be happy to answer any follow-up questions you might have 
about Zaniyah. Feel free to email me at `email`

Sincerely,
- Boss's name, Title, Company
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id="give-this-letter-to-your-boss-for-them-to-edit-it-to-their-liking"&gt;Give this letter to your boss for them to edit it to their liking&lt;/h2&gt;

&lt;p&gt;It may be intimidating to hand something like this to your boss.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Would they really have said such kind things about me? Won’t it be awkward if they read it, and say “eh, you’re not this great, lets tone it down a bit.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It would be awkward, but they won’t do that.&lt;/p&gt;

&lt;p&gt;Instead, they’ll be thankful that you did all this work for them. You know what feels terrible?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;really wanting to say a nice thing about someone, but good stories/examples of why they’re great don’t come to mind. You KNOW there are good stories and examples, but you don’t remember them all.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You’re solving a big problem for your boss, in writing this letter. &lt;strong&gt;That is why they asked you to draft your own letter of recommendation for them.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Done!&lt;/p&gt;

&lt;p&gt;If you’ve been tasked with writing your own letter of recommendation and it’s super intimidating, get in touch and I’ll help you out. Writing the first one is the hardest, it gets easier as you go.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’m not an expert on this kind of thing, but I always like finding templates others have given for how they do things. Don’t think that this is the Right Way or (heaven forbid) The Only Way. This is just how I do it. If you’d got a resource that has helped you, tell me about it and I’ll update this post with a link to it!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Lastly, if you got value from this blog post, I can probably deliver value to you again. Punch your email in below and I’ll let you know when I write other posts, or do a big update to an existing post.&lt;/p&gt;</description><author>Josh Thompson</author><pubDate>Thu, 06 Aug 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/how-to-write-a-letter-of-recommendation-for-yourself</guid></item><item><title>Build a Personal Website in Jekyll - A Detailed Guide For First-Timers</title><link>https://josh.works/build-a-personal-site-with-jekyll</link><description>&lt;p&gt;You’re a turing student, in the backend program.&lt;/p&gt;

&lt;p&gt;You know Ruby, you wanna start blogging, but everyone who says&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;go start a blog&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seems to also think you have 10 hours (or 20 hours? or 2 hours? how long does this take) to sit around dealing with setting up a personal website.&lt;/p&gt;

&lt;p&gt;Lets set one up.&lt;/p&gt;

&lt;h3 id="intended-audience"&gt;Intended audience:&lt;/h3&gt;

&lt;p&gt;Turing Mod 1 backend student, or ambitious mod-0 student&lt;/p&gt;

&lt;h3 id="output-and-expected-results"&gt;Output and expected results&lt;/h3&gt;

&lt;p&gt;Have a basic site online, at &lt;code class="language-plaintext highlighter-rouge"&gt;your-github-username.github.io&lt;/code&gt; that looks professional enough you could share it with a future employer, but puts the main emphasis on your words, not the flashyness of the page or complexity of the technology.&lt;/p&gt;

&lt;p&gt;My website (the one you’re reading on right now) looks pretty simple, and I know how to set it up, so we’ll &lt;em&gt;start&lt;/em&gt; with setting up something similar to my website, and I’ll show you how to use different templates as well.&lt;/p&gt;

&lt;h3 id="1-get-started-with-basic-jekylltheme-combination"&gt;1. Get started with basic jekyll/theme combination&lt;/h3&gt;

&lt;p&gt;Head to &lt;a href="https://github.com/poole/poole"&gt;https://github.com/poole/poole&lt;/a&gt;, and hit the &lt;code class="language-plaintext highlighter-rouge"&gt;clone or download&lt;/code&gt; url.&lt;/p&gt;

&lt;p&gt;In your terminal, make a new dirctory, perhaps in your pre-existing &lt;code class="language-plaintext highlighter-rouge"&gt;turing&lt;/code&gt; directory&lt;/p&gt;

&lt;div class="language-shell highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/turing

&lt;span class="c"&gt;# Here's we're cloning the repo, but placing it inside of a folder _we_ define name&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git clone &amp;lt;url from that &lt;span class="sb"&gt;`&lt;/span&gt;poole&lt;span class="sb"&gt;`&lt;/span&gt; repository&amp;gt; jekyll-site

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;jekyll-site

&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="c"&gt;# if `bundle install` throws error, do `gem install bundler`, then re-try `bundle install`&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll serve
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now the server should be running.&lt;/p&gt;

&lt;p&gt;Now, in a web browser, visit the given url:&lt;/p&gt;

&lt;p&gt;&lt;img alt="server running" src="https://p64.f2.n0.cdn.getcloudapp.com/items/GGukgv9R/2020-05-21%20at%2012.34%20PM.jpg?v=63d74cf95de2c35b20ef3b8f0cbc1521" /&gt;&lt;/p&gt;

&lt;h5 id="sidebar---what-the-heck-is-jekyll-how-does-this-thing-turn-into-a-website-that-people-can-visit"&gt;Sidebar - what the heck &lt;em&gt;is&lt;/em&gt; Jekyll? How does this thing turn into a website that people can visit?&lt;/h5&gt;

&lt;p&gt;great question! Holy cow.&lt;/p&gt;

&lt;p&gt;Jekyll’s documentation assumes a strong knowledge of how the internet works.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Transform your plain text into static websites and blogs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What does this mean? What’s a “static site generator”? Why do some people even care so much?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;more to come soon&lt;/em&gt;&lt;/p&gt;

&lt;h3 id="2-learn-the-basics-of-how-jekyll-works-so-you-can-customize-it-to-your-liking"&gt;2. Learn the basics of how Jekyll works, so you can customize it to your liking&lt;/h3&gt;

&lt;p&gt;Lets figure out the important parts of this new directory.&lt;/p&gt;

&lt;h4 id="_configyml"&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;_config.yml&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;the &lt;code class="language-plaintext highlighter-rouge"&gt;.yml&lt;/code&gt; extension stands for “Yaml Ain’t Markup Language”, which is the punchline to a joke.&lt;/p&gt;

&lt;p&gt;&lt;code class="language-plaintext highlighter-rouge"&gt;.yml&lt;/code&gt; is format common in Ruby for writing machine-readable setttings that are equally easy for humans to understand. So, your Jekyll site will use this file to set basic settings, but it’s easy for you to modify the values yourself.&lt;/p&gt;

&lt;p&gt;Here’s the first two changes you should make on your site:
&lt;img alt="first change" src="https://p64.f2.n0.cdn.getcloudapp.com/items/QwuKZYlA/jekyll_config.jpg?v=7e79afd04591ee5608c8cd8eacbc4711" /&gt;&lt;/p&gt;

&lt;p&gt;Look at lines 2 and 3 in my editor - try making those changes, then make them show up in your browser. Don’t forget to restart your server! (hit &lt;code class="language-plaintext highlighter-rouge"&gt;ctrl-r&lt;/code&gt; to kill it.)&lt;/p&gt;

&lt;h3 id="3-set-up-github-repo-to-host-your-site"&gt;3. Set up github repo to host your site&lt;/h3&gt;

&lt;p&gt;From github’s instructions:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Head over to &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; and &lt;a href="https://github.com/new"&gt;create a new repository&lt;/a&gt; named username.github.io, where username is your username (or organization name) on GitHub.&lt;/p&gt;

  &lt;p&gt;If the first part of the repository doesn’t exactly match your username, it won’t work, so make sure to get it right.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you’ve done that, clone the repository:&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;git clone https://github.com/username/username.github.io
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In that new directory, you’ll need to place your Jekyll site. If you want to keep working with the &lt;code class="language-plaintext highlighter-rouge"&gt;poole&lt;/code&gt; theme we’ve worked with, you will need “connect” your Jekyll site locally to this new repository.&lt;/p&gt;

&lt;p&gt;Lets first create a new directory at the root of your laptop for your website.&lt;/p&gt;

&lt;div class="language-shell highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/your-github-username.github.io
&lt;span class="nb"&gt;cd &lt;/span&gt;your-github-username.github.io
&lt;span class="nb"&gt;mv&lt;/span&gt; ~/turing/jekyll-site &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, lets connect your github repo to this repository:&lt;/p&gt;

&lt;div class="language-shell highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git init
&lt;span class="nv"&gt;$ &lt;/span&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit"&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;span class="c"&gt;# should come back empty&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git remote add origin &amp;lt;your clone-this-repo url from above&amp;gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git push origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, when you visit that URL, you should see all your files up there!&lt;/p&gt;

&lt;h1 id="customizing-your-new-jekyll-site"&gt;Customizing your new jekyll site&lt;/h1&gt;

&lt;p&gt;I’d recommend setting up a &lt;em&gt;very&lt;/em&gt; basic landing page. It’s what my home page looks like, and it’ll probably work for you.&lt;/p&gt;

&lt;p&gt;Here’s how:&lt;/p&gt;

&lt;p&gt;&lt;img alt="change index.html to index.md" src="https://p64.f2.n0.cdn.getcloudapp.com/items/5zuXZPZ6/2020-06-02%20at%209.20%20AM.jpg?v=cce72c77655716fb04e5d1e01882c66b" /&gt;&lt;/p&gt;

&lt;p&gt;Then delete all that stuff, and make it your own:&lt;/p&gt;

&lt;p&gt;&lt;img alt="add three sections" src="https://p64.f2.n0.cdn.getcloudapp.com/items/RBuq5Zw2/2020-06-02%20at%209.23%20AM.jpg?v=f6133f42c832e023da95a16b4a45dbf5" /&gt;&lt;/p&gt;

&lt;p&gt;Then fill it out and make it your own!&lt;/p&gt;

&lt;p&gt;Here’s what I might write, if I were doing this for myself:&lt;/p&gt;

&lt;p&gt;&lt;img alt="it would look like this" src="https://p64.f2.n0.cdn.getcloudapp.com/items/xQuDKxnz/2020-06-02%20at%209.26%20AM.jpg?v=4fe24cf63e185e7df22a1edf883d86e5" /&gt;&lt;/p&gt;

&lt;p&gt;And here’s how it would look running locally:&lt;/p&gt;

&lt;p&gt;&lt;img alt="running locally" src="https://p64.f2.n0.cdn.getcloudapp.com/items/mXuAd2rB/2020-06-02%20at%209.27%20AM.jpg?v=a3dc52ab0976aa55bf6a695cc2d41344" /&gt;&lt;/p&gt;

&lt;p&gt;I didn’t like how large the headings were, so instead of H1s (&lt;code class="language-plaintext highlighter-rouge"&gt;#&lt;/code&gt;), I went with H2: &lt;code class="language-plaintext highlighter-rouge"&gt;##&lt;/code&gt; before each section.&lt;/p&gt;

&lt;h3 id="additional-resources"&gt;Additional resources&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://josh.works/switching-to-jekyll"&gt;https://josh.works/switching-to-jekyll&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://jekyll-themes.com/"&gt;https://jekyll-themes.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Josh Thompson</author><pubDate>Thu, 06 Aug 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/build-a-personal-site-with-jekyll</guid></item><item><title>Terraforming Mars and Venus</title><link>https://one.mikro2nd.net/pages/terraforming-the-planets/</link><description>Elon Musk doesn&amp;rsquo;t have a fucking clue. He keeps punting the wildly techno-optimistic notion that, not only will we colonise Mars, we&amp;rsquo;ll do it within the next handful of decades. I find this overflowing with the naively exuberant &amp;ldquo;disrupt everything&amp;rdquo; style of SV tech optimism. That or some seriously good drugs.
On the other hand, I do agree with Musk, insofar as he echoes a sentiment that goes back at least as far as Tsiolkovsky: Earth is the cradle of Humankind, but one cannot live in a cradle forever.</description><author>one mikro2nd</author><pubDate>Thu, 06 Aug 2020 15:23:30 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/terraforming-the-planets/</guid></item><item><title>Why you should use functional components + Hooks over class components in React</title><link>https://maxrozen.com/react-components-hooks-functions-vs-classes</link><description>If you find yourself asking whether to use functional components with Hooks over class components, you'll find a lot of outdated information out there. Let's settle this once and for all in this article.</description><author>Max Rozen</author><pubDate>Thu, 06 Aug 2020 12:22:09 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/react-components-hooks-functions-vs-classes</guid></item><item><title>Getting started with Apache Avro and Python  Learn how to create and consume Apache Avro based data for better and efficient transfer.</title><link>https://blog.adnansiddiqi.me/getting-started-with-apache-avro-and-python/</link><description>&lt;p&gt;In this post, I am going to talk about Apache Avro, an open-source data serialization system that is being used by tools like Spark, Kafka, and others for big data processing. What is Apache Avro According to Wikipedia: Avro is a row-oriented remote procedure call and data serialization framework developed within Apache&amp;#8217;s Hadoop project. It uses JSON for defining data types and protocols, and serializes data in a compact binary format. Its primary use is in Apache Hadoop, where it can provide both a serialization format for persistent data, and a wire format for communication between Hadoop nodes, and from client programs to the Hadoop services. Avro uses a schema to structure the data that is being encoded. It has two different types of schema languages; one for human editing (Avro IDL) and another which is more machine-readable based on JSON.[3] &amp;#160; Basically, Avro is a language-independent data serialization system developed by the father of Hadoop Doug Cutting. Before I discuss further Avro, allow me to discuss in brief about data serialization and advantages of it. What is Data Serialization and DeSerialization Data Serialization is the process of converting complex objects(array, dicts, lists, class objects, JSON, etc) into byte streams so that they can be stored or transferred to other machines. The reason for data serialization of transferring data among computers who have different architecture, hardware, or operating systems. Once the data is received at the other end, it can be revert back to the original form. The process is called Deserialization. Now you know what is it all about, let&amp;#8217;s dig in and play with some code. Development and Installation There are two libraries that are currently being used in Python applications. One is simply called avro which you can access here. And the other is FastAvro which claims to be faster than the previous one. The working of both is the same. Since we are working on a toy example therefore the previous lib is sufficient for us. So, as always use the typical pip tool to install it: pip install avro Avro Schema Apache Avro format is actually a JSON structure. You can say that Avro format is actually a combination of a JSON data structure and a schema for validation purposes. So before we create our Avro file which has an extension .avro, we will be creating its schema. {"namespace": "me.adnansiddiqi", "type": "record", "name": "User", "fields": [ {"name": "name", "type": "string"}, {"name": "age", "type": ["int", "null"]}, {"name": "gender", "type": ["string", "null"]} ] } OK, so I have come up with a schema above which you can see is a JSON structure. We will be mentioning a namespace first. It is nothing but a string. Usually, it follows the same format which is used by the Java packaging naming convention that is the reverse of your domain name but not necessary. Here I mentioned the reverse of my blog URL. After that you mentioned the type of your schema, here it is of record type. There are other types too like enum,arrays etc. After that, we mention the name of the schema which is User here. The next is field item which could be one or more. It has mandatory fields like name and type and optional fields like doc and alias. The doc field is used to document your field while alias is used to give the field a name other than the one mentioned in name.  So far so good. The schema we created, we will be saving in a file called users.avsc. Now we will be writing the code that will read the schema from the schema file and then will be adding a few records in the Avro file. Later, we will be retrieving the records and display them. Let&amp;#8217;s write the code! import avro.schema from avro.datafile import DataFileReader, DataFileWriter from avro.io import DatumReader, DatumWriter schema = avro.schema.parse(open("user.avsc").read()) writer = DataFileWriter(open("users.avro", "wb"), DatumWriter(), schema) writer.append({"name": "Alyssa", "age": 25,"gender":"female"}) writer.append({"name": "Ahmad", "age": 35,"gender":"male"}) writer.close() reader = DataFileReader(open("users.avro", "rb"), DatumReader()) for user in reader: print(user) print('===================') reader.close() After importing the necessary modules, the very first thing I am doing is reading the schema file. DatumWriter is responsible for data translation into Avro format w.r.t the input schema. DataFileWriter is responsible for writing the data in the file. After inserting a couple of records by we close the writer. The DataFileReader is working similarly, the only difference is that here DatumReader() is responsible for deserialization of data which is stored in users.avro and then make it available for display. When you run the code it will display like the below: python play.py {'name': 'Alyssa', 'age': 25, 'gender': 'female'} =================== {'name': 'Ahmad', 'age': 35, 'gender': 'male'} So far so good? Now let&amp;#8217;s make a bit of change in the schema. I changed age field to dob and when I run it gives the following error: python play.py Traceback (most recent call last): File "play.py", line 8, in &amp;#60;module&amp;#62; writer.append({"name": "Alyssa", "age": 25,"gender":"female"}) File "/Users/AdnanAhmad/Data/anaconda3/lib/python3.7/site-packages/avro/datafile.py", line 303, in append self.datum_writer.write(datum, self.buffer_encoder) File "/Users/AdnanAhmad/Data/anaconda3/lib/python3.7/site-packages/avro/io.py", line 771, in write raise AvroTypeException(self.writer_schema, datum) avro.io.AvroTypeException: The datum {'name': 'Alyssa', 'age': 25, 'gender': 'female'} is not an example of the schema { "type": "record", "name": "User", "namespace": "me.adnansiddiqi", "fields": [ { "type": "string", "name": "name" }, { "type": [ "int", "null" ], "name": "dob" }, { "type": [ "string", "null" ], "name": "gender" } ] } Cool, No? Similarly, if you make changes in the data it will scream and tell you to fix things up. Conclusion I hope you will have learned a bit about Apache Avro and how Python lets you use it to transfer data across devices and systems. I have just touched the surface of it and there is more about it. Avro is also heavily used by Apache Spark and Kafka for data transfer. If you like this post then you should subscribe to my blog for future updates. * indicates required Email Address *&lt;/p&gt;
The post &lt;a href="https://blog.adnansiddiqi.me/getting-started-with-apache-avro-and-python/"&gt;Getting started with Apache Avro and Python &lt;br /&gt; &lt;span style="color: grey; font-size: 25px; font-weight: 300;"&gt;Learn how to create and consume Apache Avro based data for better and efficient transfer.&lt;/span&gt;&lt;/a&gt; first appeared on &lt;a href="https://blog.adnansiddiqi.me"&gt;Adnan's Random bytes&lt;/a&gt;.</description><author>Adnan's Random bytes</author><pubDate>Thu, 06 Aug 2020 12:07:52 GMT</pubDate><guid isPermaLink="true">https://blog.adnansiddiqi.me/getting-started-with-apache-avro-and-python/</guid></item><item><title>Tracing difficult shell scripts</title><link>https://jasoneckert.github.io/myblog/tracing-difficult-shell-scripts/</link><description>&lt;p&gt;&lt;img alt="UNIX/Linux comic" src="comic.png#right" title="UNIX/Linux comic" /&gt;&lt;/p&gt;
&lt;p&gt;Whether you&amp;rsquo;re an IT systems administrator, developer or devop working with Linux/UNIX shell scripts, you&amp;rsquo;re likely going to come across some that are not well documented and difficult to trace (read and understand) as a result.&lt;/p&gt;
&lt;p&gt;While these scripts discourage others from tracing them, you can easily trace even the most difficult shell scripts if you follow good tracing procedures. Moreover, by tracing a difficult shell script, you build your knowledge of specific Linux/UNIX components, as well as scripting in general.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Thu, 06 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/tracing-difficult-shell-scripts/</guid></item><item><title>Chocolate</title><link>https://www.anfractuosity.com/projects/chocolate/</link><description>Unfortunately I must have fermented too long in the first attempt as the beans became mouldy. Attempt 2 Fermented for only 1 day 19 hours Used a dehydrator on full for around 4 hours, this was probably too hot in retrospect, next time put beans in a higher shelf and use a low temperature Roasted [&amp;#8230;]</description><author>Anfractuosity</author><pubDate>Wed, 05 Aug 2020 20:17:18 GMT</pubDate><guid isPermaLink="true">https://www.anfractuosity.com/projects/chocolate/</guid></item><item><title>Random Stats About URLs</title><link>https://rjp.is/blogging/posts/2020/08/random-stats/</link><description>In which we count some URLs and domains.</description><author>infrequent oscillations</author><pubDate>Wed, 05 Aug 2020 16:36:46 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/08/random-stats/</guid></item><item><title>The Sirens of Titan</title><link>https://apurva-shukla.me/bookshelf/the-sirens-of-titan/</link><description>⭐ ⭐ ⭐ ⭐ ⭐ This is my first Vonnegut novel, and my first words are “Wow!“.

The novel through its simplicity explores a whole range of themes,…</description><author>Apurva Shukla's RSS Feed</author><pubDate>Wed, 05 Aug 2020 15:32:45 GMT</pubDate><guid isPermaLink="true">https://apurva-shukla.me/bookshelf/the-sirens-of-titan/</guid></item><item><title>Wednesday roundup for 2020-08-05</title><link>https://rjp.is/blogging/posts/2020/08/random-roundup/</link><description>Various things, links, and excitement.</description><author>infrequent oscillations</author><pubDate>Wed, 05 Aug 2020 12:36:55 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/08/random-roundup/</guid></item><item><title>Keeping your sites fast with regular performance tests</title><link>https://maxrozen.com/keep-site-fast-regular-performance-tests</link><description>You pride yourself on delivering fast websites to your clients, but do the websites stay fast as the months go by?</description><author>Max Rozen</author><pubDate>Tue, 04 Aug 2020 18:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/keep-site-fast-regular-performance-tests</guid></item><item><title>Preventing infinite re-renders when using useEffect and useState</title><link>https://maxrozen.com/learn-useeffect-dependency-array-react-hooks</link><description>React's useEffect hook is an incredibly useful tool for fetching data, but if you're not careful, can cause infinite re-renders.</description><author>Max Rozen</author><pubDate>Tue, 04 Aug 2020 08:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/learn-useeffect-dependency-array-react-hooks</guid></item><item><title>Top Component Libraries for React in Comparison</title><link>https://www.tderflinger.com/en/top-components-libs-comparison</link><description>For every serious web application, you should choose a component library. This article compares Material UI, Fluent UI React, Ant Design, React Spectrum and Semantic UI React.</description><author>Thoughts by Thomas Derflinger</author><pubDate>Tue, 04 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.tderflinger.com/en/top-components-libs-comparison</guid></item><item><title>Make a News Website with NextJS and Prismic</title><link>https://rajeevnaruka.com/blog/make-a-news-website-with-nextjs-and-prismic</link><description>In this tutorial, we will be creating a dynamic news website using NextJS (a ReactJS framework) and Prismic (a headless CMS) for managing all our articles that are published on the news site. For styling our react components we will be using TailwindCSS. We will be dealing with - Setting up NextJS project along with TailwindCSS, Understanding the Prismic CMS and how custom types work, Integrating the app to backend Prismic CMS,Creating pages with dynamic routing in NextJS</description><author>Rajeev Singh Naruka</author><pubDate>Tue, 04 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://rajeevnaruka.com/blog/make-a-news-website-with-nextjs-and-prismic</guid></item><item><title>Thoughts on Goals in Programming Language Design</title><link>https://lambdaland.org/posts/2020-08-04-thoughts-on-pl-design-goals/</link><description>&lt;p&gt;+++&lt;/p&gt;
&lt;p&gt;I’ve been thinking about programming languages a lot recently. A question I asked myself was: why do we work on, refine, and create new programming languages?&lt;/p&gt;
&lt;p&gt;I thought of several reasons, but they seemed to boil down into two broader reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Better abstractions and more automation:&lt;/strong&gt; Some languages automate and ease some tedious tasks like memory management, concurrency, or type annotations. Almost all languages give you some ways of creating abstractions that let you reason with concepts in your problem domain, but different languages do this in different ways.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;More precisely describe what you want:&lt;/strong&gt; Languages like Haskell let you describe the behavior of your program very precisely with an expressive type system. This lets you write &lt;em&gt;correct&lt;/em&gt; programs with a high degree of confidence.&lt;/p&gt;
&lt;p&gt;Other languages give you a different level of control: C lets you manipulate bits at arbitrary memory locations and evaluate them as you please. You can get very good performance from a well-tuned C program.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There’s some overlap between these domains for sure, but these goals often seem to conflict one another: the first objective seems optimal for &lt;em&gt;drafting&lt;/em&gt; programs. The second group is more tuned for long-running projects or programs with specific constraints. Permissive languages like Perl, Ruby, and most Lisps seem designed with the first objective in mind and are very easy to use when exploring an idea. They can be expressive and concise. More demanding languages, like Rust or Haskell, seem optimized for a long-lived project or a program with intensive system resource constraints or performance requirements. Maybe some people can draft in Rust, but I find it more difficult to whip up something in Rust than Perl or Elixir.&lt;/p&gt;
&lt;p&gt;Can we reconcile these two goals? Maybe. I think the further away you get away from the machine—trading some fine-grained control for abstraction—the closer the goals can converge. You can have a language well-suited for discovering an idea, which can then let you evolve your program into a more correct, reliable version.&lt;/p&gt;
&lt;p&gt;In the end, I don’t think there is a perfect language. But some languages are more perfect than others! Hopefully I’ll strike on something interesting in my fumbling about with PL.&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Tue, 04 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-08-04-thoughts-on-pl-design-goals/</guid></item><item><title>An Algorithm for
B2B Products</title><link>https://mebassett.info/algorithm-for-b2b-products</link><description>There's an algorithm for product discovery, at least for business-to-business products. If you combine that algorithm with decent technical execution and a SaaS business model then you have a recipe for a company. And if your market is big enough then you may even be looking at a billion-dollar startup.</description><author>Essays by Matthew Eric Bassett</author><pubDate>Mon, 03 Aug 2020 19:20:00 GMT</pubDate><guid isPermaLink="true">https://mebassett.info/algorithm-for-b2b-products</guid></item><item><title>Memory safety in Rust - part 2</title><link>https://hashrust.com/blog/memory-safety-in-rust-part-2/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In &lt;a href="https://hashrust.com/blog/memory-safey-in-rust-part-1/"&gt;part 1&lt;/a&gt; of &lt;em&gt;Memory safety in rust&lt;/em&gt; I discussed the concept of memory safety and various techniques used by different languages to achieve it. Almost all languages fall on a spectrum with memory safety on one side and programmer control on the other. Rust is unique in that it doesn't make this trade-off — the programmer gets both memory safety and control.&lt;/p&gt;
&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
Not all programs that can be written in C++ can be written in safe Rust. As I will show, indiscriminate aliasing is not possible in Rust and this is a good thing. The default mode in rust is memory safety, but if the programmer really wants to have C++ style unfettered control, they can use &lt;a href="https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html"&gt;unsafe code&lt;/a&gt;.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;h2 id="aliasing-mutation-and-safety"&gt;Aliasing, mutation and safety&lt;/h2&gt;
&lt;p&gt;To safely free an object, there must be no references to it, otherwise you'll end up with a dangling pointer. Similarly, if a thread wants to send an object to another thread, there can't be a reference to it on the sending thread. There are two elements in play here: aliasing and mutation. If the object was not being destroyed or sent across a thread, there is nothing wrong with having references to it. It is only when both of them are combined that you get in trouble.&lt;/p&gt;
&lt;p&gt;In light of this observation, Rust's solution to memory safety is to simply disallow both aliasing and mutation at the same time, and Rust achieves this through ownership and borrowing.&lt;/p&gt;
&lt;h2 id="ownership"&gt;Ownership&lt;/h2&gt;
&lt;p&gt;When you create a new object in Rust, the assigned variable becomes the owner of the object. For example in the following Rust code, variable &lt;code&gt;v&lt;/code&gt; owns the &lt;code&gt;Vec&lt;/code&gt; instance:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and when &lt;code&gt;v&lt;/code&gt; goes out of scope, the &lt;code&gt;Vec&lt;/code&gt; is &lt;a href="https://doc.rust-lang.org/std/ops/trait.Drop.html" rel="external"&gt;dropped&lt;/a&gt;. There can only be a single owner of an object at a time, which ensures that only the owner drops it. This avoids double-free bugs. If &lt;code&gt;v&lt;/code&gt; is assigned to another variable, the ownership is transferred:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//v1 is the new owner&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since &lt;code&gt;v1&lt;/code&gt; is now the owner, access is no longer allowed through &lt;code&gt;v&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//error: Use of moved value&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;
    &lt;span class="note-background"&gt;Note&lt;/span&gt;
    &lt;span class="note"&gt;Note&lt;/span&gt;
    &lt;aside&gt;
Although C++ too has move semantics, it doesn't prevent you from introducing a &lt;a href="https://web.mst.edu/~nmjxv3/articles/move-gotchas.html"&gt;use-after-move bug&lt;/a&gt;.
    &lt;/aside&gt;
&lt;/div&gt;
&lt;p&gt;The owner can of course mutate the object:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//mut is needed to mutate the object&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But since there is no aliasing, we are good.&lt;/p&gt;
&lt;p&gt;If all a programmer could do in Rust was own values and transfer them around, it would be quite a restrictive programming environment. Fortunately, Rust allows borrowing from the owner.&lt;/p&gt;
&lt;h2 id="borrowing"&gt;Borrowing&lt;/h2&gt;
&lt;p&gt;Borrowing introduces aliasing. A reference can be borrowed from the owner:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//v1 has borrowed from v&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//fine&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//also fine&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unlike an owner, there can be multiple borrowed references at the same time:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//v1 has borrowed from v&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//v2 has also borrowed from v&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//allowed&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//also allowed&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//also allowed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But a borrower cannot access the resource after the owner has destroyed it because otherwise it will lead to a use-after-free bug:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;   let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;   v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;//v is dropped here&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//error:borrowed value does not live long enough&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So even though aliasing is possible, Rust ensures that no references outlive the object being referenced, again avoiding aliasing and mutation at the same time.&lt;/p&gt;
&lt;p&gt;Until now all the borrows were immutable. It is possible to have mutable references, but as I will show next, Rust is smart enough to disallow aliasing when mutation is introduced.&lt;/p&gt;
&lt;h2 id="mutable-borrowing"&gt;Mutable borrowing&lt;/h2&gt;
&lt;p&gt;Although there can be multiple shared references, there can only be one mutable reference at one time:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;:&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//first mutable reference&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-storage"&gt;mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//second mutable reference&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span class="z-comment"&gt;//error:cannot borrow `v` as mutable more than once at a time&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As soon as mutation is allowed through a mutable reference, Rust takes away aliasing by disallowing other references (shared or mutable).&lt;/p&gt;
&lt;p&gt;These borrowing rules prevent dangling pointers. If Rust had allowed a mutable reference and an immutable reference at the same time, the memory could become invalid through the mutable reference while the immutable reference could still be pointing to that invalid memory. For example, in the code below, &lt;code&gt;v1&lt;/code&gt; could access invalid memory if such code was allowed:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let mut&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; vec!&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 3&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;0&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;span class="z-comment"&gt;//an immutable reference to Vec's first element&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;4&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span class="z-comment"&gt;//this can invalidate Vec's internal buffer&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v2&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = *&lt;/span&gt;&lt;span class="z-variable"&gt;v1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//this could access invalid memory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In comparison, similar code would be allowed in C++.&lt;/p&gt;
&lt;h2 id="lifetimes"&gt;Lifetimes&lt;/h2&gt;
&lt;p&gt;I have discussed that Rust disallows both aliasing and mutation at the same time to prevent memory safety issues but hand-waved my way through these sections about &lt;em&gt;how&lt;/em&gt; Rust achieves this at compile time. Rust does this by keeping track of lifetimes of variables. Intuitively, the lifetime of a variable is tied to its scope:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;let&lt;/span&gt;&lt;span class="z-variable"&gt; v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;: &amp;amp;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;Vec&lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt;i32&lt;/span&gt;&lt;span&gt;&amp;gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//-------------------------+&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;{&lt;/span&gt;&lt;span class="z-comment"&gt;//                                          |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;   let&lt;/span&gt;&lt;span class="z-variable"&gt; v&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-entity z-name z-type"&gt; Vec&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;::&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;new&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//-----+               |v1's lifetime&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;   v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; = &amp;amp;&lt;/span&gt;&lt;span class="z-variable"&gt;v&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span class="z-comment"&gt;//                | v's lifetime  |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;}&lt;/span&gt;&lt;span class="z-comment"&gt;//&amp;lt;-------------------------+               |&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;v1&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt;.&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;len&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span class="z-comment"&gt;//&amp;lt;---------------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the compiler compares the lifetimes of various variables to figure out if something fishy is going on. For example, in the code above, &lt;code&gt;v1&lt;/code&gt; outlives the owner &lt;code&gt;v&lt;/code&gt; which is not allowed. The lifetimes in above example are called lexical lifetimes because they are inferred from the variable scopes. In reality, Rust has a more sophisticated implementation of lifetimes called &lt;a href="https://smallcultfollowing.com/babysteps/blog/2016/04/27/non-lexical-lifetimes-introduction/" rel="external"&gt;non-lexical lifetimes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lifetimes is a big topic and I cannot cover everything in this post. You can learn more about lifetimes at the &lt;a href="https://doc.rust-lang.org/nomicon/lifetimes.html" rel="external"&gt;Rustonomicon&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, I discussed the concepts of ownership and borrowing and how they help in achieving memory safety in Rust. Many memory safety issues boil down to the fact that languages like C++ allow both mutation and aliasing at the same time. Rust's ability to detect these memory safety problems at compile time makes it a strong contender for a systems programming language.&lt;/p&gt;</description><author/><pubDate>Mon, 03 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hashrust.com/blog/memory-safety-in-rust-part-2/</guid></item><item><title>Books and Links: July</title><link>http://evantravers.com/articles/2020/08/02/books-and-links-july/</link><description>&lt;p&gt;As this month wound to a close, my wife and have been awaiting our second child, so there wasn't too much in the way of reading on either side for me.&lt;/p&gt;
&lt;p&gt;I had bought a synology, so I spent a lot of time making sure our family data is backed up properly.&lt;/p&gt;
&lt;p&gt;I've been listening to a bunch of podcasts to catch up... here's some of the ones I've been enjoying.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#podcasts" id="podcasts"&gt;&lt;/a&gt;Podcasts&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-intentional-family" id="the-intentional-family"&gt;&lt;/a&gt;The Intentional Family&lt;/h3&gt;
&lt;p&gt;Sarah and I have been slowly listening to these together... I think it's a good touch point to hear another couple with similar dynamics share some of their strengths and struggles.&lt;/p&gt;
&lt;p&gt;I really got a lot out of &lt;a href="https://intentionalfamily.fm/episodes/6"&gt;#6&lt;/a&gt;, which showed me that my overly complicated and frustrating family meeting plan was all about &amp;quot;stuff done&amp;quot; and not enough about loving Sarah.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://intentionalfamily.fm/"&gt;intentionalfamily.fm&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-portal" id="the-portal"&gt;&lt;/a&gt;The Portal&lt;/h3&gt;
&lt;p&gt;I do &lt;em&gt;not&lt;/em&gt; agree with everything discussed on this podcast, but I keep listening because that even when adversarial the host and his guests are genuinely trying to persuade the other... rather than grandstanding to their respective and polarized audiences. It &lt;em&gt;is&lt;/em&gt; refreshing to hear a long conversation about important things between two passionate but respectful people.&lt;/p&gt;
&lt;p&gt;Notable episodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/32-j-d-vance-american-dreams-and-nightmares/id1469999563?i=1000473090465"&gt;JD Vance&lt;/a&gt; discussing America falling out of love with the traditional family&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/26-james-okeefe-what-is-isnt-journalism-in-21st-century/id1469999563?i=1000468918064"&gt;James O'Keefe&lt;/a&gt; and Eric getting fighting mad while staying civil and discussing ethics in journalism.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/19-bret-weinstein-the-prediction-and-the-disc/id1469999563?i=1000462975502"&gt;Bret Weinstein&lt;/a&gt; sharing a tale of frustrated research and an assumption that imperils a slew of modern medical research.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://podcasts.apple.com/us/podcast/13-garry-kasparov-avoiding-zugzwang-in-ai-and-politics/id1469999563?i=1000457968500"&gt;Garry Kasparov&lt;/a&gt; discussing chess, AI, and the immoral russian state that is willing to drown the truth in memes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://podcasts.apple.com/us/podcast/the-portal/id1469999563"&gt;The Portal - Apple Podcasts&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#cortex" id="cortex"&gt;&lt;/a&gt;Cortex&lt;/h3&gt;
&lt;p&gt;Cortex has been a big influence on some of the decisions I've made personally for my own productivity, and is a good way for me to stay distantly interested in technology without drinking from the firehose.&lt;/p&gt;
&lt;p&gt;If nothing else, it's made me more respectful of the different ways that other people work, instead of being as opinionated about &amp;quot;best practices&amp;quot; as I have been in the past.&lt;/p&gt;
&lt;p&gt;Notable episodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.relay.fm/cortex/95"&gt;Discussing yearly themes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.relay.fm/cortex/101"&gt;Productivity 101&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.relay.fm/cortex/"&gt;Cortex - Relay.fm&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#focused" id="focused"&gt;&lt;/a&gt;Focused&lt;/h3&gt;
&lt;p&gt;Another super influential one for me. Really grateful that I found this podcast when I did. It's really helped me return my attention to what's important, rather than just trying to do everything faster.&lt;/p&gt;
&lt;p&gt;Notable episodes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.relay.fm/focused/96"&gt;Working from Home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.relay.fm/focused/79"&gt;Reclaiming Margin with Shawn Blanc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.relay.fm/focused"&gt;Focused - Relay.fm&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#nested-folders" id="nested-folders"&gt;&lt;/a&gt;Nested Folders&lt;/h3&gt;
&lt;p&gt;Another lovely one that has just been a quick refresher. I would now point to this one - (especially the episodes that are now going through the &lt;a href="https://nestedfolderspodcast.com/podcast/episode-28-gtd-workflow-part-one-capture/"&gt;basics of the GTD system&lt;/a&gt;!) - as a great starting point for someone who is getting tired of being overwhelmed and unorganized and wants a place to start.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://nestedfolderspodcast.com/"&gt;https://nestedfolderspodcast.com/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#strong-songs" id="strong-songs"&gt;&lt;/a&gt;Strong Songs&lt;/h3&gt;
&lt;p&gt;I love this one... while my music theory is rusty, the host's love for music is infectious. I love re-discovering a song, learning all about the story, and finding new depths as Kirk dissects and reassembles the song from scratch.&lt;/p&gt;
&lt;p&gt;I think one of the strongest episodes is for &lt;a href="https://strongsongspodcast.com/paranoid-android-by-radiohead"&gt;Radiohead's Paranoid Android&lt;/a&gt;, which is a song I love, but he shows the careful orchestration and beauty behind the blaring and furious rock guitars.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.strongsongspodcast.com/"&gt;Strong Songs Podcast&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;p&gt;I read Christian Living in the Home by Jay Adams. It was a good and quick refresher, and very convicting for a family man about to welcome a new little one.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#look-whos-talking--real-life" id="look-whos-talking--real-life"&gt;&lt;/a&gt;Look Who’s Talking — Real Life&lt;/h3&gt;
&lt;p&gt;This is a chilling warning about the power and threat of choosing tone for UX microcopy. Very good read.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To UX writing teams, “clarity” often means making what the company wants you to do the clear choice for you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://reallifemag.com/look-whos-talking/"&gt;Look Who’s Talking — Real Life&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#how-to-get-the-best-design-feedback-from-your-team--matthew-ström-designer--developer" id="how-to-get-the-best-design-feedback-from-your-team--matthew-ström-designer--developer"&gt;&lt;/a&gt;How to get the best design feedback from your team || Matthew Ström: designer &amp;amp; developer&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The feedback process is a design tool, like Sketch or Micron pens. The best part about the feedback process is that it is, by nature, a team activity. Anyone can take part, and everyone benefits.&lt;/p&gt;
&lt;p&gt;Like any tool, the feedback process gets better with practice. At Planetary, we’ve been running short feedback cycles for 6 months or so, and we’re still working to improve (this article is part of that work).&lt;/p&gt;
&lt;p&gt;Overall, shifting focus away from the language of feedback and towards the process of feedback has allowed us to be more inclusive, work faster, and design better.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://matthewstrom.com/writing/feedback-revisited/#fnref1"&gt;How to get the best design feedback from your team || Matthew Ström: designer &amp;amp; developer&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#bonus-weird-links-from-wikipedia" id="bonus-weird-links-from-wikipedia"&gt;&lt;/a&gt;Bonus: Weird links from Wikipedia&lt;/h3&gt;
&lt;p&gt;I had a folder of weird Wikipedia articles that I was saving… I pruned them and added some commentary. Enjoy!&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#wikipediavital-articles---wikipedia" id="wikipediavital-articles---wikipedia"&gt;&lt;/a&gt;Wikipedia:Vital articles - Wikipedia&lt;/h3&gt;
&lt;p&gt;I first encountered this as a &amp;quot;curriculum&amp;quot; and starting place for expanding on your education using a curious mind. Very interesting.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Vital articles are lists of subjects for which the English Wikipedia should have corresponding featured-class articles. They serve as centralized watchlists to track the status of Wikipedia's most important articles. The very most important articles are in Level 1.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Wikipedia:Vital_articles"&gt;Wikipedia:Vital articles - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#list-of-lists-of-lists---wikipedia" id="list-of-lists-of-lists---wikipedia"&gt;&lt;/a&gt;List of lists of lists - Wikipedia&lt;/h3&gt;
&lt;p&gt;When I first saved this link, it was the List of Lists. Wise information architect recognized that there were lists of lists that contained lists, so now there is this page.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a list of lists of lists, a list of list articles that contain other list articles on the English Wikipedia. In other words, each of the articles linked here is an index to multiple lists on a topic. Some of the linked articles contain lists of lists, too.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/List_of_lists_of_lists"&gt;List of lists of lists - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#list-of-crayola-crayon-colors---wikipedia" id="list-of-crayola-crayon-colors---wikipedia"&gt;&lt;/a&gt;List of Crayola crayon colors - Wikipedia&lt;/h3&gt;
&lt;p&gt;Wikipedia's greatest secret is the glory of the &amp;quot;Talk&amp;quot; pages… I have never seen such hateful, ardent, and passionate argumentation as to what is the precise correct color codes and name on &lt;em&gt;this&lt;/em&gt; page.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since the introduction of Crayola drawing crayons by Binney &amp;amp; Smith in 1903, more than two hundred distinctive colors have been produced in a wide variety of assortments. The table below represents all of the colors found in regular Crayola assortments from 1903 to the present.[a] Since the introduction of fluorescent crayons in the 1970s, the standard colors have been complemented by a number of specialty crayon assortments, represented in subsequent tables.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/List_of_Crayola_crayon_colors"&gt;List of Crayola crayon colors - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#wikipedialist-of-hoaxes-on-wikipedia---wikipedia" id="wikipedialist-of-hoaxes-on-wikipedia---wikipedia"&gt;&lt;/a&gt;Wikipedia:List of hoaxes on Wikipedia - Wikipedia&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a list of known historical hoaxes created on Wikipedia. It is not for known hoaxes which are notable in their own right, such as Piltdown Man. Its purpose is to document hoaxes on Wikipedia, in order to improve our understanding of them and our ability to detect them. For the purpose of this list, a hoax is defined as a clear and deliberate attempt to deceptively present false information as fact. Libel, vandalism, and honest factual errors are not considered hoaxes. A hoax is considered notable enough for inclusion in this list if it evaded detection for more than one month or was discussed by reliable sources in the media. This list is incomplete, as many hoaxes remain undiscovered.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While this is a fascinating read, this is also a good reason to &lt;strong&gt;not trust anything you read on wikipedia 100%&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Wikipedia:List_of_hoaxes_on_Wikipedia"&gt;Wikipedia:List of hoaxes on Wikipedia - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#wikipediaunusual-articles---wikipedia" id="wikipediaunusual-articles---wikipedia"&gt;&lt;/a&gt;Wikipedia:Unusual articles - Wikipedia&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Of the over six million articles in the English Wikipedia there are some articles that Wikipedians have identified as being somewhat unusual. These articles are verifiable, valuable contributions to the encyclopedia, but are a bit odd, whimsical, or something one would not expect to find in Encyclopædia Britannica.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I love both the list of qualities required to be on this page, and the pages that this links to.&lt;/p&gt;
&lt;p&gt;As with anything on the internet, there are some links to less than moral things on this page.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Wikipedia:Unusual_articles"&gt;Wikipedia:Unusual articles - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#list-of-inventors-killed-by-their-own-inventions---wikipedia" id="list-of-inventors-killed-by-their-own-inventions---wikipedia"&gt;&lt;/a&gt;List of inventors killed by their own inventions - Wikipedia&lt;/h3&gt;
&lt;p&gt;Closely linked to the Darwin Awards… but distinctly sad.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a list of inventors whose deaths were in some manner caused by or related to a product, process, procedure, or other innovation that they invented or designed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/List_of_inventors_killed_by_their_own_inventions"&gt;List of inventors killed by their own inventions - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#mid-atlantic-accent---wikipedia" id="mid-atlantic-accent---wikipedia"&gt;&lt;/a&gt;Mid-Atlantic accent - Wikipedia&lt;/h3&gt;
&lt;p&gt;I forgot where I first learned of this phenomena: a completely fictional accent that became relatively well-known.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Mid-Atlantic accent, or Transatlantic accent,[1][2][3] is a purposefully cultivated accent of English that blends together the most prestigious features of American and British English (specifically Received Pronunciation for the latter). Adopted in the early 20th century mostly by American aristocrats and Hollywood actors, it is not a native or regional accent; instead, according to voice and drama professor Dudley Knight, it is an affected set of speech patterns &amp;quot;whose chief quality was that no Americans actually spoke it unless educated to do so&amp;quot;.[4]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Mid-Atlantic_accent"&gt;Mid-Atlantic accent - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#talkquantum-suicide-and-immortality-difference-between-revisions---wikipedia" id="talkquantum-suicide-and-immortality-difference-between-revisions---wikipedia"&gt;&lt;/a&gt;Talk:Quantum suicide and immortality: Difference between revisions - Wikipedia&lt;/h3&gt;
&lt;p&gt;This one is just weird, and largely persuaded me that taking ethics/morality into the quantum really befuddles the linear mind.&lt;/p&gt;
&lt;p&gt;Thinking themselves wise…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Just imagine all of the possible universes in your past in which you made a different decision and would still be alive and well today (although in different universes). The &amp;quot;you&amp;quot; that exists now is just one of infinitely possible copies of &amp;quot;you&amp;quot;. The &amp;quot;me&amp;quot; that is typing right now shares exactly the same history and continuity with the &amp;quot;me&amp;quot; that isn't typing this. At the same time, if it were ever possible for both copies to confront one another, I would not be able to get inside the head of my alternate self any more than I'd be able to get inside the head of any other being sharing a seperate existance in my reality (though my &amp;quot;double&amp;quot; would be a little more predictable).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/w/index.php?title=Talk:Quantum_suicide_and_immortality&amp;amp;curid=48693&amp;amp;diff=509809817&amp;amp;oldid=492007825"&gt;Talk:Quantum suicide and immortality: Difference between revisions - Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#great-soviet-encyclopedia---wikipedia" id="great-soviet-encyclopedia---wikipedia"&gt;&lt;/a&gt;Great Soviet Encyclopedia - Wikipedia&lt;/h3&gt;
&lt;p&gt;I first learned of this while learning about all the heroes of the defense of Leningrad who were later struck from this record. While a whimsical (and dark!) chapter of history, it's also a stark reminder of being careful who controls your source of truth. * cough * wikipedia moderators * cough *&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Great Soviet Encyclopedia (GSE; Russian: Большая советская энциклопедия, БСЭ, Bolshaya sovetskaya entsiklopediya) is one of the largest Russian-language encyclopedias,[1] published by the Soviet Union from 1926 to 1990. After 2002, the encyclopedia's data was partially included into the later Bolshaya Rossiyskaya entsiklopediya (or Great Russian Encyclopedia) in an updated and revised form. The GSE claimed to be &amp;quot;the first Marxist–Leninist general-purpose encyclopedia&amp;quot;.[2]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Great_Soviet_Encyclopedia"&gt;Great Soviet Encyclopedia - Wikipedia&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Sun, 02 Aug 2020 23:36:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/08/02/books-and-links-july/</guid></item><item><title>DIY chicken coop from old pallets</title><link>https://jeroenpelgrims.com/chicken-coop/</link><description>&lt;p&gt;&lt;img alt="Photo of the finished coop" src="https://jeroenpelgrims.com/chicken-coop/./images/20200802_122056.jpg" /&gt;&lt;/p&gt;
&lt;h2 id="index"&gt;Index&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#index" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://jeroenpelgrims.com/chicken-coop/#why-build-a-chicken-coop"&gt;Why build a chicken coop?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeroenpelgrims.com/chicken-coop/#requirements-of-the-coop"&gt;Requirements of the coop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeroenpelgrims.com/chicken-coop/#planning-before-building"&gt;Planning before building&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeroenpelgrims.com/chicken-coop/#photos-of-the-building-process"&gt;Photos of the building process&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeroenpelgrims.com/chicken-coop/#price"&gt;Price&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="why-build-a-chicken-coop"&gt;Why build a chicken coop?&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#why-build-a-chicken-coop" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I recently—well, 6 months ago—bought an apartment with a large, by Antwerp standards, garden.
There's a few reasons for this, mainly that I love gardening but also that I want to keep a few pets.
Eventually a dog, but for now I thought chickens could be fun. Trash disposal, egg and fertilizer factory all combined into one animal!&lt;/p&gt;
&lt;p&gt;But I also try to be frugal and don't want to spend a few hundred euro's on a small prefab coop which most likely doesn't even meets the most often suggested minimum size for chicken coops.
So why not build it with disassembled EUR pallets? This will save me some of the cost of the wood that I need.&lt;/p&gt;
&lt;h2 id="requirements-of-the-coop"&gt;Requirements of the coop&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#requirements-of-the-coop" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So what are these minimum sizes for coops and what other requirements do I have?&lt;/p&gt;
&lt;h3 id="minimum-amount-of-chickens"&gt;Minimum amount of chickens&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#minimum-amount-of-chickens" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chickens are social creatures, so you can't just keep one.&lt;br /&gt;
The most often named number of chickens you should keep minimum is 3, although 2 might be doable as well. [&lt;a href="https://www.reddit.com/r/BackYardChickens/comments/2r7p7s/what_is_the_minimum_number_i_could_have_for_a/"&gt;1&lt;/a&gt;] [&lt;a href="https://www.dobies.co.uk/Keeping-Chickens-Info.htm"&gt;2&lt;/a&gt;]
Seeing I'm just a guy by myself I think I might start with 2 and if needed add a third.&lt;/p&gt;
&lt;h3 id="space-inside-the-coop"&gt;Space inside the coop&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#space-inside-the-coop" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each chicken should have about 0,25 m&lt;sup&gt;2&lt;/sup&gt; of space within the coop [&lt;a href="https://avevewinkels.be/Advies/Detail/dier/kip/mijn-nieuwe-kip/met-kippen-beginnen/755d6"&gt;1&lt;/a&gt;] [&lt;a href="https://www.thespruce.com/building-a-chicken-coop-3016589"&gt;2&lt;/a&gt;]
With this in mind I'd need at least 0,5 m&lt;sup&gt;2&lt;/sup&gt; for 2 chickens or 0,75 m&lt;sup&gt;2&lt;/sup&gt; for 3.
The EUR pallets have standard sizes with planks of 1,2m and 0,8m. So if I make a rectangle of these planks this gives me &lt;code&gt;1,2 * 0,8 = 0,96&lt;/code&gt; m&lt;sup&gt;2&lt;/sup&gt;.
With the space of the nesting boxes added to it this should add upp to about 1 m&lt;sup&gt;2&lt;/sup&gt;.
So just about enough size for 4 chickens to be comfortable if I would want to get some more later.&lt;/p&gt;
&lt;h3 id="easy-cleaning"&gt;Easy cleaning&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#easy-cleaning" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The coop should be easily cleanable, this means it should have a removable floor so we can easily take it out and scrub it off.
And a removable side/wall would also be useful for easy access in case something needs to be done inside the coop.&lt;/p&gt;
&lt;h3 id="easy-egg-gathering"&gt;Easy egg gathering&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#easy-egg-gathering" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The chickens need a place to lay their eggs. This happens in nesting boxes.
A smaller mini house inside or connected to the main coop.&lt;/p&gt;
&lt;p&gt;The nesting boxes should also be easily accessible so the eggs can be gathered quickly.&lt;br /&gt;
I shouldn't have to crawl through the sie door just to get to the eggs.&lt;br /&gt;
So a lid on the top/side of the boxes should work perfectly.&lt;/p&gt;
&lt;h3 id="high-and-dry"&gt;High and dry&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#high-and-dry" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The coop should be a bit above ground so in case it rains the coop and the chickens will still be dry.
This will also help protect the coop from mold and rotting because there's more airflow on the bottom.&lt;/p&gt;
&lt;h2 id="planning-before-building"&gt;Planning before building&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#planning-before-building" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So with these sizes in mind I started drawing in SketchUp to get an idea of how the coop would look.
This would also give me an estimate of how many pallets I would need and the other materials like the poles on which it will stand and the inner skeleton of the coop.&lt;/p&gt;
&lt;p&gt;(Click on the image below to see the 3D model)&lt;/p&gt;

&lt;p&gt;I didn't draw out every detail, for example there are no hinges and the nesting box' lid is just some planks which aren't connected in any way.
Some things I left up to improvise while building the thing.&lt;/p&gt;
&lt;h2 id="photos-of-the-building-process"&gt;Photos of the building process&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#photos-of-the-building-process" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h2&gt;


&lt;ul class="gallery"&gt;
  &lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200704_155829.jpg"&gt;
      &lt;img alt="Gallery image 2" src="https://jeroenpelgrims.com/processed_images/20200704_155829.7c73ebfbcb0b7ad0.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200704_162138.jpg"&gt;
      &lt;img alt="Gallery image 3" src="https://jeroenpelgrims.com/processed_images/20200704_162138.6510b844fbb73ea5.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200713_152334.jpg"&gt;
      &lt;img alt="Gallery image 4" src="https://jeroenpelgrims.com/processed_images/20200713_152334.a6b3fc0ece0e7678.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200713_192804.jpg"&gt;
      &lt;img alt="Gallery image 5" src="https://jeroenpelgrims.com/processed_images/20200713_192804.e31e1acbb4d214be.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200713_195343.jpg"&gt;
      &lt;img alt="Gallery image 6" src="https://jeroenpelgrims.com/processed_images/20200713_195343.8e367283f3fe051c.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_140153.jpg"&gt;
      &lt;img alt="Gallery image 7" src="https://jeroenpelgrims.com/processed_images/20200720_140153.b2e6a1ab8f1e054c.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_145112.jpg"&gt;
      &lt;img alt="Gallery image 8" src="https://jeroenpelgrims.com/processed_images/20200720_145112.5907ee4b7950135d.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_160820.jpg"&gt;
      &lt;img alt="Gallery image 9" src="https://jeroenpelgrims.com/processed_images/20200720_160820.f63380e326e8eabc.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_173118.jpg"&gt;
      &lt;img alt="Gallery image 10" src="https://jeroenpelgrims.com/processed_images/20200720_173118.6360e86f7c7d1418.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_173128.jpg"&gt;
      &lt;img alt="Gallery image 11" src="https://jeroenpelgrims.com/processed_images/20200720_173128.72b037d59cdbe11c.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_175116.jpg"&gt;
      &lt;img alt="Gallery image 12" src="https://jeroenpelgrims.com/processed_images/20200720_175116.27db73f3b772115b.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_183025.jpg"&gt;
      &lt;img alt="Gallery image 13" src="https://jeroenpelgrims.com/processed_images/20200720_183025.6b90aedfc401a3ac.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_183031.jpg"&gt;
      &lt;img alt="Gallery image 14" src="https://jeroenpelgrims.com/processed_images/20200720_183031.b18cbeaf50333c31.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_200237.jpg"&gt;
      &lt;img alt="Gallery image 15" src="https://jeroenpelgrims.com/processed_images/20200720_200237.e86a3a20186117a0.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_200241.jpg"&gt;
      &lt;img alt="Gallery image 16" src="https://jeroenpelgrims.com/processed_images/20200720_200241.5c7146ed9cabb5f4.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200720_201917.jpg"&gt;
      &lt;img alt="Gallery image 17" src="https://jeroenpelgrims.com/processed_images/20200720_201917.5fb9145f0b475e6e.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200721_140719.jpg"&gt;
      &lt;img alt="Gallery image 18" src="https://jeroenpelgrims.com/processed_images/20200721_140719.190bef12dbdbe577.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200721_150409.jpg"&gt;
      &lt;img alt="Gallery image 19" src="https://jeroenpelgrims.com/processed_images/20200721_150409.acecd70b278c514e.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200721_150417.jpg"&gt;
      &lt;img alt="Gallery image 20" src="https://jeroenpelgrims.com/processed_images/20200721_150417.7b505e4fd52152a8.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200721_153059.jpg"&gt;
      &lt;img alt="Gallery image 21" src="https://jeroenpelgrims.com/processed_images/20200721_153059.6fe816cd869bbacc.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200721_153540.jpg"&gt;
      &lt;img alt="Gallery image 22" src="https://jeroenpelgrims.com/processed_images/20200721_153540.b515d62aa1c4688c.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200722_170120.jpg"&gt;
      &lt;img alt="Gallery image 23" src="https://jeroenpelgrims.com/processed_images/20200722_170120.68abf763cd24a3c3.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200722_170142.jpg"&gt;
      &lt;img alt="Gallery image 24" src="https://jeroenpelgrims.com/processed_images/20200722_170142.e35f4c88f52fa317.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200722_171906.jpg"&gt;
      &lt;img alt="Gallery image 25" src="https://jeroenpelgrims.com/processed_images/20200722_171906.582eaa1816cae13e.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200722_174036.jpg"&gt;
      &lt;img alt="Gallery image 26" src="https://jeroenpelgrims.com/processed_images/20200722_174036.40d478b3980c9d3a.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200722_174419.jpg"&gt;
      &lt;img alt="Gallery image 27" src="https://jeroenpelgrims.com/processed_images/20200722_174419.a8f78feba5b42c90.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200725_155600.jpg"&gt;
      &lt;img alt="Gallery image 28" src="https://jeroenpelgrims.com/processed_images/20200725_155600.ade29a17c218f66f.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200725_155609.jpg"&gt;
      &lt;img alt="Gallery image 29" src="https://jeroenpelgrims.com/processed_images/20200725_155609.9c6009189e8afdd6.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200725_155624.jpg"&gt;
      &lt;img alt="Gallery image 30" src="https://jeroenpelgrims.com/processed_images/20200725_155624.b6494aeab8d4c346.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200726_131402.jpg"&gt;
      &lt;img alt="Gallery image 31" src="https://jeroenpelgrims.com/processed_images/20200726_131402.913c92dbb4e83807.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;&lt;li&gt;
    &lt;a href="https://jeroenpelgrims.com/chicken-coop/images/20200802_122056.jpg"&gt;
      &lt;img alt="Gallery image 32" src="https://jeroenpelgrims.com/processed_images/20200802_122056.a6b215784c35d4b8.jpg" /&gt;
    &lt;/a&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;video controls="controls" src="https://jeroenpelgrims.com/chicken-coop/20200720_203141.mp4" width="100%"&gt;&lt;/video&gt;&lt;/p&gt;
&lt;h2 id="price"&gt;Price&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#price" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All in all this probably cost me around 100€.
This includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The wooden poles&lt;/li&gt;
&lt;li&gt;The ground drill to make holes for the poles.&lt;/li&gt;
&lt;li&gt;The beams for the internal structure&lt;/li&gt;
&lt;li&gt;The concrete plywood for the floor&lt;/li&gt;
&lt;li&gt;The paintbrush&lt;/li&gt;
&lt;li&gt;The screws&lt;/li&gt;
&lt;li&gt;The metal connecting corners&lt;/li&gt;
&lt;li&gt;3 liters of sunflower oil to make the thing a bit water resistant.&lt;/li&gt;
&lt;li&gt;The hinges for the gate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But excludes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the bigger tools which I already had like a power drill and a multi tool.&lt;/li&gt;
&lt;li&gt;Waterproof foil for the roof. I got some leftovers from my sis.&lt;/li&gt;
&lt;li&gt;The chickens&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="further"&gt;Further&lt;a class="zola-anchor" href="https://jeroenpelgrims.com/chicken-coop/#further" title="Click here to get a direct link to this section in your browser's address bar."&gt;§&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A few more things need to be done before it's finished.&lt;br /&gt;
I need to close the gaps in the brood box, apparently it should be as dark as possible in there.
I need to install a thick branch which the chickens can use as a roost.&lt;/p&gt;
&lt;p&gt;And I need to finalize the roof. This means adding a waterproof foil on the roof and then adding soil &amp;amp; grass. My goal is to make a "Torvtak":
&lt;img alt="Torvtak" src="https://scontent-bru2-1.xx.fbcdn.net/v/t1.0-9/35925599_612764029102375_7116499439237201920_n.jpg?_nc_cat=103&amp;amp;_nc_sid=8024bb&amp;amp;_nc_ohc=OK_Ky9VGgogAX-O6bjx&amp;amp;_nc_ht=scontent-bru2-1.xx&amp;amp;oh=9866c739e954c0a22b92ede33754f2e8&amp;amp;oe=5F4EB094" /&gt;&lt;/p&gt;</description><author>Jeroen Pelgrims</author><pubDate>Sun, 02 Aug 2020 13:03:00 GMT</pubDate><guid isPermaLink="true">https://jeroenpelgrims.com/chicken-coop/</guid></item><item><title>This page looks better in the app</title><link>https://ounapuu.ee/posts/2020/08/02/this-page-looks-better-in-the-app/</link><description>I'm not sure it does.</description><author>./techtipsy</author><pubDate>Sun, 02 Aug 2020 09:33:41 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/08/02/this-page-looks-better-in-the-app/</guid></item><item><title>Crime and Punishment</title><link>https://arunmani.in/library/crime-and-punishment/</link><description>I went full upside down reading this book. Perspective changing story.</description><author>Arun Mani</author><pubDate>Sun, 02 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://arunmani.in/library/crime-and-punishment/</guid></item><item><title>SwiftUI macOS desk clock</title><link>https://xenodium.com/swiftui-desk-clock</link><description>&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/swiftui-desk-clock/everclock.gif" /&gt;&lt;/p&gt;
&lt;p&gt;For time display, I've gone back and forth between an always-displayed macOS's menu bar to an auto-hide menu bar, and letting Emacs display the time. Neither felt great nor settled.&lt;/p&gt;
&lt;p&gt;With some tweaks, Paul Hudson's &lt;a href="https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-a-timer-with-swiftui"&gt;How to use a timer with SwiftUI&lt;/a&gt;, led me to build a simple desk clock. Ok, let's not get fancy. It's really just an always-on-top floating window, showing a swiftUI label, but hey I like the minimalist feel ;)&lt;/p&gt;
&lt;p&gt;Let's see if it sticks around or it gets in the way… Either way, here's standalone snippet. Run with &lt;em&gt;swift deskclock.swift&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-swift"&gt;import Cocoa
import SwiftUI

let application = NSApplication.shared
let appDelegate = AppDelegate()
NSApp.setActivationPolicy(.regular)
application.delegate = appDelegate
application.mainMenu = NSMenu.makeMenu()
application.run()

struct ClockView: View {
  @State var time = &amp;quot;--:--&amp;quot;

  let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

  var body: some View {
    GeometryReader { geometry in

      VStack {
        Text(time)
          .onReceive(timer) { input in
            let formatter = DateFormatter()
            formatter.dateFormat = &amp;quot;HH:mm&amp;quot;
            time = formatter.string(from: input)
          }
          .font(.system(size: 40))
          .padding()
      }.frame(width: geometry.size.width, height: geometry.size.height)
        .background(Color.black)
        .cornerRadius(10)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
  }
}

extension NSWindow {
  static func makeWindow() -&amp;gt; NSWindow {
    let window = NSWindow(
      contentRect: NSRect.makeDefault(),
      styleMask: [.closable, .miniaturizable, .resizable, .fullSizeContentView],
      backing: .buffered, defer: false)
    window.level = .floating
    window.setFrameAutosaveName(&amp;quot;everclock&amp;quot;)
    window.collectionBehavior = [.canJoinAllSpaces, .stationary, .ignoresCycle, .fullScreenPrimary]
    window.makeKeyAndOrderFront(nil)
    window.isMovableByWindowBackground = true
    window.titleVisibility = .hidden
    window.backgroundColor = .clear
    return window
  }
}

class AppDelegate: NSObject, NSApplicationDelegate {
  var window = NSWindow.makeWindow()
  var hostingView: NSView?

  func applicationDidFinishLaunching(_ notification: Notification) {
    hostingView = NSHostingView(rootView: ClockView())
    window.contentView = hostingView
    NSApp.activate(ignoringOtherApps: true)
  }
}

extension NSRect {
  static func makeDefault() -&amp;gt; NSRect {
    let initialMargin = CGFloat(60)
    let fallback = NSRect(x: 0, y: 0, width: 100, height: 150)

    guard let screenFrame = NSScreen.main?.frame else {
      return fallback
    }

    return NSRect(
      x: screenFrame.maxX - fallback.width - initialMargin,
      y: screenFrame.maxY - fallback.height - initialMargin,
      width: fallback.width, height: fallback.height)
  }
}

extension NSMenu {
  static func makeMenu() -&amp;gt; NSMenu {
    let appMenu = NSMenuItem()
    appMenu.submenu = NSMenu()

    appMenu.submenu?.addItem(
      NSMenuItem(
        title: &amp;quot;Quit \(ProcessInfo.processInfo.processName)&amp;quot;,
        action: #selector(NSApplication.terminate(_:)), keyEquivalent: &amp;quot;q&amp;quot;
      ))

    let mainMenu = NSMenu(title: &amp;quot;Main Menu&amp;quot;)
    mainMenu.addItem(appMenu)
    return mainMenu
  }
}

&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 02 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/swiftui-desk-clock</guid></item><item><title>Neon • Art</title><link>https://muffinman.io/art/neon/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;You can play with algorithm &lt;a href="https://neon.muffinman.io/"&gt;here&lt;/a&gt; and download images. It took me ages to find appropriate pens to plot this one. Also check &lt;a href="/blog/neon-generative-art-piece-made-using-2d-vector-field/"&gt;the blog post&lt;/a&gt; about how it is made.&lt;/p&gt;
&lt;p&gt;On the images below you can see two different drawings.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;August 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;42x30cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Fabriano Black Black 300gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Sakura Gelly Rolls&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery art-gallery--wide"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1603" src="./0.jpg" width="2800" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1709" src="./w_500-h_500--1.jpg" width="2500" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./2.jpg"&gt;&lt;img alt="" class="gallery__image" height="1768" src="./w_500-h_500--2.jpg" width="2500" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./3.jpg"&gt;&lt;img alt="" class="gallery__image" height="1875" src="./w_500-h_500--3.jpg" width="2500" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Sun, 02 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/neon/</guid></item><item><title>Chaos Surfing</title><link>http://spirals.blog/articles/chaos-surfing/</link><description>&lt;h2&gt;Finding stability in the modern world of pandemics, AI-disruption, and failing markets&lt;/h2&gt;
&lt;p&gt;I want to share something that I think will help us all. These are dark times, and there’s a strong chance they may grow darker. May this be a light for others as it has been a light for me and mine. But first, we must set our stage.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Control.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It’s such a &lt;em&gt;&lt;strong&gt;human&lt;/strong&gt;&lt;/em&gt; idea, isn’t it? One of our &lt;em&gt;core&lt;/em&gt; needs, you might argue. And yet, of late, it seems to be slipping away faster than we can slip on our custom-printed, designer mask.&lt;/p&gt;
&lt;p&gt;Readers, these are trying times for us &lt;em&gt;all&lt;/em&gt;. COVID is raging. We’ve lost our jobs. Those that haven’t are stuck trying to balance work and kids without school. Since March, we’ve experienced one of the most tumultuous and chaotic market crashes in the history of money. And then there are the hopeful whispers, and blasé, off-handed comments on weekly Zoom calls; “Oh, when things get back to normal, we’ll open things back up again.”&lt;/p&gt;
&lt;p&gt;Normal. What a strange word. It kind of implies control, doesn’t it? What is &lt;em&gt;normal&lt;/em&gt; anyway? Can anybody define this elusive concept?&lt;/p&gt;
&lt;p&gt;And now we hear rumors of the “New Normal.” Is the New Normal showing up to a limited capacity restaurant with an obligatory face-mask, greeted with a mandatory dose of potentially &lt;a href="https://www.fda.gov/drugs/drug-safety-and-availability/fda-updates-hand-sanitizers-methanol"&gt;poisonous hand-sanitizer&lt;/a&gt;, being quietly ushered to a table with a QR code for a menu?&lt;/p&gt;
&lt;p&gt;What about our jobs? In April, &lt;a href="https://www.businessinsider.com/trucking-bloodbath-truck-drivers-lost-jobs-april-jobs-report-2020-5"&gt;~88,300 American truck drivers lost their jobs&lt;/a&gt;. Will the new &lt;a href="https://www.tesla.com/semi"&gt;Telsa Semi&lt;/a&gt; replace the backbone of the American economy? Last month, GPT-3 was announced, heralding yet another breakthrough for Open AI, the company founded by Elon and others to create safe AI before it gets out of hand. Even web developers aren’t immune anymore.&lt;/p&gt;
&lt;p&gt;Chesapeake Energy, America’s second-largest oil and fracking company &lt;a href="http://app.quotemedia.com/data/downloadFiling?webmasterId=101533&amp;amp;ref=115098942&amp;amp;type=PDF&amp;amp;symbol=CHK&amp;amp;companyName=Chesapeake+Energy+Corporation&amp;amp;formType=8-K&amp;amp;dateFiled=2020-06-29&amp;amp;CK=895126"&gt;filed for bankruptcy&lt;/a&gt; on the 28th June (2020), marking it as one of the most prominent pins to drop in the silence of a terrified market. Oil even went to a negative value. Yes, that means people would pay you to take their oil.&lt;/p&gt;
&lt;p&gt;Meanwhile, a borderline sociopath (and most certainly an ego-maniac) is running “the greatest country in the world” into the ground. China is &lt;a href="https://www.defensenews.com/opinion/commentary/2020/04/17/chinas-island-fortifications-are-a-challenge-to-international-norms/"&gt;literally creating new islands&lt;/a&gt; to gain more influence on the South-China sea. Our beloved tech-giants have grown from enabling us to connect with loved ones, into a very scary and legitimate war-zone on our privacy. They’ve even admitted to &lt;a href="https://www.digitaltrends.com/news/facebook-admits-it-was-also-listening-to-your-private-conversations/"&gt;listening to our conversations&lt;/a&gt;. Thanks Fuckerberg.&lt;/p&gt;
&lt;p&gt;Unemployment in the States is at 14%, a number we haven’t seen since the Great depression. There are talks of second waves of the Coronavirus. Countries are locking down their borders. The climate is warming, and &lt;a href="https://www.globalchange.gov/browse/indicators/global-sea-level-rise"&gt;the sea is rising&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Rising complexity - Pandoras Box&lt;/h2&gt;
&lt;p&gt;&lt;img alt="network" src="http://spirals.blog/articles/chaos-surfing/network.jpg" /&gt;
&lt;em&gt;Photo by Anastasia Dulgier @dulgier&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The world is in complete disarray. Chaos has finally caught up to us and peeled back the razor-thin veil of order and sanity that we call “society.” It was always there.&lt;/p&gt;
&lt;p&gt;The vast majority of us find “safety” in our perceived abilities to predict, nudge into line, and trim the hairy shrub of possibilities that represents the branches of our future realities. We’ve attempted, for millennia, to contain chaos into a neat little Pandora’s box (read Blue for those who are students of Spiral Dynamics). But it seems that the cat is out of the bag now. Before we find a solution to the chaos in our lives, let’s explore where it comes from, and why it’s increasing.&lt;/p&gt;
&lt;h3&gt;Defining complexity&lt;/h3&gt;
&lt;p&gt;Let us briefly define complexity (though it should be stated this is not an entirely comprehensive capture of this “complex” word. Pun indeed 🙃)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“A system with multiple agents, dynamically interacting in multiple ways, following &lt;em&gt;local&lt;/em&gt; rules, and oblivious to any higher-level instructions”
Steven Johnson: Emergence: The Connected Lives of Ants, Brains, Cities, and Software&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Put simply, complexity emerges when there are lots of things doing their own thing, all interacting with each other, and paying no mind to anything other than what they want.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sound familiar?&lt;/p&gt;
&lt;p&gt;The 2 factors of complexity are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The number of “things” (Distinction)&lt;/li&gt;
&lt;li&gt;How many of those “things” are connected/talk to another “thing” (Connection)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img alt="Complexity" src="http://spirals.blog/articles/chaos-surfing/complexity.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Can you think of something that’s connected us more and more in the past few decades? 3 significant technologies come to mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Better airplanes&lt;/li&gt;
&lt;li&gt;Telephones&lt;/li&gt;
&lt;li&gt;The Internet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compared to a century ago, our actions have more of an effect. Some developers in sunny California can “accidentally” cause a genocide in Myanmar. &lt;a href="https://www.nytimes.com/2018/11/06/technology/myanmar-facebook.html"&gt;This actually happened&lt;/a&gt;. Why?&lt;/p&gt;
&lt;p&gt;From our definition before, “following &lt;em&gt;local&lt;/em&gt; rules, and oblivious to any higher-level instructions” is an apparent reason for this. Humans were not designed to be cognisant of how our individual actions affect those outside our tribe. We evolved to live with at most 150 people in a band. It’s impossible to consider how, when posting that picture of our overpriced cocktail to Instagram, we will affect someone on the other side of the globe. We just don’t have the mental capacity.&lt;/p&gt;
&lt;p&gt;And yet this is what’s happening even day. In a world of hyper-connectivity, hyper-travel, and hyper-communication, no-one is separate. Like the “nodes” of our image above, we touch more lives today than we were designed to. Hence the chaos that has ensued.&lt;/p&gt;
&lt;h2&gt;Surfing&lt;/h2&gt;
&lt;p&gt;Is it clear, now, that we are incapable of determining our future? Sure, we can set goals, work toward building a family, move to a country, and change careers. But can we control the outside factors that are “emerging” (technical word) from the apparent chaos?&lt;/p&gt;
&lt;p&gt;This was precisely my situation. I’ve spent the last 2 years trying to move to San Francisco, traveling between 5 different countries in just one year while I wait to live with my wife. Come March (2020), all visa processing was put on hold, and my marriage (long-distance) was put to the test. I’m not the only one.&lt;/p&gt;
&lt;p&gt;It’s easy to let this get to us. If we “doom scroll” on the news (designed to evoke an emotional response), and continually hit refresh on &lt;a href="https://www.worldometers.info/coronavirus/"&gt;worldmeters.info&lt;/a&gt;, is it &lt;em&gt;really&lt;/em&gt; going to improve our situation? Is knowing the recent antics of Donald Trump actually going to help us deal with life?&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gandalf" src="http://spirals.blog/articles/chaos-surfing/gandalf.jpg" /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Frodo: “I wish the Ring had never come to me. I wish none of this had happened.”&lt;/p&gt;
&lt;p&gt;Gandalf: “So do all who live to see such times, but that is not for them to decide. All we have to decide is what to do with the time that is given to us.”
– J.R.R. Tolkien, The Lord of the Rings&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Trying to control life and the future is as silly and pointless as trying to stop the waves from crashing up against the shore.&lt;/strong&gt; It cannot be done. It &lt;em&gt;should&lt;/em&gt; not be done.&lt;/p&gt;
&lt;p&gt;What if instead of trying to prevent the inevitable, we &lt;em&gt;&lt;strong&gt;accepted it&lt;/strong&gt;&lt;/em&gt;, and &lt;em&gt;&lt;strong&gt;used it&lt;/strong&gt;&lt;/em&gt;? What if we could “surf” the wave of chaos?&lt;/p&gt;
&lt;h2&gt;The Motion of the Ocean&lt;/h2&gt;
&lt;h3&gt;Go along with the ride&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Ocean" src="http://spirals.blog/articles/chaos-surfing/ocean.jpg" /&gt;
&lt;em&gt;Photo by Andrzej Kryszpiniuk @kryszpin&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Depending on what you believe, no thing, person, or event is truly “good” or “bad”. These virtues only appear when we compare them against something we are seeking in life.&lt;/p&gt;
&lt;p&gt;When we hold a tightly-coupled relationship to a future outcome, we expose ourselves to the anxiety and stress of this not eventuating. That is not (at all) to say we should live without purpose. We should be directed and clear with what we are aiming to achieve in life. But when the game changes, we need to change with it, and so do our ideas of the future. We can hold on to the bitter end (many do), or we can re-calibrate.&lt;/p&gt;
&lt;p&gt;What’s dramatically different from the past is the &lt;em&gt;frequency&lt;/em&gt; of which we need to re-calibrate. &lt;a href="https://en.wikipedia.org/wiki/The_Black_Swan:_The_Impact_of_the_Highly_Improbable"&gt;Black Swan Events&lt;/a&gt; are increasing in their occurrence, and this calls for greater flexibility.&lt;/p&gt;
&lt;h3&gt;Flexibility&lt;/h3&gt;
&lt;p&gt;Where I come from, we have a phrase:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The person with the most behavioral flexibility will have the most impact on the system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I can’t change that Australia (my home country) has shut down it’s US embassy, preventing me from moving to San Francisco to be with my wife. I complained. I grew livid. I swore. And I got over it. No action from my wife or myself could modify the chaotic nature of pandemic-influenced international regulation.&lt;/p&gt;
&lt;p&gt;So, we both looked at the 14 countries an American citizen is allowed to visit (as of Aug 2020). We cross-referenced those with the timezones of our jobs (we work remotely), good internet speeds, safe spaces. We concluded we’d reunite in Mexico City (from where I am writing this). We are currently in the process of redefining what our idea of family will look like. Where to raise our children. Where they can go to school. Are we ok with them being a &lt;a href="https://www.bbc.com/worklife/article/20161117-third-culture-kids-citizens-of-everywhere-and-nowhere"&gt;“third-culture-kid”&lt;/a&gt; despite the intense challenges?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Surfing these waves is not easy, and I will never pretend it is. It means, often on a daily/weekly basis, re-addressing the core things you hold dear about what you are looking forward to in your life. If you’ve ever taken a surfing lesson, you’ll know you fall off the board; a lot. But this isn’t failure. Failure is when you don’t get back on the board again.&lt;/p&gt;
&lt;p&gt;One thing is for sure, and that is this world is not the same as it was 10 years ago and is &lt;strong&gt;DEFINITELY&lt;/strong&gt; not what it will be in another 10 years. Nobody can predict the future. Nobody can tell you where to invest, or what country is safe from global warming, or the impending 3rd World War with China. Nobody.&lt;/p&gt;
&lt;p&gt;Because that’s not the point. The point is to let go of trying to control what we simply cannot, and &lt;em&gt;&lt;strong&gt;enjoy what we can&lt;/strong&gt;&lt;/em&gt;. Perhaps with prolonged, intensive work on ourselves, we may find we’re in a position to influence things. Perhaps not.&lt;/p&gt;
&lt;h3&gt;Control -&amp;gt; Flexibility&lt;/h3&gt;
&lt;p&gt;Allow “flexibility” to enter your &lt;em&gt;core values&lt;/em&gt; in replacement of “control”. I implore you 🙏. With flexibility comes greater empathy, healthy detachment from definite outcomes, and a deeper sense of happiness, born from a connection to the present moment.&lt;/p&gt;
&lt;hr /&gt;
&lt;center style="font-style: italic; font-weight: bold;"&gt;We don’t own the future. But we own our experience.&lt;/center&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 02 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/chaos-surfing/</guid></item><item><title>Stay Safe on the Road</title><link>https://boyter.org/posts/stay-safe-on-the-road/</link><description>&lt;p&gt;SI live in an area with a popular driving road. As such you see a lot of people flying around in fancy cars, motorbikes and bike riders. Between where I am and the start there is an awful bit of road that funnels everyone together. As such a lot of people jump the line to get past the bike riders because there isn&amp;rsquo;t enough space for them to have their own lane (I keep complaining to my local member about this).&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Sun, 02 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/stay-safe-on-the-road/</guid></item><item><title>Fixing MacBook Pro Thermal Performance Issues</title><link>https://www.dannyguo.com/blog/fixing-macbook-pro-thermal-performance-issues</link><author>Danny Guo</author><pubDate>Sun, 02 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.dannyguo.com/blog/fixing-macbook-pro-thermal-performance-issues</guid></item><item><title>Seastar's shared pointer</title><link>https://makedist.com/posts/2020/08/02/seastars-shared-pointer/</link><description>A reference counted smart pointer with unique optimizations.</description><author>Noah Watkins</author><pubDate>Sun, 02 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://makedist.com/posts/2020/08/02/seastars-shared-pointer/</guid></item><item><title>Introduction to AR.js and Natural Feature Tracking</title><link>https://web.navan.dev/posts/2020-08-01-Natural-Feature-Tracking-ARJS.html</link><description>An introduction to AR.js and NFT</description><author>Navan's Archive</author><pubDate>Sat, 01 Aug 2020 18:43:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-08-01-Natural-Feature-Tracking-ARJS.html</guid></item><item><title>Projects</title><link>https://ferrucc.io/projects/</link><description>&lt;div&gt;
 &lt;h1 style="font-size: 2rem; text-align: center;"&gt;Ferruccio Balestreri&lt;/h1&gt;
 &lt;p style="font-size: 1rem; color: #333;"&gt;I love making things and take pride in it.&lt;/p&gt;</description><author>ferrucc.io</author><pubDate>Sat, 01 Aug 2020 15:59:23 GMT</pubDate><guid isPermaLink="true">https://ferrucc.io/projects/</guid></item><item><title>Why your academic code needs a software licence</title><link>https://bastian.rieck.me/blog/2020/licence/</link><description>&lt;p&gt;Regardless of the scientific discipline you are working in, you probably
write some code to perform your experiments. This post aims to inform
you about the need for adding a &lt;em&gt;licence&lt;/em&gt; to your software&amp;mdash;a procedure
that is often neglected, in particular since it is associated with legal
considerations, which are perceived as being tedious by many&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Since
I am not a lawyer, I will go easy on the legalese and just provide
a quick overview.&lt;/p&gt;
&lt;p&gt;(If you are in a hurry, feel free to &lt;a href="#parting-thoughts"&gt;skip to the conclusion and its actionable items&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Caveat lector&lt;/strong&gt;: Your university might require you to consult with
them &lt;em&gt;prior&lt;/em&gt; to releasing software into the wild. Make sure to check
whether you are actually allowed to release your code without anyone
checking out the legalities of the situation. This article is mostly
written from a machine learning perspective, where people tend to be
very generous in releasing their code, but often forget to choose an
appropriate licence.&lt;/p&gt;
&lt;h1 id="why-are-software-licences-useful"&gt;Why are software licences useful?&lt;/h1&gt;
&lt;p&gt;Software licences serve multiple purposes. Most importantly, they specify
what kind of interactions you want people to have with your code. For
example, are you okay with your code&amp;mdash;and thus potentially your
name&amp;mdash;being used to &lt;em&gt;advertise&lt;/em&gt; a product or service of someone else? Are
you okay with people using the software &lt;em&gt;commercially&lt;/em&gt;? What happens if
your code does not work as expected and produces &lt;em&gt;incorrect results&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;A licence helps you cover all of these aspects&amp;mdash;and many more. But the
primary function of a licence is not necessarily to &lt;em&gt;protect&lt;/em&gt; you from bad
things, it also defines what kind of community you want to build around your
code. For example, how do you handle improvements of your code? How do
you want to be attributed? How do you want &lt;em&gt;others&lt;/em&gt; to be attributed?
Can &lt;em&gt;anyone&lt;/em&gt; contribute to your project?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: A software licence clearly defines what people &lt;em&gt;can&lt;/em&gt; and
&lt;em&gt;cannot&lt;/em&gt; do with your code. It helps you, your users, and your
potential contributors.&lt;/p&gt;
&lt;h1 id="why-is-having-no-licence-a-bad-thing"&gt;Why is having &lt;em&gt;no&lt;/em&gt; licence a bad thing?&lt;/h1&gt;
&lt;p&gt;You might think that, being the generous scientist that you are, that
your code should be released with essentially a &amp;rsquo;no strings attached'
policy. That is commendable&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;, but the law, for once, is &lt;em&gt;not&lt;/em&gt; on your
side here: if you release code &lt;em&gt;without&lt;/em&gt; a licence attached, the default
interpretation in most&amp;mdash;if not all&amp;mdash;jurisdictions is that you retain
all privileges. This might sound not too bad, but there are often
unintended  consequences. For example,
&lt;a href="https://choosealicense.com/no-permission"&gt;choosealicense.com&lt;/a&gt; has the
following things to say about having &lt;em&gt;no&lt;/em&gt; licence (emphasis by me):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When you make a creative work (which includes code), the work is under
&lt;em&gt;exclusive copyright&lt;/em&gt; by default. Unless you include a license that
specifies otherwise, &lt;em&gt;nobody else&lt;/em&gt; can copy, distribute, or modify your
work without being at risk of take-downs, shake-downs, or litigation.
&lt;strong&gt;Once the work has other contributors (each a copyright holder), “nobody”
starts including you&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is bad! Suppose that you revisit a project that you collaborated on
with multiple people. After a few years, you have the urge to make this
into a commercial tool. If you have no licence, you technically have to
negotiate with all of your original contributors, or even your previous
employers (remember that you might change university affiliations a few
times). If you fail to do this, you make your life harder and, in the
worst case, you may be subject to litigation.&lt;/p&gt;
&lt;p&gt;However, you are not only impeding &lt;em&gt;your&lt;/em&gt; future possibilities if you do
not specify a licence, you are also hurting the options of &lt;em&gt;others&lt;/em&gt;:
code without a licence can be removed without a whim, and technically,
everyone who builds on that code has to ask for permission and is not
directly allowed to redistribute it. Again, as a worst-case scenario,
you might have to &lt;em&gt;retract&lt;/em&gt; code because you never had the right to use
it in the first place! Plus, companies tend to avoid code without
a licence like a plague because &lt;em&gt;they&lt;/em&gt; have legal departments that know
about the dire consequences of using code without the proper legal
framework&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: If you do not use a licence, you are only hurting
yourself (or your future self) and the prospects of your project.&lt;/p&gt;
&lt;h1 id="how-do-i-licence-my-code-then"&gt;How do I licence my code, then?&lt;/h1&gt;
&lt;p&gt;After all these warnings about unintended consequences, it is time for
some good news: in this age, adding a licence to your code is as easy as
it gets. Here are the main steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First, you have to &lt;em&gt;pick&lt;/em&gt; an appropriate licence&amp;mdash;no worries, we
will talk about this in a second!&lt;/li&gt;
&lt;li&gt;You now create a file called &lt;code&gt;LICENSE&lt;/code&gt;&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt; in your main code
repository and add your name to it.&lt;/li&gt;
&lt;li&gt;Optionally, you now add a text of the form &amp;lsquo;See &lt;code&gt;LICENSE&lt;/code&gt; for details
on how to use this code&amp;rsquo; to your source code files. This is just
a courtesy for your users; your selected licence still applies to all
source files, but sometimes, adding such a disclaimer is a good
reminder&amp;mdash;in particular for large code bases.&lt;/li&gt;
&lt;li&gt;You publish the code. That&amp;rsquo;s it!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sounds easy, right? In fact, it is so easy that &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; even provides
licence templates when setting up a repository. It does not even take
a few minutes of your time&amp;mdash;which is how it should be!&lt;/p&gt;
&lt;h1 id="which-licence-should-i-choose"&gt;Which licence should I choose?&lt;/h1&gt;
&lt;p&gt;Now that you know how easy it is, which licence should you choose?  For
this, the website &lt;a href="https://choosealicense.com"&gt;choosealicense.com&lt;/a&gt; is
a treasure trove. Moreover, the website &lt;a href="https://tldrlegal.com/"&gt;tldrlegal.com&lt;/a&gt;
is also great in explaining the specifics of a licence in plain English.
Please do not take my word for it and check all the licences I will
subsequently mention!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Caveat lector&lt;/strong&gt;: At this point, I have to stress that what comes next
is my personal opinion and it is thus heavily biased towards a certain
type of licence.  I will try to back up my claims, though!&lt;/p&gt;
&lt;h2 id="avoid-copyleft-licences"&gt;Avoid copyleft licences&lt;/h2&gt;
&lt;p&gt;As a first piece of advice, I would urge you to &lt;em&gt;avoid&lt;/em&gt; so-called
copyleft licences, like the &lt;a href="https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)"&gt;GNU General Public Licence v3&lt;/a&gt;.
I know that this is a controversial statement for some, but before you
close this tab in anger, let me explain: a copyleft licence forces your
users to require all derivative works&amp;mdash;other projects, updates, and
extensions of your code&amp;mdash;to be released under the &lt;em&gt;same&lt;/em&gt; licence as
your original code. This sounds fair at first glance&amp;mdash;after all, you
made your code available for anyone else to be free to use, so others
should do the same, right? While I agree with this sentiment, the
GPL (and similar licences) make it harder for private companies to
engage with your project. There are subtle legal issues that often
require for-profit businesses &lt;em&gt;not&lt;/em&gt; to engage with code like this, even
if they wanted to!&lt;/p&gt;
&lt;p&gt;Note that I am not claiming that there are no successful industry
contributions to GPL projects! I am merely pointing out that this
licence raises the bar quite considerably for other institutions to
engage with your code. Especially when you develop tools for others to
be used, as is very common in bioinformatics and machine learning, you
want to make it easy for others to build on your work. Do not take my
word for it, though: if you are
not convinced, read &lt;a href="http://ivory.idyll.org/blog/2015-on-licensing-in-bioinformatics.html"&gt;this article on licencing software in bioinformatics&lt;/a&gt;
by &lt;a href="http://ivory.idyll.org/"&gt;C. Titus Brown&lt;/a&gt;,
as well as &lt;a href="https://liorpachter.wordpress.com/2017/08/03/i-was-wrong-part-2"&gt;this article on the troubles with licencing&lt;/a&gt;, written
by &lt;a href="https://pachterlab.github.io/biography.html"&gt;Lior Pachter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: Avoid copyleft licences if you can (but they are still
a lot better than having no licence at all).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Philosophical sidenote&lt;/strong&gt; (you may skip this): it is one of my
core tenets that I do not want to &lt;em&gt;force&lt;/em&gt; people into a certain kind of
desirable behaviour&amp;mdash;such as sharing their code&amp;mdash;but rather I want to
&lt;em&gt;convince&lt;/em&gt; them. The formulation of copyleft appears to be too
stringent for my taste: I can easily imagine situations in which abiding
by this licence is problematic for the other party, even if they &lt;em&gt;want&lt;/em&gt;
to abide by it! Thus, I am not a big proponent of these licences any
more. When I originally got involved with Linux, BSD, and the open
source movement, I liked the GPL a lot, but as I started using BSD more
and more, my stance changed.&lt;/p&gt;
&lt;h2 id="use-a-permissive-licence-instead"&gt;Use a permissive licence instead&lt;/h2&gt;
&lt;p&gt;So, what licence &lt;em&gt;should&lt;/em&gt; you choose for your academic code, then?
I prefer the so-called &lt;em&gt;permissive&lt;/em&gt; licences, which are often also
referred to as &amp;lsquo;BSD-style&amp;rsquo; licences. Permissive licences have minimal
restrictions as to how your software can be used, but they provide
protection for you &lt;em&gt;and&lt;/em&gt; make it possible for others to attribute your
work! Here is my preferred permissive licence, the &lt;a href="https://tldrlegal.com/license/bsd-3-clause-license-(revised)"&gt;Revised BSD 3-Clause
Licence&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Copyright (c) YEAR AUTHOR, all rights reserved.&lt;/p&gt;
&lt;p&gt;Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &amp;ldquo;AS
IS&amp;rdquo; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I like this licence because it permits others&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="#fn:5"&gt;5&lt;/a&gt;&lt;/sup&gt; to use your software
commercially, modify it, distribute it, and even provide a warranty for
it, &lt;em&gt;provided&lt;/em&gt; they include the copyright notice&amp;mdash;in other words, they
attribute your work&amp;mdash;and the licence itself. Moreover, you &lt;em&gt;cannot&lt;/em&gt; be
held liable for any damages arising from the use of the code, and others
cannot use your name to endorse any derived products (they &lt;em&gt;can&lt;/em&gt; of
course obtain permission from you). The last part is particularly
interesting, as you never know how your software is going to be used.&lt;/p&gt;
&lt;p&gt;There are variations of this licence, depending on the number of clauses
that are being used. Other permissive licences include the &lt;a href="https://tldrlegal.com/license/mit-license"&gt;MIT
Licence&lt;/a&gt;, as well as the
&lt;a href="https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)"&gt;Apache Licence
2.0&lt;/a&gt;. The
latter is slightly more complicated and requires users to be more
specific concerning the changes they make to the software, but
essentially, &lt;em&gt;all&lt;/em&gt; of these licences permit commercial and
non-commercial use. Picking any one of them is going to make everything
easier for you and users of your project!&lt;/p&gt;
&lt;h2 id="software-licences-in-the-wild"&gt;Software licences in the wild&lt;/h2&gt;
&lt;p&gt;The success of these permissive licences can easily be observed in the
machine learning and data visualisation communities. Here are some
examples of our most beloved projects and their respective licences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://keras.io"&gt;Keras&lt;/a&gt;: MIT Licence&lt;/li&gt;
&lt;li&gt;&lt;a href="https://matplotlib.org"&gt;matplotlib&lt;/a&gt;: A BSD-style licence&lt;/li&gt;
&lt;li&gt;&lt;a href="https://numpy.org"&gt;numpy&lt;/a&gt;: BSD 3-Clause Licence&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scikit-learn.org"&gt;scikit-learn&lt;/a&gt;: BSD 3-Clause Licence&lt;/li&gt;
&lt;li&gt;&lt;a href="https://seaborn.pydata.org"&gt;seaborn&lt;/a&gt;: BSD 3-Clause Licence&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pytorch.org"&gt;PyTorch&lt;/a&gt;: BSD 3-Clause Licence&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.tensorflow.org"&gt;TensorFlow&lt;/a&gt;: Apache Licence 2.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I think this establishes that permissive licences and vibrant
communities can go hand in hand.&lt;/p&gt;
&lt;h1 id="parting-thoughts"&gt;Parting thoughts&lt;/h1&gt;
&lt;p&gt;I hope I provided an interesting glimpse into the wonderful world of
licences. Whether you read the whole article or skipped to the end,
I want everyone to take away these three statements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Your project needs a licence. It helps &lt;em&gt;you&lt;/em&gt; and it helps others.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Any&lt;/em&gt; licence (regardless of whether you choose to use a copyleft
licence like the GPL or a permissive BSD licence) is &lt;strong&gt;infinitely
better&lt;/strong&gt; than no licence at all.&lt;/li&gt;
&lt;li&gt;When in doubt, aim for permissive licences for academic projects. The
&lt;a href="https://tldrlegal.com/license/bsd-3-clause-license-(revised)"&gt;BSD 3-Clause
Licence&lt;/a&gt;
is a good choice because it requires people to credit you (the
favourite currency in academia!), while preventing them from claiming
that you endorse their product.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wish you all the best for your projects, no matter their size and
scope. Until next time!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;At least in this, law and mathematics are united: most people
cannot fathom why one should be fascinated by the subject, even
though, when you look more closely, it is really captivating. With
apologies to my legally-educated friends, I like the analogy of
thinking of a contract as &amp;lsquo;code that you run in your society&amp;rsquo;. In
other words, contracts define how certain interactions between legal
persons should work.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;And we will cover a licence that approaches this ideal rather
well!&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Your university also has a legal department with lawyers that are
very aware of these consequences. The pity is that almost no one
thinks about consulting them! At this point, let me give a shout-out
to the excellent &lt;a href="https://ethz.ch/en/industry-and-society/tto.html"&gt;Technology Transfer
Office&lt;/a&gt; of &lt;a href="https://ethz.ch/en.html"&gt;ETH
Zürich&lt;/a&gt;. Their employees are extremely
well-versed in negotiations involving industry and academia, and they
saved our bacon quite a few times now with their ability to navigate
the murky waters of international copyright law.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;Unfortunately, the agreed-upon spelling is the American one here.
Having been trained to write the Queen&amp;rsquo;s English, I often stumble over
this.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;Remember that &amp;lsquo;others&amp;rsquo; also includes future versions of yourself!&amp;#160;&lt;a class="footnote-backref" href="#fnref:5"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Sat, 01 Aug 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/licence/</guid></item><item><title>Manual code signing certificate request procedure</title><link>https://blog.kaetemi.be/2020/08/01/manual-code-signing-certificate-request-procedure/</link><description>Executables signed with a reputable code signing certificate get better SmartScreen treatment. A signed executable proves that it hasn&amp;#8217;t been tampered with by anyone who does not have the signature...</description><author>Kaetemi</author><pubDate>Sat, 01 Aug 2020 06:10:13 GMT</pubDate><guid isPermaLink="true">https://blog.kaetemi.be/2020/08/01/manual-code-signing-certificate-request-procedure/</guid></item><item><title>Come to Armenia 🇦🇲</title><link>https://ashvardanian.com/posts/armenia/</link><description>Why Armenia is an emerging tech hub worth your attention — from startup tax incentives to ancient history, discover what makes this small nation punch above its weight.</description><author>Ash's Blog</author><pubDate>Sat, 01 Aug 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ashvardanian.com/posts/armenia/</guid></item><item><title>NDAA Implications for Design Engineers</title><link>https://shielddigitaldesign.com/posts/2020/ndaa/</link><description>&lt;p&gt;
I recently found out about the latest &lt;span class="glossary-term" tabindex="0" title=""&gt;
    National Defense Authorization
Act
&lt;/span&gt;

 (from &lt;a href="http://pcb.iconnect007.com/index.php/article/123799"&gt;I-Connect007&lt;/a&gt;) and a new provision for &lt;span class="glossary-term" tabindex="0" title="Multiple boards used to mechanically support and electrically connect electronic components."&gt;
    printed circuit boards
&lt;/span&gt;
with some government contract procurement rules. If you made it
through that first sentence, then there's a good chance the rest of
this article won't be too boring for you! This seems like it's a bit
of a dry subject, but it's got me excited for what it means for the
future of both &lt;span class="glossary-term" tabindex="0" title="The overall process of producing a functional electronic assembly, including both PCB fabrication and assembly."&gt;
    PCB manufacturing
&lt;/span&gt; as well as broader economic impacts
in our country. In this article, I'm going to try to explain these
provisions (at least to the best of my limited ability to understand
them) but more importantly I've got some predictions about what this
means for the design engineer (since I'm sure most discussion of the
NDAA will probably talk about it only from the perspective of the
&lt;span class="glossary-term" tabindex="0" title="Factories that manufacture bare printed circuit boards (PCBs)."&gt;
    fabricators
&lt;/span&gt; and &lt;span class="glossary-term" tabindex="0" title="The factory for printed circuit boards which handles the assembly of components onto the bare boards."&gt;
    assemblers
&lt;/span&gt;).&lt;/p&gt;</description><author>Shield Digital Design</author><pubDate>Fri, 31 Jul 2020 19:00:00 GMT</pubDate><guid isPermaLink="true">https://shielddigitaldesign.com/posts/2020/ndaa/</guid></item><item><title>Re-architecting our PDF Generation</title><link>/pdf-generation/</link><description>&lt;p&gt;When I joined the Koru team, one of the biggest issues with our pipeline was the PDF generation system.
We have PDF's in the first place as a nice report that customers get about each of their candidates that takes an assessment on our system.
These PDF's are saved to S3 and then we send the customer a signed link to download the PDF.&lt;/p&gt;
&lt;p&gt;The major problem with it however, was that the PDF system ran on two big expensive &lt;code&gt;m4.large&lt;/code&gt; box (~$74 a month each!) and then there was another one for our QA environment.
You wouldn't mind paying a premium for the machine if the service worked but it constantly failed to generate PDF's for unknown reasons. It was one of those services that was just a black hole to us.
I don't like having any black holes in systems that I'm charged with running and maintaining. It pays to be extremely knowledgable about the system (within reason of course).&lt;/p&gt;
&lt;p&gt;So we've got the classic, too expensive, doesn't work and a &amp;quot;known unknown&amp;quot;. What would you do?&lt;/p&gt;
&lt;p&gt;How the PDF system worked historically was to open the web page in an instance of Chrome and then &amp;quot;print&amp;quot; it to a PDF. This was extremely memory intensive and the box could only handle a couple of PDF's at a time.
However, there was no mechanism to rate limit itself. Therefore, if we fired five requests at it, then the box crashed and it had to be manually rebooted.
Although we tried a number of ways to fix it, what we really wanted was something that was event driven so it could fail and manage it's own processing rate with ease. Since the application was hosted on EC2, we couldn't configure it to trigger from SQS without additional overhead, so we decided to rewrite.&lt;/p&gt;
&lt;p&gt;The first MVP was a Node Lambda that called a service called Api2Pdf - a simple API-as-a-service platform that, given a URL and some parameters, creates you a PDF.
We then saved this PDF Buffer to our own S3 bucket and then deleted the one that they had just generated.
Unfortunately, we had a number of bugs with this system. Because the web page that we took a PDF of often took up to 700ms to load, the PDF was being generated before any of the content had loaded. It was seemingly only an edge case though.
The obvious fix for this was to add some kind of CSS selector that the API would wait for &lt;em&gt;before&lt;/em&gt; generating the PDF - but this was not possible at the time with Api2Pdf's API.&lt;/p&gt;
&lt;p&gt;So the next step, was to add some protective validation that would check if the PDF had any content before then being accepted. If it was blank then an error was thrown for it to be retried.&lt;/p&gt;
&lt;p&gt;This worked for a couple of weeks, and then we got some more errors... This time, it had generated the content but the underlying data hadn't yet loaded it. This meant it passed the &amp;quot;blank&amp;quot; check but ultimately hadn't loaded correctly.
So I got working on another fix, my first attempt was to take a sample and compare the Buffers and see if they were the same. However, there were edge cases that this could not handle.
I then found PDFJS from Mozilla which had a handy feature to be able to get the text of a PDF. I decided to compare the generated PDF's text with a sample I had taken.&lt;/p&gt;
&lt;p&gt;Again, this appeared to work for a few weeks - perhaps too well. Although still ultimately had the downside that if it failed we would have to regenerate the PDF and were charged in the process for doing so.&lt;/p&gt;
&lt;p&gt;However, after an API release, it appeared as though the page rendering the PDF had slowed down enough that the amount of PDF's getting generated incorrectly had increased.&lt;/p&gt;
&lt;p&gt;At this point, I decided I was done with hacky fixes and working with a million libraries not updated in ages - seriously with the amount of NPM packages out there I would have thought there was something decent for PDF's.
It was time for the big guns - it was time for Puppeteer.&lt;/p&gt;
&lt;p&gt;As you may or may not know, Puppeteer is a beautifully designed API for working with Chromium. It has specific functions for screenshots, modifying the page, etc. But most importantly for us, it could generate PDF's.&lt;/p&gt;
&lt;p&gt;Porting over to the API was relatively ease and didn't require a whole lot of modification. What did, was getting it deployable to serverless and AWS Lambda.&lt;/p&gt;
&lt;p&gt;Because Puppeteer contains the entire Chromium browser in its install, it vastly goes beyond the size limit for Lambdas (50MB Zipped, 250MB Unzipped)
The solution was to use a Lambda layer to contain the Puppeteer stuff and then just the application code in the lambda itself. I used a lambda layer taken from &lt;a href="https://github.com/shelfio/chrome-aws-lambda-layer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I had to modify my serverless config like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;layers:
  HeadlessChrome:
    name: HeadlessChrome
    compatibleRuntimes:
      - nodejs12.x
    description: Required for headless chrome
    package:
      artifact: layers/chrome_aws_lambda.zip

functions:
  generate-pdf:
    provisionedConcurrency: 1
    description: Generates PDF from HTTP calls or SQS messages.
    handler: dist/handler.handler
    layers:
      - { Ref: HeadlessChromeLambdaLayer }
    events: ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, I had issues with the PDF working fine, but not displaying any background colors. At first I tried doing the &lt;code&gt;emulatePageMedia&lt;/code&gt; function and passing null so that it would not use print based CSS code, but to no avail. Finally, I managed to find a helpful fix on StackOverflow &lt;a href="https://stackoverflow.com/questions/60736354/puppeteer-not-rendering-color-background-color-when-i-try-to-save-pdf-on-disk"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-css"&gt;html {
  -webkit-print-color-adjust: exact;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I slumped back in my chair after this and breathed a sigh of relief. That was it... or so I thought.&lt;/p&gt;
&lt;p&gt;Turns out, in my haste I had set the option of &lt;code&gt;waitUntil: networkidle2&lt;/code&gt; in the &lt;code&gt;.goto()&lt;/code&gt; function for Puppeteer.
Basically this function is called so that the headless browser will navigate to the page provided. It returns a Promise of the page when the page has loaded. So, it can be awaited until the navigation has finished. But what is considered &amp;quot;loaded&amp;quot; anyway? Well thankfully, Puppeteer takes an array of special strings that tell it what it should consider &amp;quot;loaded&amp;quot;. NetworkIdle2, according to the documentation, works as follows: &lt;code&gt;consider navigation to be finished when there are no more than 2 network connections for at least 500 ms&lt;/code&gt;.
Now I'm not sure why I did this because in hindsight that was bound to go wrong. If the network request that loads the data takes more than 500ms then that means it will consider the page loaded before the content is present. Therefore, we changed it so it waited for &lt;code&gt;networkidle0&lt;/code&gt; which is the same as networkidle2 but waits until there are 0 network connections for 500ms.
Additionally, for added safety we added a 5 second &amp;quot;sleep&amp;quot; before it takes the PDF. This probably isn't needed any more, but we wanted to be extra cautious because of all the customer problems that this system had caused.&lt;/p&gt;
&lt;p&gt;This was the final piece in the puzzle. For real this time! It was finally stable. It was quite a journey and forced me to conquer some interesting problems with tonnes of various answers that had worked for some individuals. Additionally, we expanded our internal tooling with this project which will help us going forward to resolve customer issues. So overall, despite the chaos, it was a win win.
On reflection, I wish we had gone straight to Puppeteer but hindsight is 20/20. In all honesty, I was afraid of it. I saw it as an absolutely mammoth task, having nightmares about trying to implement it years ago at a web dev job, but it was shockingly simple to implement. It's taught me to take a better look at the options and not hold onto opinions from time gone. Technology moves to fast to do so.&lt;/p&gt;
&lt;p&gt;I'll conclude this article with a quote that I believe applies here:
&lt;code&gt;It ain’t what you don’t know that gets you into trouble. It’s what you know for sure that just ain’t so.&lt;/code&gt;&lt;/p&gt;</description><author/><pubDate>Fri, 31 Jul 2020 17:06:03 GMT</pubDate><guid isPermaLink="true">/pdf-generation/</guid></item><item><title>India’s New Education Policy (NEP 2020) — Key Points</title><link>https://nitinnain.com/indias-new-education-policy-nep-2020/</link><description>(Cross-post from schooldesk.io) A New Education Policy (NEP) for India was approved by the Union Cabinet on 29 July 2020. The policy is forward-looking, inclusive, the right amount of idealistic, and very much doable. There are big changes to the current system in this policy and these are being received very positively by most people, [&amp;#8230;]</description><author>Nitin Nain</author><pubDate>Fri, 31 Jul 2020 07:56:00 GMT</pubDate><guid isPermaLink="true">https://nitinnain.com/indias-new-education-policy-nep-2020/</guid></item><item><title>Short posts</title><link>https://ricardoanderegg.com/posts/write-short-blog-posts/</link><description>&lt;p&gt;Our attention spans are short. Even more when looking for new information. We get flooded by different sources. Most of them contain little useful information. Content should be concise, packed with information and clean of empty prose. Focused around examples. Remove everything not related to the title.&lt;/p&gt;
&lt;p&gt;When was the last time you spent more than 15 minutes reading a single piece of information?&lt;/p&gt;
&lt;p&gt;That is why I started writing &lt;a href="https://ricardoanderegg.com/recipes/"&gt;recipes&lt;/a&gt;.&lt;/p&gt;</description><author>Posts on rand[om]</author><pubDate>Fri, 31 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ricardoanderegg.com/posts/write-short-blog-posts/</guid></item><item><title>RenderMan Art Challenge: Shipshape</title><link>https://blog.yiningkarlli.com/2020/07/shipshape-renderman-challenge.html</link><description>&lt;div&gt;

  &lt;p&gt;&lt;/p&gt;
  &lt;h2 id="table-of-contents"&gt;Table of Contents&lt;/h2&gt;

  &lt;div class="tableofcontents"&gt;
    &lt;div class="tableofcontents-row"&gt;
        &lt;div class="tableofcontents-column3"&gt;
            &lt;div class="tableofcontents-content"&gt;
                1. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-introduction"&gt;Introduction&lt;/a&gt;&lt;br /&gt;
                2. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-initial-explorations"&gt;Initial Explorations&lt;/a&gt;&lt;br /&gt;
                3. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-layout-and-framing"&gt;Layout and Framing&lt;/a&gt;&lt;br /&gt;
                4. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-uv-unwrapping"&gt;UV Unwrapping&lt;/a&gt;&lt;br /&gt;
                5. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-texturing-the-ship"&gt;Texturing the Ship&lt;/a&gt;&lt;br /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="tableofcontents-column3"&gt;
            &lt;div class="tableofcontents-content"&gt;
                6. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-shading-the-ship"&gt;Shading the Ship&lt;/a&gt;&lt;br /&gt;
                7. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-shading-and-texturing-the-robots"&gt;Shading and Texturing the Robots&lt;/a&gt;&lt;br /&gt;
                8. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-the-wet-shader"&gt;The Wet Shader&lt;/a&gt;&lt;br /&gt;
                9. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-additional-props-and-elements"&gt;Additional Props and Elements&lt;/a&gt;&lt;br /&gt;
                10. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-rain-fx"&gt;Rain FX&lt;/a&gt;&lt;br /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        &lt;div class="tableofcontents-column3"&gt;
            &lt;div class="tableofcontents-content"&gt;
                11. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-lighting-and-compositing"&gt;Lighting and Compositing&lt;/a&gt;&lt;br /&gt;
                12. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-conclusion"&gt;Conclusion&lt;/a&gt;&lt;br /&gt;
                13. &lt;a href="/2020/07/shipshape-renderman-challenge.html#2020-07-31-references"&gt;References&lt;/a&gt;&lt;br /&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

  &lt;div id="2020-07-31-introduction"&gt;&lt;/div&gt;
  &lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;

  &lt;p&gt;Last year, I &lt;a href="https://blog.yiningkarlli.com/2019/11/woodville-renderman-challenge.html"&gt;participated in one of Pixar’s RenderMan Art Challenges&lt;/a&gt; as a way to learn more about modern RenderMan &lt;a href="https://dl.acm.org/citation.cfm?id=3182162"&gt;[Christensen et al. 2018]&lt;/a&gt; and as a way to get some exposure to tools outside of my normal day-to-day toolset (Disney’s Hyperion Renderer professionally, Takua Renderer as a hobby and learning exercise).
I had a lot of fun, and wound up doing better in the “Woodville” art challenge contest than I expected to!
Recently, I entered another one of &lt;a href="https://renderman.pixar.com/news/renderman-shipshape-art-challenge"&gt;Pixar’s RenderMan Art Challenges, “Shipshape”&lt;/a&gt;.
This time around I entered just for fun; since I had so much fun last time, I figured why not give it another shot!
That being said though, I want to repeat the main point I made in my post about the previous “Woodville” art challenge: I believe that for rendering engineers, there is enormous value in learning to use tools and renderers that aren’t the ones we work on ourselves.
Our field is filled with brilliant people on every major rendering team, and I find both a lot of useful information/ideas and a lot of joy in seeing the work that friends and peers across the field have put into commercial renderers such as RenderMan, Arnold, Vray, Corona, and others.&lt;/p&gt;

  &lt;p&gt;As usual for the RenderMan Art Challenges, Pixar &lt;a href="https://renderman.pixar.com/shipshape-pup-asset"&gt;supplied some base models&lt;/a&gt; without any uvs, texturing, shading, lighting or anything else, and challenge participants had to start with the base models and come up with a single compelling image for a final entry.
I had a lot of fun spending evenings and weekends throughout the duration of the contest to create my final image, which is below.
I got to explore and learn a lot of new things that I haven’t tried before, which this post will go through.
To my enormous surprise, this time around my entry &lt;a href="https://renderman.pixar.com/news/renderman-shipshape-art-challenge-final-results"&gt;won first place in the contest&lt;/a&gt;!&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/shipshape_full_4k.jpg"&gt;&lt;img alt="Figure 1: My entry to Pixar's RenderMan Shipshape Art Challenge, titled &amp;quot;Oh Good, The Bus is Here&amp;quot;. Click for 4K version. Base ship, robot, and sextant models are from Pixar; all shading, lighting, additional modeling, and environments are mine. Ship concept by Ian McQue. Robot concept by Ruslan Safarov. Models by Cheyenne Chapel, Aliya Chen, Damian Kwiatkowski, Alyssa Minko, Anthony Muscarella, and Miguel Zozaya © Disney / Pixar - RenderMan &amp;quot;Shipshape&amp;quot; Art Challenge." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/shipshape_full.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-initial-explorations"&gt;&lt;/div&gt;
  &lt;h2 id="initial-explorations"&gt;Initial Explorations&lt;/h2&gt;

  &lt;p&gt;For this competition, Pixar provided five models: a futuristic scifi ship based on an Ian McQue concept, a robot based on a Ruslan Safarov concept, an old wooden boat, a butterfly, and a sextant.
The fact that one of the models was based on an Ian McQue concept was enough to draw me in; I’ve been a big fan of Ian McQue’s work for many years now!
I like to start these challenges by just rendering the provided assets as-is from a number of different angles, to try to get a sense of what I like about the assets and how I will want to showcase them in my final piece.
I settled pretty quickly on wanting to focus on the scifi ship and the robot, and leave the other three models aside.
I did find an opportunity to bring in the sextant in my final piece as well, but wound up dropping the old wooden boat and the butterfly altogether.
Here are some simple renders showing what was provided out of the box for the scifi ship and the robot:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/scifiship_base.jpg"&gt;&lt;img alt="Figure 2: Scifi ship base model provided by Pixar, rendered against a white cyclorama background using a basic skydome." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/scifiship_base.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/robot_base.jpg"&gt;&lt;img alt="Figure 3: Robot base model provided by Pixar, rendered against a white cyclorama background using a basic skydome." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/robot_base.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;I initially had a lot of trouble settling on a concept and idea for this project; I actually started blocking out an entirely different idea before pivoting to the idea that eventually became my final image.
My initial concept included the old wooden boat in addition the scifi ship and the robot; this initial concept was called “River Explorer”.
My initial instinct was to try to show the scifi ship from a top-down view, in order to get a better view of the deck-boards and the big VG engine and the crane arm.
I liked the idea of putting the camera at roughly forest canopy height, since forest canopy height is a bit of an unusual perspective for most photographs due to canopy height being this weird height that is too high off the ground for people to shoot from, but too low for helicopters or drones to be practical either.
My initial idea was about a robot-piloted flying patrol boat exploring an old forgotten river in a forest; the ship would be approaching the old sunken boat in the river water.
With this first concept, I got as far as initial compositional blocking and initial time-of-day lighting tests:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_012.jpg"&gt;&lt;img alt="Figure 4: Initial &amp;quot;River Explorer&amp;quot; concept, daylight lighting test." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/progress_012.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_013.jpg"&gt;&lt;img alt="Figure 5: Initial &amp;quot;River Explorer&amp;quot; concept, dusk lighting test." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/progress_013.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;If you’ve followed my blog for a while now, those pine trees might look familiar.
They’re actually the same trees from &lt;a href="https://blog.yiningkarlli.com/2018/10/bidirectional-mipmap.html"&gt;the forest scene I used a while back&lt;/a&gt;, ported from Takua’s shading system to RenderMan’s PxrSurface shader.&lt;/p&gt;

  &lt;p&gt;I wasn’t ever super happy with the “River Explorer” concept; I think the overall layout was okay, but it lacked a sense of dynamism and overall just felt very static to me, and the robot on the flying scifi ship felt kind of lost in the overall composition.
Several other contestants wound up also going for similar top-down-ish views, which made me worry about getting lost in a crowd of similar-looking images.
After a week of trying to get the “River Explorer” concept to work better, I started to play with some completely different ideas; I figured that this early in the process, a better idea was worth more than a week’s worth of sunk time.&lt;/p&gt;

  &lt;div id="2020-07-31-layout-and-framing"&gt;&lt;/div&gt;
  &lt;h2 id="layout-and-framing"&gt;Layout and Framing&lt;/h2&gt;

  &lt;p&gt;I had started UV unwrapping the ship already, and whilst tumbling around the ship unwrapping all of the components one-by-one, I got to see a lot more of the ship and a lot more interesting angles, and I suddenly came up with a completely different idea for my entry.
The idea that popped into my head was to have a bunch of the little robots waiting to board one of the flying ships at a quay or something of the sort.
I wanted to convey a sense of scale between the robots and the flying scifi ship, so I tried putting the camera far away and zooming in using a really long lens.
Since long lenses have the effect of flattening perspective a bit, using a long lens helped make the ships feel huge compared to the robots.
At this point I was just doing very rough, quick, AO render “sketches”.
This is the AO sketch where my eventual final idea started:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_015.jpg"&gt;&lt;img alt="Figure 6: Rough AO render &amp;quot;sketch&amp;quot; that eventually evolved into my final idea." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_015.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;I’ve always loved the idea of the mundane fantastical; the flying scifi ship model is fairly fantastical, which led me to want to do something more everyday with them.
I thought it would be fun to texture the scifi ship model as if it was just part of a regular metro system that the robots use to get around their world.
My wife, Harmony, suggested a fun idea: set the entire scene in drizzly weather and give two of the robots umbrellas, but give the third robot a briefcase instead and have the robot use the briefcase as a makeshift umbrella, as if it had forgotten its umbrella at home.
The umbrella-less robot’s reaction to seeing the ship arriving provided the title for my entry- “Oh Good, The Bus Is Here”.
Harmony also pointed out that the back of the ship has a lot more interesting geometric detail compared to the front of the ship, and suggested placing the focus of the composition more on the robots than on the ships.
To incorporate all of these ideas, I played more with the layout and framing until I arrived at the following image, which is broadly the final layout I used:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_019.jpg"&gt;&lt;img alt="Figure 7: Rough AO render &amp;quot;sketch&amp;quot; of my final layout." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_019.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;I chose to put an additional ship in the background flying away from the dock for two main reasons.
First, I wanted to be able to showcase more of the ship, since the front ship is mostly obscured by the foreground dock.
Second, the background ship helps fill out and balance the right side of the frame more, which would otherwise have been kind of empty.&lt;/p&gt;

  &lt;p&gt;In both this project and in the previous Art Challenge, my workflow for assembling the final scene relies heavily on Maya’s referencing capabilities.
Each separate asset is kept in its own .ma file, and all of the .ma files are referenced into the main scene file.
The only the things the main scene file contains are references to assets, along with scene-level lighting, overrides, and global-scale effects such as volumes and, in the case of this challenge, the rain streaks.
So, even though the flying scifi ship appears in my scene twice, it is actually just the same .ma file referenced into the main scene twice instead of two separate ships.&lt;/p&gt;

  &lt;p&gt;The idea of a rainy scene largely drove the later lighting direction of my entry; from this point I basically knew that the final scene was going to have to be overcast and drizzly, with a heavy reliance on volumes to add depth separation into the scene and to bring out practical lights on the ships.
I had a lot of fun modeling out the dock and gangway, and may have gotten slightly carried away.
I modeled every single bolt and rivet that you would expect to be there in real life, and I also added lampposts to use later as practical light sources for illuminating the dock and the robots.
Once I had finished modeling the dock and had made a few more layout tweaks, I arrived at a point where I was happy to start with shading and initial light blocking.
Zoom in if you want to see all of the rivets and bolts and stuff on the dock:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_032.jpg"&gt;&lt;img alt="Figure 8: AO render of my layout going into shading and lighting. Check out all of the crazy detail on the dock that I modeled!" src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/progress_032.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-uv-unwrapping"&gt;&lt;/div&gt;
  &lt;h2 id="uv-unwrapping"&gt;UV Unwrapping&lt;/h2&gt;

  &lt;p&gt;UV unwrapping the ship took a ton of time.
For the last challenge, I relied on a combination of manual UV unwrapping by hand in Maya and using &lt;a href="https://www.sidefx.com/tutorials/houdini-game-dev-tools-auto-uvs/"&gt;Houdini’s Auto UV SOP&lt;/a&gt;, but I found that the Auto UV SOP didn’t work as well on this challenge due to the ship and robot having a lot of strange geometry with really complex topology.
On the treehouse in the last challenge, everything was more or less some version of a cylinder or a rectangular prism, with some morphs and warps and extra bits and bobs applied.
Almost every piece of the ship aside from the floorboards are very complex shapes that aren’t easy to find good seams for, so the Auto UV SOP wound up making a lot of choices for UV cuts that I didn’t like.
As a result, I basically manually UV unwrapped this entire challenge in Maya.&lt;/p&gt;

  &lt;p&gt;A lot of the complex undercarriage type stuff around the back thrusters on the ship was really insane to unwrap.
The muffler manifold and mechanical parts of the crane arm were difficult too.
Fortunately though, the models came with subdivision creases, and a lot of the subd crease tags wound up proving to be useful hints towards good places to place UV edge cuts.
I also found that the new and improved UV tools in Maya 2020 performed way better than the UV tools in Maya 2019.
For some meshes, I manually placed UV cuts and then used the unfold tool in Maya 2020, which I found generally worked a lot better than Maya 2019’s version of the same tool.
For other meshes, Maya 2020’s auto unwrap actually often provided a useful starting place as long a I rotated the piece I was unwrapping into a more-or-less axis-aligned orientation and froze its transform.
After using the auto-unwrap tool, I would then transfer the UVs back onto the piece in its original orientation using Maya’s Mesh Transfer Attributes tool.
The auto unwrap tended to cut meshes into too many UV islands, so I would then re-stitch islands together and place new cuts where appropriate.&lt;/p&gt;

  &lt;p&gt;When UV unwrapping, a good test to see how good the resultant UVs are is to assign some sort of a checkerboard grid texture to the model and look for distortion in the checkerboard pattern.
Overall I think I did an okay job here; not terrible, but could be better.
I think I managed to hide the vast majority of seams pretty well, and the total distortion isn’t too bad (if you look closely, you’ll be able to pick out some less than perfect areas, but it was mostly okay).
I wound up with a high degree of variability in the grid size between different areas, but I wasn’t too worried about that since my plan was to adjust texture resolutions to match.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/ship_uvs.jpg"&gt;&lt;img alt="Figure 9: Checkerboard test for my UV unwrapping of the scifi ship." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/ship_uvs.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;After UV unwrapping the ship, UV unwrapping the robot proved to be a lot easier in comparison.
Many parts of the robot turn out to be the same mesh just duplicated and squash/stretch/scaled/rotated, which means that they share the same underlying topology.
For all parts that share the same topology, I was able to just UV unwrap one of them, and then copy the UVs to all of the others.
One great example is the robot’s fingers; most components across all fingers shared the same topology.
Here’s the checkerboard test applied to my final UVs for the robot:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/robot_uvs.jpg"&gt;&lt;img alt="Figure 10: Checkerboard test for my UV unwrapping of the robot." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/robot_uvs.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-texturing-the-ship"&gt;&lt;/div&gt;
  &lt;h2 id="texturing-the-ship"&gt;Texturing the Ship&lt;/h2&gt;

  &lt;p&gt;After trying out Substance Painter for the previous RenderMan Art Challenge and getting fairly good results, I went with Substance Painter again on this project.
The overall texturing workflow I used on this project was actually a lot simpler compared with the workflow I used for the previous Art Challenge.
Last time I tried to leave a lot of final decisions about saturation and hue and whatnot as late as possible, which meant moving those decisions into the shader so that they could be changed at render-time.
This time around, I decided to make those decisions upfront in Substance Painter; doing so makes the Substance Painter workflow much simpler since it means I can just paint colors directly in Substance Painter like a normal person would, as opposed to painting greyscale or desaturated maps in Substance Painter that are expected to be modulated in the shader later.
Also, because of the nature of the objects in this project, I actually used very little displacement mapping; most detail was brought in through normal mapping, which makes more sense for hard surface metallic objects.
Not having to worry about any kind of displacement mapping simplified the Substance Painter workflow a bit more too, since that was one fewer texture map type I had to worry about managing.&lt;/p&gt;

  &lt;p&gt;One the last challenge I relied on a lot of Quixel Megascans surfaces as starting points for texturing, but this time around I (unintentionally) found myself relying on Substance smart materials more for starting points.
One thing I like about Substance Painter is how it comes with a number of good premade smart materials, and there are even more good smart materials on Substance Source.
Importantly though, I believe that smart materials should only serve as a starting point; smart materials can look decent out-of-the-box, but to really make texturing shine, a lot more work is required on top of the out-of-the-box result in order to really create story and character and a unique look in texturing.
I don’t like when I see renders online where a smart material was applied and left in its out-of-the-box state; something gets lost when I can tell which default smart material was used at a glance!
For every place that I used a smart material in this project, I used a smart material (or several smart materials layered and kitbashed together) as a starting point, but then heavily customized on top with custom paint layers, custom masking, decals, additional layers, and often even heavy custom modifications to the smart material itself.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/substance_screenshot.png"&gt;&lt;img alt="Figure 11: Texturing the main piece of the ship's hull in Substance Painter." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/substance_screenshot.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;I was originally planning on using a UDIM workflow for bringing the ship into Substance Painter, but I wound up with so many UDIM tiles that things quickly became unmanageable and Substance Painter ground to a halt with a gigantic file containing 80 (!!!) 4K UDIM tiles.
To work around this, I broke up the ship into a number of smaller groups of meshes and brought each group into Substance Painter separately.
Within each group I was able to use a UDIM workflow with usually between 5 to 10 tiles.&lt;/p&gt;

  &lt;p&gt;I had a lot of fun creating custom decals to apply to various parts of the ships and to some of the robots; even though a lot of the details and decals aren’t very visible in the final image, I still put a good amount of time into making them simply to keep things interesting for myself.
All of the decals were made in Photoshop and Illustrator and then brought in to Substance Painter along with opacity masks and applied to surfaces using Substance Painter’s projection mode, either in world space or in UV space depending on situation.
In Substance Painter, I created a new layer in with a custom paint material and painted the base color for the paint material by projecting the decal, and then masked the decal layer using the opacity mask I made using the same projection that I used for the base color.
The “Seneca” logo seen throughout my scene has &lt;a href="https://blog.yiningkarlli.com/2016/07/minecraft-in-renderman-ris.html"&gt;shown up on my blog before&lt;/a&gt;!
A few years ago on a Minecraft server that I played a lot on, a bunch of other players and I had a city named Seneca; ever since then, I’ve tried to sneak in little references to Seneca in projects here and there as a small easter egg.&lt;/p&gt;

  &lt;p&gt;Many of the buses around where I live have an orange and silver color scheme, and while I was searching the internet for reference material, I also found pictures of the Glasgow Subway’s trains, which have an orange and black and white color scheme.
Inspired by the above, I picked an orange and black color scheme for the ship’s Seneca Metro livery.
I like orange as a color, and I figured that orange would bring a nice pop of color to what was going to be an overall relatively dark image,
I made the upper part of the hull orange but kept the lower part of the hull black since the black section was going to be the backdrop that the robots would be in front of in the final image; the idea was that keeping that part of the hull darker would allow the robots to pop a bit more visually.&lt;/p&gt;

  &lt;p&gt;One really useful trick I used for masking different materials was to just follow edgeloops that were already part of the model.
Since everything in this scene is very mechanical anyway, following straightedges in the UVs helps give everything a manufactured, mechanical look.
For example, Figure 12 shows how I used Substance Painter’s Polygon Fill tool to mask out the black paint from the back metal section of the ship’s thrusters.
In some other cases, I added new edgeloops to the existing models just so I could follow the edgeloops while masking different layers.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/substance_uvmask.png"&gt;&lt;img alt="Figure 12: Masking in the metal section of the ship's thrusters by following existing edgeloops using Substance Painter's Polygon Fill tool." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/substance_uvmask.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-shading-the-ship"&gt;&lt;/div&gt;
  &lt;h2 id="shading-the-ship"&gt;Shading the Ship&lt;/h2&gt;

  &lt;p&gt;For the previous Art Challenge, I used a combination of PxrDisney and PxrSurface shaders; this time around, in order to get a better understanding of how PxrSurface works, I opted to go all-in on using PxrSurface for everything in the scene.
Also, for the rain streaks effect (discussed later in this post), I needed some features that are available in the extended Disney Bsdf model &lt;a href="https://doi.org/10.1145/2776880.2787670"&gt;[Burley 2015]&lt;/a&gt; and in PxrSurface &lt;a href="http://graphics.pixar.com/library/PxrMaterialsCourse2017/index.html"&gt;[Hery et al. 2017]&lt;/a&gt;, but RenderMan 23 only implements the base Disney Brdf &lt;a href="https://doi.org/10.1145/2343483.2343493"&gt;[Burley 2012]&lt;/a&gt; without the extended Bsdf features; this basically meant I had to use PxrSuface.&lt;/p&gt;

  &lt;p&gt;One of the biggest differences I had to adjust to was how metallic color is controlled in PxrSurface.
The Disney Bsdf drives the diffuse color and metallic color using the same base color parameter and shifts energy between the diffuse/spec and metallic lobes using a “metallic” parameter, but PxrSurface separates the diffuse and metallic colors entirely.
PxrSurface uses a “Specular Face Color” parameter to directly drive the metallic lobe and has a separate “Specular Edge Color” control; this parameterization reminds me a lot of Framestore’s artist-friendly metallic fresnel parameterization &lt;a href="http://jcgt.org/published/0003/04/03/"&gt;[Gulbrandsen 2014]&lt;/a&gt;, but I don’t know if this is actually what PxrSurface is doing under the hood.
PxrSurface also has two different modes for its specular controls: an “artistic” mode and a “physical” mode; I only used the artistic mode.
To be honest, while PxrSurface’s extensive controls are extremely powerful and offer an enormous degree of artistic control, I found trying to understand what every control did and how they interacted with each other to be kind of overwhelming.
I wound up paring back the set of controls I used back to a small subset that I could mentally map back to what the Disney Bsdf or VRayMtl or Autodesk Standard Surface &lt;a href="https://autodesk.github.io/standard-surface/"&gt;[Georgiev et al. 2019]&lt;/a&gt; models do.&lt;/p&gt;

  &lt;p&gt;Fortunately, converting from the Disney Bsdf’s baseColor/metallic parameterization to PxrSurface’s diffuse/specFaceColor is very easy:&lt;/p&gt;

  &lt;div&gt;\[ diffuse = baseColor * (1 - metallic) \\ specFaceColor = baseColor * metallic \]&lt;/div&gt;

  &lt;p&gt;The only gotcha to look out for is that everything needs to be in linear space first.
Alternatively, Substance Painter already has a output template for PxrSurface as well.
Once I had the maps in the right parameterization, for the most part all I had to do was plug the right maps into the right parameters in PxrSurface and then make minor manual adjustments to dial in the look.
In addition to two different specular parameterization modes, PxrSurface also supports choosing from a few different microfacet models for the specular lobes; by default PxrSurface is set to use the Beckmann model &lt;a href="https://us.artechhouse.com/The-Scattering-of-Electromagnetic-Waves-from-Rough-Surfaces-P257.aspx"&gt;[Beckmann and Spizzichino 1963]&lt;/a&gt;, but I selected the GGX model &lt;a href="http://dx.doi.org/10.2312/EGWR/EGSR07/195-206"&gt;[Walter et al. 2007]&lt;/a&gt; for everything in this scene since GGX is what I’m more used to.&lt;/p&gt;

  &lt;p&gt;For the actual look of the ship, I didn’t want to go with the dilapidated look that a lot of the other contestants went with.
Instead, I wanted the ship to look like it was a well maintained working vehicle, but with all of the grime and scratches that build up over daily use.
So, there are scratches and dust and dirt streaks on the boat, but nothing is actually rusting.
I also did modeled some glass for the windows at the top of the tower superstructure, and added some additional lamps to the top of the ship’s masts and on the tower superstructure for use in lighting later.
After getting everything dialed, here is the “dry” look of the ship:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/ship_shading_progress_angle3_31.png"&gt;&lt;img alt="Figure 13: Fully shaded &amp;quot;dry&amp;quot; look for the ship." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/ship_shading_progress_angle3_31.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Here’s a close-up render of the back engine section of the ship, which has all kinds of interesting bits and bobs on it.
The engine exhaust kind of looks like it could be a volume, but it’s not.
I made the engine exhaust by making a bunch of cards, arranging them into a truncated cone, and texturing them with a blue gradient in the diffuse slot and a greyscale gradient in PxrSurface’s “presence” slot.
The glow effect is done using the glow parameter in PxrSurface.
The nice thing about using this more cheat-y approach instead of a real volume is that it’s way faster to render!&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/ship_shading_progress_angle2_23.png"&gt;&lt;img alt="Figure 14: Fully shaded &amp;quot;dry&amp;quot; look for the back engine area of the ship." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/ship_shading_progress_angle2_23.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Most of the ship’s metal components are covered over using a black, semi-matte paint material, but in areas that I thought would be subjected to high temperatures, such as exhaust vents or the inside of the thrusters or the many floodlights on the ship, I chose to use a beaten copper material instead.
Basically wherever I wound up placing a practical light, the housing around the practical light is made of beaten copper.
Well, I guess it’s actually some kind of high-temperature copper alloy or copper-colored composite material, since real copper’s melting point is lower than real steel’s melting point.
The copper color had an added nice effect of making practical lights look more yellow-orange, which I think helps sell the look of engine thrusters and hot exhaust vents more.&lt;/p&gt;

  &lt;p&gt;Each exhaust vent and engine thruster actually contains two practical lights: one extremely bright light near the back of the vent or thruster pointing into the vent or thruster, and one dimmer but more saturated light pointing outwards.
This setup produces a nice effect where areas deeper into the vent or thruster look brighter and yellower, while areas closer to the outer edge of the vent or thruster look a bit dimmer and more orange.
The light point outwards also casts light outside of the vent or thruster, providing some neat illumination on nearby surfaces or volumes.
Later in this post, I’ll write more about how I made use of this in the final image.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/ship_shading_progress_angle4_07.png"&gt;&lt;img alt="Figure 15: Wide view of the back of the ship, showing the practical lights in the ship's various engine thrusters and exhaust vents." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/ship_shading_progress_angle4_07.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Here’s a turntable video of the ship, showcasing all of the texturing and shading that I did.
I had a lot of fun taking care of all of the tiny details that are part of the ship, even though many of them aren’t actually visible in my final image.
The dripping wet rain effect is discussed later in this post.&lt;/p&gt;

  &lt;div class="embed-container"&gt;Shipshape Art Challenge Ship Turntable&lt;/div&gt;
  &lt;div class="figcaption"&gt;&lt;span&gt;Figure 16: Turntable of the ship showing both dry and wet variants.&lt;/span&gt;&lt;/div&gt;

  &lt;div id="2020-07-31-shading-and-texturing-the-robots"&gt;&lt;/div&gt;
  &lt;h2 id="shading-and-texturing-the-robots"&gt;Shading and Texturing the Robots&lt;/h2&gt;

  &lt;p&gt;For the robots, I used the same Substance Painter based texturing workflow and the same PxrSurface based shading workflow that I used for the ship.
However, since the robot has far fewer components than the ship, I was able to bring all of the robot’s UDIM tiles into Substance Painter at once.
The main challenge with the robots wasn’t the sheer quantity of parts that had to be textured, but instead was in the variety of robot color schemes that had to be made.
In order to populate the scene and give my final image a sense of life, I wanted to have a lot of robots on the ships, and I wanted all of the robots to have different paint and color schemes.&lt;/p&gt;

  &lt;p&gt;I knew from an early point that I wanted the robot carrying the suitcase to be yellow, and I knew I wanted a robot in some kind of conductor’s uniform, but aside from that, I didn’t much pre-planned for the robot paint schemes.
As a result, coming up with different robot paint schemes was a lot of fun and involved a lot of just goofing around and improvisation in Substance Painted until I found ideas that I liked.
To help unify how all of the robots looked and to help with speeding up the texturing process, I came up with a base metallic look for the robot’s legs and arms and various functional mechanical parts.
I alternated between steel and copper parts to help bring some visual variety to all of the mechanical parts.
The metallic parts are the same across all of the robots; the parts that vary between robots are the body shell and various outer casing parts on the arms:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/yellow_bot.jpg"&gt;&lt;img alt="Figure 17: Robot with steel and copper mechanical parts and yellow outer shell." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/yellow_bot.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;I wanted very different looks for the other two robots that are on the dock with the yellow robot.
I gave one of them a more futuristic looking white glossy shell with a subtle hexagon imprint pattern and red accents.
The hexagon imprint pattern is created using a hexagon pattern in the normal map.
The red stripes use the same edgeloop-following technique that I used for masking some layers on the ship.
I made the other robot a matte green color, and I thought it would be fun make him into a sports fan.
He’s wearing the logo and colors of the local in-world sports team, the Seneca Senators!
Since the robots don’t wear clothes per se, I guess maybe the sports team logo and numbers are some kind of temporary sticker?
Or maybe this robot is such a bit fan that he had the logo permanently painted on… I don’t know!
Since I knew these two robots would be seen from the back in the final image, I made sure to put all of the interesting stuff on their sides and back.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/white_bot.jpg"&gt;&lt;img alt="Figure 18: Futuristic robot with glossy white outer shell and red accents." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/white_bot.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/green_bot.jpg"&gt;&lt;img alt="Figure 19: Sports fan robot wearing the colors of the in-world team, the Seneca Senators." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/green_bot.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;For the conductor robot, I chose a blue and gold color scheme based on real world conductor uniforms I’ve seen before.
I made the conductor robot overall a bit more cleaned up compared to the other robots, since I figured the conductor robot should look a bit more crisp and professional.
I also gave the conductor robot a gold mustache, for a bit of fun!
To complete the look, I modeled a simple conductor’s hat for the conductor robot to wear.
I also made a captain robot, which has a white/black/gold color scheme derived from the conductor robot.
The white/black/gold color scheme is based on old-school ship’s captain uniforms.
The captain robot required a bit of a different hat from the conductor hat; I made the captain hat a little bigger and a little bit more elaborate, complete with gold stitching on the front around the Seneca Metro emblem.
In the final scene you don’t really see the captain robots, since they wound up inside of the wheelhouse at the top of the ship’s tower superstructure, but hey, at least the captain robots were fun to make, and at least I know that they’re there!&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/conductor_bot.jpg"&gt;&lt;img alt="Figure 20: Conductor robot with a blue and gold color scheme and a hat!" src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/conductor_bot.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/captain_bot.jpg"&gt;&lt;img alt="Figure 21: Captain robot with a white and black and gold color scheme and an even fancier hat." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/captain_bot.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;As a bit of a joke, I tried making a poncho for one of the robots.
I thought it would look very silly, which for me was all the more reason to try!
To make the poncho, I made a big flat disc in Maya and turned it into nCloth, and just let it fall onto the robot with the robot’s geometry acting as a static collider.
This approach basically worked out-of-the-box, although I made some manual edits to the geometry afterwards just to get the poncho to billow a bit more on the bottom.
The poncho’s shader is a simple glass PxrSurface shader, with the bottom frosted section and smooth diamond-shaped window section both driven using just roughness.
The crinkly plastic sheet appearance is achieved entirely through a wrinkle normal map.
The poncho bot is also not really visible in the final image, but somewhere in the final image, this robot is in the background on the deck of the front ship behind some other robots!&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/poncho_bot.jpg"&gt;&lt;img alt="Figure 22: Robot wearing a clear plastic poncho." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/poncho_bot.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Don’t worry, I didn’t forget about the fact that the robots have antennae!
For the poncho robot, I modeled a hole into the poncho for the antenna to pass through, and I modeled similar holes into the captain robot and conductor robot’s hats as well.
Again, this is a detail that isn’t visible in the final image at all, but is there mostly just so that I can know that it’s there:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/poncho_antenna_hole.png"&gt;&lt;img alt="Figure 23: Antenna pass-through hole modeled into the poncho." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/poncho_antenna_hole.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;In total I created 12 different unique robot variants, which some variants duplicated in the final image.
All 12 variants are actually present in the scene!
Most of them are in the background (and a few variants are only on the background ship), so most of them aren’t very visible in the final image.
You, the reader, have probably noticed a theme in this post now where I put a lot of effort into things that aren’t actually visible in the final image… for me, a large part of this project wasn’t necessarily about the final image and was instead just about having fun and getting some practice with the tools and workflows.&lt;/p&gt;

  &lt;p&gt;Here is a turntable showcasing all 12 robot variants.
In the turntable, only the yellow robot has both a wet and dry variant, since all of the other robots in the scene remembered their umbrellas and were therefore able to stay dry.
The green sports fan robot does have a variant with a wet right arm though, since in the final image the green sports fan robot’s right arm is extended beyond the umbrella to wave at the incoming ship.&lt;/p&gt;

  &lt;div class="embed-container"&gt;Shipshape Art Challenge Robots Turntable&lt;/div&gt;
  &lt;div class="figcaption"&gt;&lt;span&gt;Figure 24: Turntable of the robots, with all 12 robot variants.&lt;/span&gt;&lt;/div&gt;

  &lt;div id="2020-07-31-the-wet-shader"&gt;&lt;/div&gt;
  &lt;h2 id="the-wet-shader"&gt;The Wet Shader&lt;/h2&gt;

  &lt;p&gt;Going into the shading process, the single problem that worried me the most was how I was going to make everything in the rain look wet.
Having a good wet look is extremely important for selling the overall look of a rainy scene.
I actually wasn’t too worried about the base dry shading, since hard metal/plastic surfaces are one of the things that CG is really good at by default.
By contrast, getting a good wet rainy look took an enormous amount of experimentation and effort, and wound up even involving some custom tools.&lt;/p&gt;

  &lt;p&gt;From a cursory search online, I found some techniques for creating a wet rainy look that basically work by modulating the primary specular lobe and applying a normal map to the base normal of the surface.
However, I didn’t really like how this looked; in some cases, this approach basically makes it look like the underlying surface itself has rivulets and dots in it, not like there’s water running on top of the surface.
My hunch was to use PxrSurface’s clearcoat lobe instead, since from a physically motivated perspective, water streaks and droplets behave more like an additional transparent refractive coating layer on top of a base surface.
A nice bonus from trying to use the clearcoat lobe is that PxrSurface supports using different normal maps for each specular lobe; this way, I could have a specific water droplets and streaks normal map plugged into the bump normal parameter for the clearcoat lobe without having to disturb whatever normal map I had plugged into the bump normal parameter to the base diffuse and primary specular lobes.
My idea was to create a single shading graph for creating the wet rainy look, and then plug this graph into the clearcoat lobe parameters for any PxrSurface that I wanted a wet appearance for.
Here’s what the final graph looked like:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/wetshader_graph.png"&gt;&lt;img alt="Figure 25: Shading graph for creating the wet rainy look. This graph plugs into the clearcoat parameters of any shader that I wanted to have a wet appearance." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/wetshader_graph.png" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;In the graph above, note how the input textures are fed into PxrRemap nodes for ior, edge color, thickness, and roughness; this is so I can rescale the 0-1 range inputs from the textures to whatever they need to be for each parameter.
The node labeled “mastercontrol” allows for disabling the entire wet effect by feeding 0.0 into the clearcoat edge color parameter, which effectively disables the clearcoat lobe.&lt;/p&gt;

  &lt;p&gt;Having to manually connect this graph into all of the clearcoat parameters in each PxrSurface shader I used was a bit of a pain.
Ideally I would have preferred if I could have just plugged all of the clearcoat parameters into a PxrLayer, disabled all non-clearcoat lobes in the PxrLayer, and then plugged the PxrLayer into a PxrLayerSurface on top of underlying base layers.
Basically, I wish PxrLayerSurface supported enabling/disabling layers on a per-lobe basis, but this ability currently doesn’t exist in RenderMan 23.
In Disney’s Hyperion Renderer, we support this functionality for sparsely layering Disney Bsdf parameters &lt;a href="https://doi.org/10.1145/2776880.2787670"&gt;[Burley 2015]&lt;/a&gt;, and it’s really really useful.&lt;/p&gt;

  &lt;p&gt;There are only four input maps required for the entire wet effect: a greyscale rain rivulets map, a corresponding rain rivulets normal map, a greyscale droplets map, and a corresponding droplets normal map.
The rivulets maps are used for the sides of a PxrRoundCube projection node, while the droplets maps are used for the top of the PxrRoundCube projection node; this makes the wet effect look more like rain drop streaks the more vertical a surface is, and more like droplets splashing on a surface the more horizontal a surface is.
Even though everything in my scene is UV mapped, I chose to use PxrRoundCube to project the wet effect on everything in order to make the wet effect as automatic as possible; to make sure that repetitions in the wet effect textures weren’t very visible, I used a wide transition width for the PxrRoundCube node and made sure that the PxrRoundCube’s projection was rotated around the Y-axis to not be aligned with any model in the scene.&lt;/p&gt;

  &lt;p&gt;To actually create the maps, I used a combination of Photoshop and a custom tool that I originally wrote for Takua Renderer.
I started in Photoshop by kit-bashing together stuff I found online and hand-painting on top to produce a 1024 by 1024 pixel square example map with all of the characteristics I wanted.
While in Photoshop, I didn’t worry about making sure that the example map could tile; tiling comes in the next step.
After initial work in Photoshop, this is what I came up with:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/painted_wetmask.jpg"&gt;&lt;img alt="Figure 26: Initial kit-bashed / hand-painted exemplars for streak and droplet wet maps." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/painted_wetmask.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Next, to make the maps repeatable and much larger, I used a custom tool I previously wrote that implements a practical form of histogram-blending hex tiling &lt;a href="http://jcgt.org/published/0008/04/02/"&gt;[Burley 2019]&lt;/a&gt;.
Hex tiling with histogram preserving blending, originally introduced by &lt;a href="https://doi.org/10.1145/3233304"&gt;Heitz and Neyret [2018]&lt;/a&gt;, is one of the closest things to actual magic in recent computer graphics research; using hex tiling instead of normal rectilinear tiling basically completely hides obvious repetitions in the tiling from the human eye, and the histogram preserving blending makes sure that hex tile boundaries blend in a way that makes them completely invisible as well.
I’ll write more about hex tiling and make my implementation publicly available in a future post.
What matters for this project is hex tiling allowed me to convert my exemplar map from Photoshop into a much larger 8K seamlessly repeatable texture map with no visible repetition patterns.
Below is a cropped section from each 8K map:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/hextiled_wetmask.jpg"&gt;&lt;img alt="Figure 27: Crops from the 8K wet maps generated from the exemplar maps using my custom implementation of histogram-blending hex tiling." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/hextiled_wetmask.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;For the previous Art Challenge, I also made some custom textures that had to be tileable.
Last time though, I used Substance Designer to make the textures tileable, which required setting up a big complicated node graph and produced results where obvious repetition was still visible.
Conversely, hex tiling basically works automatically and doesn’t require any kind of manual setup or complex graphs or anything.&lt;/p&gt;

  &lt;p&gt;To generate the normal maps, I used Photoshop’s “Generate Normal Map” filter, which is found under “Filter &amp;gt; 3D”.
For generating normal maps from simple greyscale heightmaps, this Photoshop feature works reasonably well.
Because of the deterministic nature of the hex tiling implementation though, I could have also generated normal maps from the grey scale exemplars and then fed the normal map exemplars through the hex tiling tool with the same parameters as how I fed in the greyscale maps, and I would have gotten the same result as below.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/hextiled_normals.jpg"&gt;&lt;img alt="Figure 28: Crops from the 8K wet map normals generated using Photoshop's &amp;quot;Generate Normal Map&amp;quot; filter tool." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/hextiled_normals.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;For the wet effect’s clearcoat lobe, I chose to use the physical mode instead of the artistic mode (unlike for the base dry shaders, where I only used the artistic mode).
The reason I used the physical mode for the wet effect is because of the layer thickness control, which darkens the underlying base shader according to how thick the clearcoat layer is supposed to be. I wanted this effect, since wet surfaces appear darker than their dry counterparts in real life.
Using the greyscale wet map, I modulated the layer thickness control according to how much water there was supposed to be at each part of the surface.&lt;/p&gt;

  &lt;p&gt;Finally, after wiring everything together in Maya’s HyperShade editor, everything just worked!
I think the wet look my approach produces looks reasonable convincing, especially from the distances that everything is from the camera in my final piece.
Up close the effect still holds up okay, but isn’t as convincing as using real geometry for the water droplets with real refraction and caustics drive by manifold next event estimation &lt;a href="http://dx.doi.org/10.1111/cgf.12681"&gt;[Hanika et al. 2015]&lt;/a&gt;.
In the future, if I need to do close up water droplets, I’ll likely try an MNEE based approach instead; fortunately, RenderMan 23’s PxrUnified integrator already comes with an MNEE implementation as an option, along with various other strategies for handling caustic cases &lt;a href="http://graphics.pixar.com/library/BiDir/"&gt;[Hery et al. 2016]&lt;/a&gt;. 
However, the approach I used for this project is far cheaper from a render time perspective compare to using geometry and MNEE, and from a mid to far distance, I’m pretty happy with how it turned out!&lt;/p&gt;

  &lt;p&gt;Below are some comparisons of the ship and robot with and without the wet effect applied.
The ship renders are from the same camera angles as in Figures 13, 14, and 15. drag the slider left and right to compare:&lt;/p&gt;

&lt;/div&gt;

&lt;div class="embed-container" id="wideship_wetdrycompare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 29: Wide view of the ship with (left) and without (right) the wet shader applied. For a full screen comparison, &lt;a href="/content/images/2020/Jul/shipshape/comparisons/wideship_wetdrycompare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;

&lt;div class="embed-container" id="backship_wetdrycompare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 30: Back view of the ship with (left) and without (right) the wet shader applied. For a full screen comparison, &lt;a href="/content/images/2020/Jul/shipshape/comparisons/backship_wetdrycompare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;

&lt;div class="embed-container" id="sideship_wetdrycompare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 31: Side view of the ship with (left) and without (right) the wet shader applied. For a full screen comparison, &lt;a href="/content/images/2020/Jul/shipshape/comparisons/sideship_wetdrycompare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;

&lt;div class="embed-container" id="robot_wetdrycompare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 32: Main yellow robot with (left) and without (right) the wet shader applied. For a full screen comparison, &lt;a href="/content/images/2020/Jul/shipshape/comparisons/robot_wetdrycompare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;

&lt;div&gt;

  &lt;div id="2020-07-31-additional-props-and-elements"&gt;&lt;/div&gt;
  &lt;h2 id="additional-props-and-set-elements"&gt;Additional Props and Set Elements&lt;/h2&gt;

  &lt;p&gt;In addition to texturing and shading the flying scifi ship and robot models, I had to create from scratch several other elements to help support the story in the scene.
By far the single largest new element that had to be created was the entire dock structure that the robots stand on top of.
As mentioned earlier, I wound up modeling the dock to a fairly high level of detail; the dock model contains every single bolt and rivet and plate that would be necessary for holding together a similar real steel frame structure.
Part of this level of detail is justifiable by the fact that the dock structure is in the foreground and therefore relatively close to camera, but part of having this level of detail is just because I could and I was having fun while modeling.
To model the dock relatively quickly, I used a modular approach where I first modeled a toolkit of basic reusable elements like girders, connection points, bolts, and deckboards.
Then, from these basic elements, I assembled larger pieces such as individual support legs and crossbeams and such, and then I assembled these larger pieces into the dock itself.&lt;/p&gt;

  &lt;p&gt;Shading the dock was relatively fast and straightforward; I created a basic galvanized metal material and applied it using a PxrRoundCube projection.
To get a bit more detail and break up the base material a bit, I added a dirt layer on top that is basically just low-frequency noise multiplied by ambient occlusion.
I did have to UV map the gangway section of the dock in order to add the yellow and black warning stripe at the end of the gangway; however, since the dock is made up almost entirely of essentially rectangular prisms oriented at 90 degree angles to each other, just using Maya’s automatic UV unwrapping provided something good enough to just use as-is.
The yellow and black warning stripe uses the same thick worn paint material that the warning stripes on the ship uses.
On top of all of this, I then applied my wet shader clearcoat lobe.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/dock_wide.png"&gt;&lt;img alt="Figure 33: Shading test for the dock, with wet effect applied. The lampposts are in a different orientation compared to where they are in the final scene." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/dock_wide.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;The metro sign on the dock is just a single rectangular prism with a dark glass material applied.
The glowing text is a color texture map plugged into PxrSurface’s glow parameter; whereever there is glowing text, I also made the material diffuse instead of glass, with the diffuse color matching the glow color.
To balance the intensity of the glow, I had to cheat a bit; turning the intensity of the glow down enough so that the text and colors read well means that the glow is no longer bright enough to show up in reflections or cast enough light to show up in a volume.
My solution was to turn down the glow in the PxrSurface shader, and then add a PxrRectLight immediately in front of the metro sign driven by the same texture map.
The PxrRectLight is set to be invisible to the camera.
I suppose I could have done this in post using light path expressions, but cheating it this way was simpler and allowed for everything to just look right straight out of the render.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/dock_closeup.png"&gt;&lt;img alt="Figure 34: Closeup test of the metro sign on the dock." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/dock_closeup.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;The suitcase was a really simple prop to make.
Basically it’s just a rounded cube with some extra bits stuck on to it for the handles and latch; the little rivets are actually entirely in shading and aren’t part of the geometry at all.
I threw on a basic burlap material for the main suitcase, multiplied on some noise to make it look a bit dirtier and worn, and applied basic brass and leather materials to the latch and handle, and that was pretty much it.
Since the suitcase was going to serve as the yellow robot’s makeshift umbrella, making sure that the suitcase looked good with the wet effect applied turned out to be really important.
Here’s a lookdev test render of the suitcase, with and without the wet effect applied (slide left and right to compare):&lt;/p&gt;

&lt;/div&gt;

&lt;div class="embed-container" id="suitcase_wetdrycompare"&gt;
&lt;/div&gt;
&lt;div class="figcaption"&gt;&lt;span&gt;Figure 35: Suitcase with (left) and without (right) the wet shader applied. For a full screen comparison, &lt;a href="/content/images/2020/Jul/shipshape/comparisons/suitcase_wetdrycompare.html"&gt;click here.&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;

&lt;div&gt;

  &lt;p&gt;From early on, I was fairly worried about making the umbrellas look good; I knew that making sure the the umbrellas looked convincingly wet was going to be really important for selling the overall rainy day setting.
I originally was going to make the umbrellas opaque, but realized that opaque umbrellas were going to cast a lot of shadows and block out a lot of parts of the frame.
Switching to transparent umbrellas made out of clear plastic helped a lot with brightening up parts of the frame and making sure that large parts of the ship weren’t completely blocked out in the final image.
As a bonus, I think the clear umbrellas also help the overall setting feel slightly more futuristic.
I modeled the umbrella canopy as a single-sided mesh, so the “thin” setting in PxrSurface’s glass parameters was really useful here.
Since the umbrella canopy is transparent with refraction roughness, having the wet effect work through the clearcoat lobe proved really important here since doing so allowed for the rain droplets and rivulets to have sharp specular highlights while simultaneously preserving the more blurred refraction in the underlying umbrella canopy material.
In the end, lighting turned out to be really important for selling the look of the wet umbrella as well; I found that having tons of little specular highlights coming from all of the rain drops helped a lot.&lt;/p&gt;

  &lt;p&gt;As a bit of an aside, settling on a final umbrella canopy shape took a surprising amount of time!
I started with a much flatter umbrella canopy, but eventually made it more bowed after looking at various umbrellas I have sitting around at home.
Most clear umbrella references I found online are of these Japanese bubble umbrellas which are actually far more bowed than a standard umbrella, but I wanted a shape that more closely matched a standard opaque umbrella.&lt;/p&gt;

  &lt;p&gt;One late addition I made to the umbrella was the small lip at the bottom edge of the umbrella canopies; for much of the development process, I didn’t have this small lip and kept feeling like something was off about the umbrellas.
I eventually realized that some real umbrellas have a bit of a lip to help catch and guide water runoff; adding this feature to the umbrellas helped them feel a bit more correct.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/umbrella.jpg"&gt;&lt;img alt="Figure 36: Lookdev test of the umbrella, with wet effect applied." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/umbrella.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Shortly before the due date for the final image, I made a last-minute addition to my scene: I took the sextant that came with Pixar’s base models and made the white/red robot on the dock hold it.
Since the green and yellow robots were both doing something a bit more dynamic than just standing around, I wanted the middle white/red robot to be doing something as well.
Maybe the white/red robot is going to navigation school!
I did a very quick-and-dirty shading job on the sextant using Maya’s automatic UVs; overall the sextant prop is not shaded to the same level of detail as most of the other elements in my scene, but considering how small the sextant is in the final image, I think it holds up okay.
I still tried to add a plausible amount of wear and age to the metal materials on the sextant, but I didn’t have time to put in carved numbers and decals and grippy textures and stuff.
There are also a few small areas where you can see visible texture stretching at UV seams, but again, in the final image, it didn’t matter too much.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/sextant.jpg"&gt;&lt;img alt="Figure 37: Quick n' dirty lookdev test of the sextant. Model is by Aliyah Chen and was provided by Pixar as one of the contest's base models." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/sextant.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-rain-fx"&gt;&lt;/div&gt;
  &lt;h2 id="rain-fx"&gt;Rain FX&lt;/h2&gt;

  &lt;p&gt;Having a good wet surface look was one half of getting my scene to look convincingly rainy; the other major problem to solve was making the rain itself!
My initial, extremely naive plan was to simulate all of the rainfall as one enormous FLIP sim in Houdini.
However, I almost immediately realized what a bad idea that was, due to the scale of the scene.
Instead, I opted to simulate the rain as nParticles in Maya.&lt;/p&gt;

  &lt;p&gt;To start, I first duplicated all of the geometry that I wanted the rain to interact with, combined it all into one single huge mesh, and then decimated the mesh heavily and simplified as much as I could.
This single mesh acted as a proxy for the full scene for use as a passive collider in the nParticles network.
Using a decimated proxy for the collider instead of the full scene geometry was very important for making sure that the sim ran fast enough for me to be able to get in a good number of different iterations and attempts to find the look that I wanted.
I mostly picked geometry that was upward facing for use in the proxy collider:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/rain_proxygeo.png"&gt;&lt;img alt="Figure 38: The proxy mesh I used for the rain nParticles sim. This is an earlier version of the proxy mesh before I settled on final scene geometry; the final sim was run with an updated proxy mesh made from the final scene geometry." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/rain_proxygeo.png" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Next, I set up a huge volume nParticle emitter node above the scene, covering the region visible in the camera frustum.
The only forces I set up were gravity and a small amount of wind, and then I ran the nParticles system and let it run until rain had filled all parts of the scene visible to the camera.
To give the impression of fast moving motion-blurred rain droplets, I set the rendering mode of the nParticles to ‘multistreak’, which makes each particle look like a set of lines with lengths varying according to velocity.
I had to play with the collider proxy mesh’s properties a bit to get the right amount of raindrops bouncing off of surfaces and to dial in how high raindrops bounced.
I initially tried allowing particles to collide with each other as well, but this slowed the entire sim down to basically a halt, so for the final scene I have particle-to-particle collision disabled.&lt;/p&gt;

  &lt;p&gt;After a couple of rounds of iteration, I started getting something that looked reasonably like rain!
Using the proxy collision geometry wa really useful for creating “rain shadows”, which are areas that rain isn’t present due to being stopped by something else.
I also tuned the wind speed a lot in order to get rain particles bouncing off of the umbrellas to look like they were being blown aside in the wind.
After getting a sim that I liked, I baked out the frame of the sim that I wanted for my final render using Maya’s nCache system, which caches the nParticle simulation to disk so that it can be rapidly loaded up later without having to re-run the entire simulation.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/rain_viewport.png"&gt;&lt;img alt="Figure 39: Closeup of a work-in-progress version of the rain sim. Note how the umbrellas properly block rain from falling on the robots under the umbrellas." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/rain_viewport.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;To add just an extra bit of detail and storytelling, near the end of the competition period I revisited my original idea for making the rain in Houdini using a FLIP solver.
I wanted to add in some “hero” rain drops around the foreground robots, running off of their umbrellas and suitcases and stuff.
To create these “hero” droplets, I brought the umbrella canopies and suitcase into Houdini and built a basic FLIP simulation, meshed the result, and brought it back into Maya to integrate back into the scene.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/houdini_rainsim.png"&gt;&lt;img alt="Figure 40: Using a FLIP simulation in Houdini to create some &amp;quot;hero&amp;quot; rain droplets running off of the umbrella canopies and suitcase." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/houdini_rainsim.png" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;Dialing in the look of the rain required a lot of playing with both the width of the rain drop streaks and with the rain streak material.
I was initially very wary of making the rain in my scene heavy, since I was concerned about how much a heavy rain look would prevent me from being able to pull good detail and contrast from the ships.
However, after some successful initial tests, I felt a bit more confident about a heavier rain look. 
I took the test from yesterday with more rain, and tried increasing the amount of rain by around 10x.
I originally started working on the sim with only around a million particles, but by the end I had bumped up the particle count to around 10 million.
In order to prevent the increased amount of rain from completely washing out the scene, I made each rain drop streak on the thinner and shorter side, and also tweaked the material to be slightly more forward scattering.
My rain material is basically a mix of a rough glass and grey diffuse, with the reasoning being rain needs to be a glass material since rain is water, but since the rain droplet streaks are meant to look motion blurred, throwing in some diffuse just helps them show up better in camera; making the rain material more forwards scattering in this case just means changing the ratio of glass/diffuse to be more glass.
I eventually arrived at a ratio of 60% diffuse light grey to 40% glass, which I found helped the rain show up in the camera and catch light a bit better.
I also used the “presence” parameter (which is really just opacity) in PxrShader to make final adjustments to balance how visible the rain was with how much it was washing out other details.
For the “hero” droplets, I used a completely bog-standard glass material.&lt;/p&gt;

  &lt;p&gt;Figuring out how to simulate the rain and make it look good was by far the single largest source of worries for me in this whole project, so I was incredibly relieved at the end when it all came together and started looking good.
Here’s a 2K crop from my final image showing the “hero” droplets and all of the surrounding rain streaks around the foreground robots.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/raindrops_crop.jpg"&gt;&lt;img alt="Figure 41: 2K crop showing &amp;quot;hero&amp;quot; droplets and rain streaks." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/raindrops_crop.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-lighting-and-compositing"&gt;&lt;/div&gt;
  &lt;h2 id="lighting-and-compositing"&gt;Lighting and Compositing&lt;/h2&gt;

  &lt;p&gt;Lighting this scene proved to be very interesting and very different from what I did for the previous challenge!
Looking back, I think I actually may have “overlit” the scene in the previous challenge; I tend to prefer a slightly more naturalistic look, but while in the thick of lighting, it’s easy to get carried away and push things far beyond the point of looking naturalistic.
Another aspect of this scene that it made it very different from anything I’ve tried before is both the sheer number of practical lights in the scene and the fact that practical lights are the primary source of all lighting in this scene!&lt;/p&gt;

  &lt;p&gt;The key lighting in this scene is provided by the overhead lampposts on the dock, which illuminate the foreground robots.
I initially had a bunch of additional invisible PxrRectLights providing additional illumination and shaping on the robots, but I got rid of all of them and in the final image I relied only on the actual lights on the lampposts.
To prevent the visible light surfaces themselves from blowing out an aliasing, I used two lights for every lamppost: one visible-to-camera PxrRectLight set to a low intensity that wouldn’t alias in the render, and one invisible-to-camera PxrRectLight set to a relatively higher intensity for providing the actual lighting.
The visible-to-camera PxrRectLight is rendered out as the only element on a separate render layer, which can then be added back in to the main key lighting render layer.&lt;/p&gt;

  &lt;p&gt;To better light the ships, I added a number of additional floodlights to the ship that weren’t part of the original model; you can see these additional floodlights mounted on top of the various masts of the ships and also on the sides of the tower superstructure.
These additional floodlights illuminate the decks of the ships and help provide specular highlights to all of the umbrellas on the deck of the foreground ship, which enhances the rainy water droplet covered look.
For the foreground robots on the dock, the ship floodlights also act as something of a rim light.
Each of the ship floodlights is modeled as a visible-to-camera PxrDiscLight behind a glass lens with a second invisible-to-camera PxrDiscLight in front of the glass lens. The light behind the glass lens is usually lower in intensity and is there to provide the in-camera look of the physical light, while the invisible light in front of the lens is usually higher in intensity and provides the actual illumination in the scene.&lt;/p&gt;

  &lt;p&gt;In general, one of the major lessons I learned on this project was that when lighting using practical lights that have to be be visible in camera, a good approach is to use two different lights: one visible-to-camera and one invisible-to-camera.
This approach allows for separating how the light itself looks versus what kind of lighting it provides.&lt;/p&gt;

  &lt;p&gt;The overall fill lighting and time of day is provided by the skydome, which is of an overcast sky at dusk.
I waffled back and forth for a while between a more mid-day setting versus a dusk setting, but eventually settled on the dusk skydome since the overall darker time of day allows the practical lights to stand out more.
I think allowing the background trees to fade almost completely to black actually helps a lot in keeping the focus of the image on the main story elements in the foreground.
One feature of RenderMan 23 that really helped in quickly testing different lighting setups and iterating on ideas was RenderMan’s IPR mode, which has come a long way since RendermMan first moved to path tracing.
In fact, throughout this whole project, I used the IPR mode extensively for both shading tests and for the lighting process.
I have a lot of thoughts about the huge, compelling improvements to artist workflows that will be brought by even better interactivity (RenderMan XPU is very exciting!), but writing all of those thoughts down is probably better material for a different blog post in the future.&lt;/p&gt;

  &lt;p&gt;In total I had five lighting render layers: the key from the lampposts, the foreground rim and background fill from the floodlights, overall fill from the skydome, and two practicals layers for the visible-to-camera parts of all of the practical lights.
Below are the my lighting render layers, although with the two practicals layers merged:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_key.jpg"&gt;&lt;img alt="Figure 42: Final render, lampposts key lighting pass." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_key.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_floods.jpg"&gt;&lt;img alt="Figure 43: Final render, floodlights lighting pass." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_floods.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_sky.jpg"&gt;&lt;img alt="Figure 44: Final render, sky fill lighting pass." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_sky.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_practicals.jpg"&gt;&lt;img alt="Figure 45: Final render, practical lights lighting pass." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/lights_practicals.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;I used a number of PxrRodLightFilters to knock down some distractingly bright highlights in the scene (especially on the foreground robots’ umbrellas in the center of the frame).
As a rendering engineer, rod light filters are a constant source of annoyance due to the sampling problems they introduce; rods allow for arbitrarily increasing or decreasing the amount of light going through an area, which throws off energy conservation, which can mess up importance sampling strategies that depend on a degree of energy conservation.
However, as a user, rod light filters have become one of my favorite go-to tools for shaping and adjusting lighting on a local basis, since they offer an enormous amount of localized artistic control.&lt;/p&gt;

  &lt;p&gt;To convey the humidity of a rainstorm and to provide volumetric glow around all of the practical lights in the scene, I made extensive use of volume rendering on this project as well.
Every part of the scene visible in-camera has some sort of volume in it!
There are generally two types of volumes in this scene: a group of thinner, less dense volumes to provide atmospherics, and then a group of thicker, denser “hero” volumes that provide some of the more visible mist below the foreground ship and swirling around the background ship.
All of these volumes are heterogeneous volumes brought in as VDB files.&lt;/p&gt;

  &lt;p&gt;One odd thing I found with volumes was some major differences in sampling behavior between RenderMan 23’s PxrPathtracer and PxrUnified integrators.
I found that by default, whenever I had a light that was embedded in a volume, areas in the volume near the light were extremely noisy when rendered using PxrUnified but rendered normally when using PxrPathtracer.
I don’t know enough about the details of how PxrUnified and PxrPathtracer’s volume integration &lt;a href="https://doi.org/10.1145/3084873.3084907"&gt;[Fong et al. 2017]&lt;/a&gt; approaches differ, but it almost looks to me like PxrPathtracer is correctly using RenderMan’s equiangular sampling implementation &lt;a href="http://dx.doi.org/10.1111/j.1467-8659.2012.03148.x"&gt;[Kulla and Fajardo 2012]&lt;/a&gt; in these areas and PxrUnified for some reason is not.
As a result, for rendering all volume passes I relied on PxrPathtracer, which did a great job with quickly converging on all passes.&lt;/p&gt;

  &lt;p&gt;An interesting unintended side effect of filling the scene with volumes was in how the volumes interacted with the orange thruster and exhaust vent lights.
I had originally calibrated the lights in the thrusters and exhaust vents to provide an indication of heat coming from those areas of the ship without being so bright as to distract from the rest of the image, but the orange glows these lights produced in the volumes made the entire bottom of the image orange, which was distracting anyway.
As a result, I had to re-adjust the orange thruster and exhaust vent lights to be considerably dimmer than I had originally had them, so that when interacting with the volumes, everything would be brought up to the apparent image-wide intensity that I had originally wanted.&lt;/p&gt;

  &lt;p&gt;In total I had eight separate render passes for volumes; each of the consolidated lighting passes from above had two corresponding volume passes.
Within the two volume passes for each consolidated lighting pass, one volume pass was for the atmospherics and one was for the heavier mist and fog.
Below are the volume passes consolidated into four images, with each image showing both the atmospherics and mist/fog in one image:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_key.jpg"&gt;&lt;img alt="Figure 46: Final render, lampposts key volumes combined passes." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_key.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_floods.jpg"&gt;&lt;img alt="Figure 47: Final render, floodlights volumes combined passes." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_floods.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_sky.jpg"&gt;&lt;img alt="Figure 48: Final render, sky fill volumes combined passes." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_sky.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_practicals.jpg"&gt;&lt;img alt="Figure 49: Final render, practical lights volumes combined passes." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/volumes_practicals.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;One final detail I added in before final rendering was to adjust the bokeh shape to something more interesting than a uniform circle.
RenderMan 23 offers a variety of controls for customizing the camera’s aperture shape, which in turn controls the bokeh shape when using depth of field.
All of the depth of field in my final image is in-render, and because of all of the tiny specular hits from all of the raindrops and from the wet shader, there is a lot of visible bokeh going on.
I wanted to make sure that all of this bokeh was interesting to look at!
I picked a rounded 5-bladed aperture with a significant amount of non-uniform density (that is, the outer edges of the bokeh are much brighter than the center core).&lt;/p&gt;

  &lt;p&gt;For final compositing, I used a basic Photoshop and Lightroom workflow like I did in the previous challenge, mostly because Photoshop is a tool I already know extremely well and I don’t have Nuke at home.
I took a relatively light-handed approach to compositing this time around; adjustments to layers were limited to just exposure adjustments.
All of the layers shown above already have the exposure adjustments I made baked in.
After making adjustments in Photoshop and flattening out to a single layer, I then brought the image into Lightroom for final color grading.
For the final color grade, I tried push the overall look to be a bit moodier and a bit more contrast-y, with the goal of having the contrast further draw the viewer’s eye to the foreground robots where the main story is.
Figure 50 is a gif that visualizes the compositing process for my final image by showing how all of the successive layers are added on top of each other.
Figure 51 shows what all of the lighting, comp, and color grading looks like applied to a 50% grey clay shaded version of the scene, and if you don’t want to scroll all the way back to the top of this post to see the final image, I’ve included it again as Figure 52.&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/final_layers_lossy.gif"&gt;&lt;img alt="Figure 50: Animated breakdown of compositing layers." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/final_layers_lossy.gif" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/clayrender_graded_4k.jpg"&gt;&lt;img alt="Figure 51: Final lighting, comp, and color grading applied to a 50% grey clay shaded version. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/clayrender_graded.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/shipshape_full_4k.jpg"&gt;&lt;img alt="Figure 52: Final image. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/shipshape_full.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-conclusion"&gt;&lt;/div&gt;
  &lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

  &lt;p&gt;On a whole, I’m happy with how this project turned out!
I think a lot of what I did on this project represents a decent evolution over and applies a lot of lessons learned on the previous RenderMan Art Challenge.
I started this project mostly as an excuse to just have fun, but along the way I still learned a lot more, and going forward I’m definitely hoping to be able to do more pure art projects alongside my main programming and technical projects.&lt;/p&gt;

  &lt;p&gt;Here is a progression video I put together from all of the test and in-progress renders that I made throughout this entire project:&lt;/p&gt;

  &lt;div class="embed-container"&gt;Shipshape Art Challenge Progression Reel&lt;/div&gt;
  &lt;div class="figcaption"&gt;&lt;span&gt;Figure 53: Progression reel made from test and in-progress renders leading up to my final image.&lt;/span&gt;&lt;/div&gt;

  &lt;p&gt;My wife, Harmony Li, deserves an enormous amount of thanks on this project.
First off, the final concept I went with is just as much her idea as it is mine, and throughout the entire project she provided valuable critiques and suggestions and direction.
As usual with the RenderMan Art Challenges, Leif Pederson from Pixar’s RenderMan group provided a lot of useful tips, advice, feedback, and encouragement as well.
Many other entrants in the Art Challenge also provided a ton of support and encouragement; the community that has built up around the Art Challenges is really great and a fantastic place to be inspired and encouraged.
Finally, I owe an enormous thanks to all of the judges for this RenderMan Art Challenge, because they picked my image for first place!
Winning first place in a contest like this is incredibly humbling, especially since I’ve never really considered myself as much of an artist.
Various friends have since pointed out that with this project, I no longer have the right to deny being an artist!
If you would like to see more about my contest entry, check out the &lt;a href="https://renderman.pixar.com/answers/challenge/15577/river-patrol.html"&gt;work-in-progress thread I kept on Pixar’s Art Challenge forum&lt;/a&gt;, and I also made &lt;a href="https://www.artstation.com/artwork/WK2OJv"&gt;an Artstation post&lt;/a&gt; for this project.&lt;/p&gt;

  &lt;p&gt;As a final bonus image, here’s a daylight version of the scene.
My backup plan in case I wasn’t able to pull off the rainy look was to just go for a boring daylight setup; I figured that the lighting would be a lot more boring, but the additional visible detail would be an okay consolation prize for myself.
Thankfully, the rainy look worked out and I didn’t have to go to my backup plan!
After the contest wrapped up, I went back and made a daylight version out of curiosity:&lt;/p&gt;

  &lt;p&gt;&lt;a href="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/daylight_comp_4k.jpg"&gt;&lt;img alt="Figure 54: Bonus image: daylight version. Click for 4K version." src="https://blog.yiningkarlli.com/content/images/2020/Jul/shipshape/preview/daylight_comp.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

  &lt;div id="2020-07-31-references"&gt;&lt;/div&gt;
  &lt;h2 id="references"&gt;References&lt;/h2&gt;

  &lt;p&gt;Petr Beckmann and André Spizzichino. 1963. &lt;a href="https://us.artechhouse.com/The-Scattering-of-Electromagnetic-Waves-from-Rough-Surfaces-P257.aspx"&gt;The Scattering of Electromagnetic Waves from Rough Surfaces&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;Brent Burley. 2012. &lt;a href="https://doi.org/10.1145/2343483.2343493"&gt;Physically Based Shading at Disney&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2012-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2012 Course Notes: Practical Physically-Based Shading in Film and Game Production&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;Brent Burley. 2015. &lt;a href="https://doi.org/10.1145/2776880.2787670"&gt;Extending the Disney BRDF to a BSDF with Integrated Subsurface Scattering&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2015-shading-course"&gt;&lt;em&gt;ACM SIGGRAPH 2015 Course Notes: Physically Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;Brent Burley. 2019. &lt;a href="https://www.jcgt.org/published/0008/04/02/"&gt;On Histogram-Preserving Blending for Randomized Texture Tiling&lt;/a&gt;. &lt;em&gt;Journal of Computer Graphics Techniques&lt;/em&gt; 8, 4 (Nov. 2019), 31-53.&lt;/p&gt;

  &lt;p&gt;Per Christensen, Julian Fong, Jonathan Shade, Wayne Wooten, Brenden Schubert, Andrew Kensler, Stephen Friedman, Charlie Kilpatrick, Cliff Ramshaw, Marc Bannister, Brenton Rayner, Jonathan Brouillat, and Max Liani. 2018. &lt;a href="https://dl.acm.org/citation.cfm?id=3182162"&gt;RenderMan: An Advanced Path-Tracing Architeture for Movie Rendering&lt;/a&gt;. &lt;em&gt;ACM Transactions on Graphics&lt;/em&gt; 37, 3 (Jul. 2018), Article 30.&lt;/p&gt;

  &lt;p&gt;Johannes Hanika, Marc Droske, and Luca Fascione. 2015. &lt;a href="http://dx.doi.org/10.1111/cgf.12681"&gt;Manifold Next Event Estimation&lt;/a&gt;. &lt;em&gt;Computer Graphics Forum (Proc. of Eurographics Symposium on Rendering)&lt;/em&gt; 34, 4 (Jun. 2015), 87-97.&lt;/p&gt;

  &lt;p&gt;Eric Heitz and Fabrice Neyret. 2018. &lt;a href="https://dl.acm.org/doi/10.1145/3233304"&gt;High-Performance By-Example Noise using a Histogram-Preserving Blending Operator&lt;/a&gt;. &lt;em&gt;Proceedings of the ACM on Computer Graphics and Interactive Techniques (Proc. of High Performance Graphics)&lt;/em&gt; 1, 2 (Aug. 2018), Article 31.&lt;/p&gt;

  &lt;p&gt;Christophe Hery, Ryusuke Villemin, and Junyi Ling. 2017. &lt;a href="http://graphics.pixar.com/library/PxrMaterialsCourse2017/index.html"&gt;Pixar’s Foundation for Materials: PxrSurface and PxrMarschnerHair&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2017-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2017 Course Notes: Physically Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;Christophe Hery, Ryusuke Villemin, and Florian Hecht. 2016. &lt;a href="http://graphics.pixar.com/library/BiDir/"&gt;Towards Bidirectional Path Tracing at Pixar&lt;/a&gt;. In &lt;a href="https://blog.selfshadow.com/publications/s2016-shading-course/"&gt;&lt;em&gt;ACM SIGGRAPH 2016 Course Notes: Physically Based Shading in Theory and Practice&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;Julian Fong, Magnus Wrenninge, Christopher Kulla, and Ralf Habel. 2017. &lt;a href="https://doi.org/10.1145/3084873.3084907"&gt;Production Volume Rendering&lt;/a&gt;. In &lt;em&gt;ACM SIGGRAPH 2017 Courses&lt;/em&gt;. Article 2.&lt;/p&gt;

  &lt;p&gt;Iliyan Georgiev, Jamie Portsmouth, Zap Andersson, Adrien Herubel, Alan King, Shinji Ogaki, Frederic Servant. 2019. &lt;a href="https://autodesk.github.io/standard-surface/"&gt;Autodesk Standard Surface&lt;/a&gt;. &lt;em&gt;Autodesk white paper&lt;/em&gt;.&lt;/p&gt;

  &lt;p&gt;Ole Gulbrandsen. 2014. &lt;a href="http://jcgt.org/published/0003/04/03/"&gt;Artistic Friendly Metallic Fresnel&lt;/a&gt;. &lt;em&gt;Journal of Computer Graphics Techniques&lt;/em&gt; 3, 4 (Dec. 2014), 64-72.&lt;/p&gt;

  &lt;p&gt;Christopher Kulla and Marcos Fajardo. 2012. &lt;a href="http://dx.doi.org/10.1111/j.1467-8659.2012.03148.x"&gt;Important Sampling Techniques for Path Tracing in Participating Media&lt;/a&gt;. &lt;em&gt;Computer Graphics Forum (Proc. of Eurographics Symposium on Rendering)&lt;/em&gt; 31, 4 (Jun. 2012), 1519-1528.&lt;/p&gt;

  &lt;p&gt;Bruce Walter, Steve Marschner, Hongsong Li, and Kenneth E. Torrance. 2007. &lt;a href="http://dx.doi.org/10.2312/EGWR/EGSR07/195-206"&gt;Microfacet Models for Refraction through Rough Surfaces&lt;/a&gt;. In &lt;em&gt;Proc. of Eurographics Symposium on Rendering (Rendering Techniques 2007)&lt;/em&gt;, 195-206.&lt;/p&gt;

&lt;/div&gt;</description><author>Code &amp;amp; Visuals</author><pubDate>Fri, 31 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.yiningkarlli.com/2020/07/shipshape-renderman-challenge.html</guid></item><item><title>Preserving Links whilst Migrating Domains with S3</title><link>/domain-migration/</link><description>&lt;p&gt;Domain migrations can be fairly simple things, change the CNAME and bobs your uncle. Difficulties arise when you have two different website systems and existing paths that you want to preserve and the site is run statically with no web server. The latter was the situation we found ourselves in.&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;The product I work on, Koru was purchased by a company called Cappfinity. Koru had a website https://joinkoru.com and Cappfinity had https://cappfinity.com. To consolidate the offerings, the websites were effectively merged.&lt;/p&gt;
&lt;p&gt;The setup for the Koru site was as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A static web app hosted on S3 on a subdomain of joinkoru.com&lt;/li&gt;
&lt;li&gt;Route53 for DNS&lt;/li&gt;
&lt;li&gt;A wordpress site hosted externally for the &amp;quot;main&amp;quot; website&lt;/li&gt;
&lt;li&gt;Cloudfront for all SSL and edge distribution&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We wanted to redirect &lt;code&gt;*.joinkoru.com&lt;/code&gt; to &lt;code&gt;cappfinity.com/koru&lt;/code&gt; whilst preserving the paths for the user. Ordinarily, we would have just used an Nginx or Apache rewrite rule. That would have given us much more granular control than the solution we arrived at, but we didn't want to host a whole new web server for the sake of some redirects.&lt;/p&gt;
&lt;h2&gt;S3 To the Rescue!&lt;/h2&gt;
&lt;p&gt;We eventually discovered that you can have &amp;quot;Routing Rules&amp;quot; in S3 Buckets. I quickly got to work creating a new S3 bucket.
Then under &lt;code&gt;Properties &amp;gt; Static Web Hosting&lt;/code&gt; I configured the following
Index Document: &lt;code&gt;index.html&lt;/code&gt; - this doesn't need to exist, the form element just needs to have content.&lt;/p&gt;
&lt;p&gt;The magic happens in &lt;code&gt;Redirection Rules&lt;/code&gt; which takes a horrendous XML type configuration. We set it up as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-xml"&gt;&amp;lt;RoutingRules&amp;gt;
  &amp;lt;RoutingRule&amp;gt;
    &amp;lt;Condition&amp;gt;
      &amp;lt;KeyPrefixEquals/&amp;gt;
    &amp;lt;/Condition&amp;gt;
    &amp;lt;Redirect&amp;gt;
      &amp;lt;HostName&amp;gt;koru.cappfinity.com&amp;lt;/HostName&amp;gt;
    &amp;lt;/Redirect&amp;gt;
  &amp;lt;/RoutingRule&amp;gt;
  &amp;lt;RoutingRule&amp;gt;
    &amp;lt;Condition&amp;gt;
      &amp;lt;HttpErrorCodeReturnedEquals&amp;gt;403&amp;lt;/HttpErrorCodeReturnedEquals&amp;gt;
    &amp;lt;/Condition&amp;gt;
    &amp;lt;Redirect&amp;gt;
      &amp;lt;HostName&amp;gt;koru.cappfinity.com&amp;lt;/HostName&amp;gt;
      &amp;lt;ReplaceKeyPrefixWith&amp;gt;404&amp;lt;/ReplaceKeyPrefixWith&amp;gt;
    &amp;lt;/Redirect&amp;gt;
  &amp;lt;/RoutingRule&amp;gt;
&amp;lt;/RoutingRules&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;So what's happening here?&lt;/h2&gt;
&lt;p&gt;The first part is the routing condition. For us, we have made it so the KeyPrefixEquals blank which means anything. This handles all the main redirects for existing content. In other cases, you may have it so &lt;code&gt;https://olddomain.com/blog&lt;/code&gt; goes to &lt;code&gt;https://newdomain.com/newblog&lt;/code&gt;. In that case, you would set the KeyPrefixEqual as &lt;code&gt;&amp;lt;KeyPrefixEqual&amp;gt;/blog&amp;lt;/KeyPrefixEqual&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The second routing rule states that if the document that we redirect to returns a 403 (meaning forbidden) then we will redirect to the same host but replace the Http Error code with 404 so it will go to their Not Found page correctly. This 403 error was happening in a subset of requests due to content not being present in the new system. We left it in for historical reasons.&lt;/p&gt;
&lt;h2&gt;Subdomains to Suffix's&lt;/h2&gt;
&lt;p&gt;You'll notice in the rules above that the redirect is not to &lt;code&gt;cappfinity.com/koru&lt;/code&gt; but rather to &lt;code&gt;koru.cappfinity.com&lt;/code&gt;. I forget the reason exactly for this because we could have used the &lt;code&gt;&amp;lt;ReplaceKeyPrefixWith&amp;gt;&lt;/code&gt; tag to redirect to &lt;code&gt;/koru&lt;/code&gt;. Nonetheless, we didn't for whatever reason (I hunted my emails down for a answer but couldn't find one). Instead, on the Cappfinity website side, which was newly hosted in Netlify, &lt;code&gt;koru.cappfinity.com&lt;/code&gt; was setup as a domain alias and a CNAME was configured for that subdomain to redirect to the Netlify Application.&lt;/p&gt;
&lt;p&gt;And hey presto! We were done. Overall, it was a fairly simple migration but used a solution I didn't even know was possible with S3!&lt;/p&gt;</description><author/><pubDate>Fri, 31 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/domain-migration/</guid></item><item><title>Guest post: Better SQLAlchemy and Beyond</title><link>https://gaganpreet.in/posts/better-sqlalchemy-beyond/</link><description>&lt;p&gt;I wrote a blog post which was originally published on the &lt;a href="https://medium.com/tiqets-tech/better-sqlalchemy-and-beyond-c2b57d9482ca" rel="noreferrer" target="_blank"&gt;Tiqets Tech blog&lt;/a&gt;.&lt;/p&gt;</description><author>Gaganpreet Arora</author><pubDate>Fri, 31 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://gaganpreet.in/posts/better-sqlalchemy-beyond/</guid></item><item><title>Different approaches to HTTP routing in Go</title><link>https://benhoyt.com/writings/go-routing/</link><description>Compares routing techniques in Go, including five custom approaches and three using third-party routing libraries.</description><author>Ben Hoyt's technical writing</author><pubDate>Thu, 30 Jul 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://benhoyt.com/writings/go-routing/</guid></item><item><title>Low Risk Contrarian</title><link>https://ferrucc.io/posts/low-risk-contrarian/</link><description>&lt;p&gt;Most founders in tech will tell you that they&amp;rsquo;re a contrarian&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But is being a contrarian an optimal decision? What are the alternatives? Is being a contrarian an advantage?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Founders of high growth companies, are making one big high risk high reward bet.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re looking for a big win you first have to find something that has high uncertainty.&lt;/p&gt;
&lt;p&gt;For example, there&amp;rsquo;s high uncertainty around when VR will become mainstream.&lt;/p&gt;</description><author>ferrucc.io</author><pubDate>Thu, 30 Jul 2020 15:47:05 GMT</pubDate><guid isPermaLink="true">https://ferrucc.io/posts/low-risk-contrarian/</guid></item><item><title>Braindump-2020Q3</title><link>https://one.mikro2nd.net/pages/braindump-2020q3/</link><description>Prelude It occurs to me that it might be useful to write down some of the stuff I&amp;rsquo;m currently thinking about and working on, and to put it out in the Wilds of The Internet in case someone else harbours intersecting/overlapping ideas and might be interested in talking about it or working with me on these things.
tl;dr: fediweb, swarm organisations, gaps in the NewStack
The focus of this post is my thoughts around internet-mediated collaborations and interactions, though not exclusively.</description><author>one mikro2nd</author><pubDate>Thu, 30 Jul 2020 15:36:05 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/braindump-2020q3/</guid></item><item><title>Go filesystems and file embedding</title><link>https://lwn.net/Articles/827215/</link><description>A presentation of the Go draft designs for a filesystem interface and a standard way to embed files in a Go binary (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Thu, 30 Jul 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/827215/</guid></item><item><title>Mending bookmarks</title><link>https://xenodium.com/mending-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://youtu.be/S6UfWgMDlkQ"&gt;12 Great Sewing Tips and Tricks ! Best great sewing tips and tricks #7 - YouTube&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Thu, 30 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/mending-bookmarks</guid></item><item><title>APEX Security: Why Sequential Primary Keys Can Be A Risk</title><link>https://hartenfeller.dev/blog/apex-security-sequences-risk</link><description>If you use sequences to generate primary key values make sure you use the checksum feature of APEX. Otherwise, users can easily discover data they should not be able to see by raising or lowering the numeric ID in the URL.</description><author>Philipp Hartenfeller Blog RSS Feed</author><pubDate>Thu, 30 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hartenfeller.dev/blog/apex-security-sequences-risk</guid></item><item><title>Failed Emacs builds, hanging kernels, abort(), oh my</title><link>https://porkrind.org/missives/failed-emacs-builds-hanging-kernels-abort-oh-my/</link><description>My nightly Emacs builds stopped about a month and a half ago. A couple days after I noticed it was failing I tried to debug the issue and found that building openssl was hanging—I found that Jenkins was timing out after an hour or so. I should mention that it&amp;#8217;s dying on a Mac OS &amp;#8230; &lt;a class="more-link" href="https://porkrind.org/missives/failed-emacs-builds-hanging-kernels-abort-oh-my/"&gt;Continue reading &lt;span class="screen-reader-text"&gt;Failed Emacs builds, hanging kernels, abort(), oh my&lt;/span&gt;&lt;/a&gt;</description><author>Missives</author><pubDate>Thu, 30 Jul 2020 01:05:10 GMT</pubDate><guid isPermaLink="true">https://porkrind.org/missives/failed-emacs-builds-hanging-kernels-abort-oh-my/</guid></item><item><title>Football summary 2019</title><link>https://rjp.is/blogging/posts/2020/07/football-2019/</link><description>In which we lament the introduction of VAR.</description><author>infrequent oscillations</author><pubDate>Wed, 29 Jul 2020 21:43:31 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/07/football-2019/</guid></item><item><title>How I Built a Serverless Search for My Blog</title><link>https://www.morling.dev/blog/how-i-built-a-serverless-search-for-my-blog/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_why_serverless"&gt;Why Serverless?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_solution_overview"&gt;Solution Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_data_extraction"&gt;Data Extraction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_search_backend_implementation"&gt;Search Backend Implementation&lt;/a&gt;
&lt;ul class="sectlevel2"&gt;
&lt;li&gt;&lt;a href="#_apache_lucene_in_a_graalvm_native_binary"&gt;Apache Lucene in a GraalVM Native Binary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_the_search_http_service"&gt;The Search HTTP Service&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#_wiring_things_up"&gt;Wiring Things Up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_deployment_to_aws_lambda"&gt;Deployment to AWS Lambda&lt;/a&gt;
&lt;ul class="sectlevel2"&gt;
&lt;li&gt;&lt;a href="#_building_quarkus_applications_for_aws_lambda"&gt;Building Quarkus Applications for AWS Lambda&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_identity_and_access_management"&gt;Identity and Access Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_performance"&gt;Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_cost_control"&gt;Cost Control&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#_wrap_up_and_outlook"&gt;Wrap-Up and Outlook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph teaser"&gt;
&lt;p&gt;I have built a custom search functionality for this blog,
based on Java and the Apache Lucene full-text search library,
compiled into a native binary using the Quarkus framework and GraalVM.
It is deployed as a Serverless application running on AWS Lambda,
providing search results without any significant cold start delay.
If you thought Java wouldn’t be the right language for this job, keep reading;
in this post I’m going to give an overview over the implementation of this feature and my learnings along the way.&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Wed, 29 Jul 2020 18:30:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/how-i-built-a-serverless-search-for-my-blog/</guid></item><item><title>Anomalous Parity</title><link>https://rjp.is/blogging/posts/2020/07/anomalous-parity/</link><description>In which we fiddle with some code.</description><author>infrequent oscillations</author><pubDate>Wed, 29 Jul 2020 11:11:42 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/07/anomalous-parity/</guid></item><item><title>Connect to remote docker host via SSH.</title><link>https://ricardoanderegg.com/posts/remote-manage-docker-with-ssh/</link><description>&lt;p&gt;I could not get reliable connections with docker-machine or docker context. This is how I got 100% reliable connections through ssh forwarding.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also more secure. You don&amp;rsquo;t need to expose any additional ports.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# create bash function&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;function&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;dockcon&lt;span style="color: #CE5C00; font-weight: bold;"&gt;()&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;{&lt;/span&gt;

&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# if used with the argument `unset`, close the connection&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# see the part after this conditional to understand it better&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;if&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;[[&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000;"&gt;$1&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;==&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;unset&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;]]&lt;/span&gt;&lt;span style="color: #000; font-weight: bold;"&gt;;&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;then&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# get the PID of the ssh process and kill it&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;&lt;span style="color: #204A87;"&gt;kill&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;$(&lt;/span&gt;cat&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;docker_connection.pid&lt;span style="color: #204A87; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;

&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# unset the environment variable&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;&lt;span style="color: #204A87;"&gt;unset&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;DOCKER_HOST

&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# remove the file with the PID&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;rm&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;docker_connection.pid

&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# end&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;        &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;return&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;fi&lt;/span&gt;


&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# generate a random integer between 27000 and 37000 to choose as a port&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #000;"&gt;PORT&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;$((&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #000;"&gt;RANDOM&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;%&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold;"&gt;10000&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt;  &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;+&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold;"&gt;27000&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;))&lt;/span&gt;

&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# connect via ssh&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# forward the remote docker socket to a local port on your machine&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# the argument &amp;quot;$1&amp;quot; is the remote host&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# echo the PID of the ssh connection to a text file&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;ssh&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;-NL&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;localhost:&lt;span style="color: #000;"&gt;$PORT&lt;/span&gt;:/var/run/docker.sock&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000;"&gt;$1&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #000; font-weight: bold;"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #204A87;"&gt;echo&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #000;"&gt;$!&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&amp;gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;docker_connection.pid

&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# set the environment variable to tell docker which host to use&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;&lt;span style="color: #204A87;"&gt;export&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #000;"&gt;DOCKER_HOST&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;tcp://localhost:&lt;/span&gt;&lt;span style="color: #000;"&gt;$PORT&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;
&lt;span style="color: #CE5C00; font-weight: bold;"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Usage:&lt;/p&gt;</description><author>Posts on rand[om]</author><pubDate>Wed, 29 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ricardoanderegg.com/posts/remote-manage-docker-with-ssh/</guid></item><item><title>For better prompts</title><link>https://dystroy.org/blog/prompts/</link><description>&lt;p&gt;Prompts I see everywhere are very bad in my opinion.&lt;/p&gt;
&lt;p&gt;They're sometimes fancy, full of bling which amazes coworkers, but usability nightmares.&lt;/p&gt;</description><author>dystroy|Canop / blog</author><pubDate>Wed, 29 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dystroy.org/blog/prompts/</guid></item><item><title>Notes on "Growing a Language"</title><link>https://www.swyx.io/notes-on-growing-a-language-by-guy-steele-5501</link><description>Revisiting one of my favorite talks ever, on designing programming languages for user extensibility and collaboration</description><author>swyx's site RSS Feed</author><pubDate>Tue, 28 Jul 2020 23:50:13 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/notes-on-growing-a-language-by-guy-steele-5501</guid></item><item><title>Let's build a Full-Text Search engine</title><link>https://artem.krylysov.com/blog/2020/07/28/lets-build-a-full-text-search-engine/</link><description>&lt;p&gt;Full-Text Search is one of those tools people use every day without realizing it. If you ever googled &amp;quot;golang coverage report&amp;quot; or tried to find &amp;quot;indoor wireless camera&amp;quot; on an e-commerce website, you used some kind of full-text search.&lt;/p&gt;
&lt;p&gt;Full-Text Search (FTS) is a technique for searching text in a collection of documents. A document can refer to a web page, a newspaper article, an email message, or any structured text.&lt;/p&gt;
&lt;p&gt;Today we are going to build our own FTS engine. By the end of this post, we'll be able to search across millions of documents in less than a millisecond. We'll start with simple search queries like &amp;quot;give me all documents that contain the word &lt;em&gt;cat&lt;/em&gt;&amp;quot; and we'll extend the engine to support more sophisticated boolean queries.&lt;/p&gt;
&lt;aside class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;Most well-known FTS engine is &lt;a class="reference external" href="https://lucene.apache.org/" target="_blank"&gt;Lucene&lt;/a&gt; (as well as &lt;a class="reference external" href="https://github.com/elastic/elasticsearch" target="_blank"&gt;Elasticsearch&lt;/a&gt; and Solr built on top of it).&lt;/p&gt;
&lt;/aside&gt;
&lt;section id="why-fts"&gt;
&lt;h3&gt;Why FTS&lt;a class="headerlink" href="#why-fts" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we start writing code, you may ask &amp;quot;can't we just use &lt;em&gt;grep&lt;/em&gt; or have a loop that checks if every document contains the word I'm looking for?&amp;quot;. Yes, we can. However, it's not always the best idea.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="corpus"&gt;
&lt;h3&gt;Corpus&lt;a class="headerlink" href="#corpus" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We are going to search a part of the abstract of English Wikipedia. The latest dump is available at &lt;a class="reference external" href="https://dumps.wikimedia.org/enwiki/latest/enwiki-latest-abstract1.xml.gz" target="_blank"&gt;dumps.wikimedia.org&lt;/a&gt;. As of today, the file size after decompression is 913 MB. The XML file contains over 600K documents.&lt;/p&gt;
&lt;p&gt;Document example:&lt;/p&gt;
&lt;pre class="code xml literal-block"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Wikipedia:&lt;span class="w"&gt; &lt;/span&gt;Kit-Cat&lt;span class="w"&gt; &lt;/span&gt;Klock&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://en.wikipedia.org/wiki/Kit-Cat_Klock&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;abstract&amp;gt;&lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;Kit-Cat&lt;span class="w"&gt; &lt;/span&gt;Klock&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;an&lt;span class="w"&gt; &lt;/span&gt;art&lt;span class="w"&gt; &lt;/span&gt;deco&lt;span class="w"&gt; &lt;/span&gt;novelty&lt;span class="w"&gt; &lt;/span&gt;wall&lt;span class="w"&gt; &lt;/span&gt;clock&lt;span class="w"&gt; &lt;/span&gt;shaped&lt;span class="w"&gt; &lt;/span&gt;like&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;grinning&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;cartoon&lt;span class="w"&gt; &lt;/span&gt;eyes&lt;span class="w"&gt; &lt;/span&gt;that&lt;span class="w"&gt; &lt;/span&gt;swivel&lt;span class="w"&gt; &lt;/span&gt;in&lt;span class="w"&gt; &lt;/span&gt;time&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;its&lt;span class="w"&gt; &lt;/span&gt;pendulum&lt;span class="w"&gt; &lt;/span&gt;tail.&lt;span class="nt"&gt;&amp;lt;/abstract&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="loading-documents"&gt;
&lt;h3&gt;Loading documents&lt;a class="headerlink" href="#loading-documents" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, we need to load all the documents from the dump. The built-in &lt;span class="docutils literal"&gt;encoding/xml&lt;/span&gt; package comes very handy:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;encoding/xml&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;os&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`xml:&amp;quot;title&amp;quot;`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`xml:&amp;quot;url&amp;quot;`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`xml:&amp;quot;abstract&amp;quot;`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;loadDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;dump&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;Documents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`xml:&amp;quot;doc&amp;quot;`&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Documents&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every loaded document gets assigned a unique identifier.
To keep things simple, the first loaded document gets assigned ID=0, the second ID=1 and so on.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="first-attempt"&gt;
&lt;h3&gt;First attempt&lt;a class="headerlink" href="#first-attempt" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;section id="searching-the-content"&gt;
&lt;h4&gt;Searching the content&lt;a class="headerlink" href="#searching-the-content" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Now that we have all documents loaded into memory, we can try to find the ones about cats. At first, let's loop through all documents and check if they contain the substring &lt;em&gt;cat&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On my laptop, the search phase takes 103ms - not too bad.
If you spot check a few documents from the output, you may notice that the function matches &lt;em&gt;caterpillar&lt;/em&gt; and &lt;em&gt;category&lt;/em&gt;, but doesn't match &lt;em&gt;Cat&lt;/em&gt; with the capital &lt;em&gt;C&lt;/em&gt;. That's not quite what I was looking for.&lt;/p&gt;
&lt;p&gt;We need to fix two things before moving forward:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Make the search case-insensitive (so &lt;em&gt;Cat&lt;/em&gt; matches as well).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Match on a word boundary rather than on a substring (so &lt;em&gt;caterpillar&lt;/em&gt; and &lt;em&gt;communication&lt;/em&gt; don't match).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/section&gt;
&lt;section id="searching-with-regular-expressions"&gt;
&lt;h4&gt;Searching with regular expressions&lt;a class="headerlink" href="#searching-with-regular-expressions" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;One solution that quickly comes to mind and allows implementing both requirements is &lt;em&gt;regular expressions&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here it is - &lt;span class="docutils literal"&gt;&lt;span class="pre"&gt;(?i)\bcat\b&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;&lt;span class="docutils literal"&gt;&lt;span class="pre"&gt;(?i)&lt;/span&gt;&lt;/span&gt; makes the regex case-insensitive&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;span class="docutils literal"&gt;\b&lt;/span&gt; matches a word boundary (position where one side is a word character and another side is not a word character)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;regexp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MustCompile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`(?i)\b`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;`\b`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Don't do this in production, it's a security risk. term needs to be sanitized.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MatchString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ugh, the search took more than 2 seconds. As you can see, things started getting slow even with 600K documents. While the approach is easy to implement, it doesn't scale well. As the dataset grows larger, we need to scan more and more documents. The time complexity of this algorithm is linear - the number of documents required to scan is equal to the total number of documents. If we had 6M documents instead of 600K, the search would take 20 seconds. We need to do better than that.&lt;/p&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="inverted-index"&gt;
&lt;h3&gt;Inverted Index&lt;a class="headerlink" href="#inverted-index" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To make search queries faster, we'll preprocess the text and build an index in advance.&lt;/p&gt;
&lt;p&gt;The core of FTS is a data structure called &lt;em&gt;Inverted Index&lt;/em&gt;.
The Inverted Index associates every word in documents with documents that contain the word.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;&lt;code&gt;&lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;a donut on a glass plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;only the donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;listen to the drum machine&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;listen&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;to&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;drum&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="s2"&gt;&amp;quot;machine&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Below is a real-world example of the Inverted Index. An index in a book where a term references a page number:&lt;/p&gt;
&lt;img alt="" src="https://artem.krylysov.com/images/2020-fts/book-index.png" style="width: 592px;" /&gt;
&lt;/section&gt;
&lt;section id="text-analysis"&gt;
&lt;h3&gt;Text analysis&lt;a class="headerlink" href="#text-analysis" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before we start building the index, we need to break the raw text down into a list of words (tokens) suitable for indexing and searching.&lt;/p&gt;
&lt;p&gt;The text analyzer consists of a tokenizer and multiple filters.&lt;/p&gt;
&lt;img alt="" src="https://artem.krylysov.com/images/2020-fts/text-analysis.png" style="width: 530px;" /&gt;
&lt;/section&gt;
&lt;section id="tokenizer"&gt;
&lt;h3&gt;Tokenizer&lt;a class="headerlink" href="#tokenizer" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The tokenizer is the first step of text analysis. Its job is to convert text into a list of tokens. Our implementation splits the text on a word boundary and removes punctuation marks:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FieldsFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="c1"&gt;// Split on any character that is not a letter or a number.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IsLetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IsNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A donut on a glass plate. Only the donuts.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donuts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="filters"&gt;
&lt;h3&gt;Filters&lt;a class="headerlink" href="#filters" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In most cases, just converting text into a list of tokens is not enough. To make the text easier to index and search, we'll need to do additional normalization.&lt;/p&gt;
&lt;section id="lowercase"&gt;
&lt;h4&gt;Lowercase&lt;a class="headerlink" href="#lowercase" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In order to make the search case-insensitive, the lowercase filter converts tokens to lower case. &lt;em&gt;cAt&lt;/em&gt;, &lt;em&gt;Cat&lt;/em&gt; and &lt;em&gt;caT&lt;/em&gt; are normalized to &lt;em&gt;cat&lt;/em&gt;.
Later, when we query the index, we'll lower case the search terms as well. This will make the search term &lt;em&gt;cAt&lt;/em&gt; match the text &lt;em&gt;Cat&lt;/em&gt;.&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lowercaseFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lowercaseFilter&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donuts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donuts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="dropping-common-words"&gt;
&lt;h4&gt;Dropping common words&lt;a class="headerlink" href="#dropping-common-words" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Almost any English text contains commonly used words like &lt;em&gt;a&lt;/em&gt;, &lt;em&gt;I&lt;/em&gt;, &lt;em&gt;the&lt;/em&gt; or &lt;em&gt;be&lt;/em&gt;. Such words are called &lt;em&gt;stop words&lt;/em&gt;. We are going to remove them since almost any document would match the stop words.&lt;/p&gt;
&lt;p&gt;There is no &amp;quot;official&amp;quot; list of stop words. Let's exclude the top 10 by the &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Most_common_words_in_English" target="_blank"&gt;OEC rank&lt;/a&gt;. Feel free to add more:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stopwords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// I wish Go had built-in sets.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;and&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;be&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;have&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;i&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;in&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;of&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;that&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;to&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stopwordFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stopwords&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stopwordFilter&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donuts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donuts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="stemming"&gt;
&lt;h4&gt;Stemming&lt;a class="headerlink" href="#stemming" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Because of the grammar rules, documents may include different forms of the same word.
Stemming reduces words into their base form. For example, &lt;em&gt;fishing&lt;/em&gt;, &lt;em&gt;fished&lt;/em&gt; and &lt;em&gt;fisher&lt;/em&gt; may be reduced to the base form (stem) &lt;em&gt;fish&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Implementing a stemmer is a non-trivial task, it's not covered in this post. We'll take one of the &lt;a class="reference external" href="https://github.com/kljensen/snowball" target="_blank"&gt;existing&lt;/a&gt; modules:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snowballeng&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/kljensen/snowball/english&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stemmerFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;snowballeng&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stemmerFilter&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donuts&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;aside class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;A stem is not always a valid word. For example, some stemmers may reduce &lt;em&gt;airline&lt;/em&gt; to &lt;em&gt;airlin&lt;/em&gt;.&lt;/p&gt;
&lt;/aside&gt;
&lt;/section&gt;
&lt;/section&gt;
&lt;section id="putting-the-analyzer-together"&gt;
&lt;h3&gt;Putting the analyzer together&lt;a class="headerlink" href="#putting-the-analyzer-together" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lowercaseFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stopwordFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stemmerFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tokenizer and filters convert sentences into a list of tokens:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A donut on a glass plate. Only the donuts.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;on&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;glass&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;plate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tokens are ready for indexing.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="building-the-index"&gt;
&lt;h3&gt;Building the index&lt;a class="headerlink" href="#building-the-index" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Back to the inverted index. It maps every word in documents to document IDs.
The built-in &lt;span class="docutils literal"&gt;map&lt;/span&gt; is a good candidate for storing the mapping.
The key in the map is a token (string) and the value is a list of document IDs:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;][]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Building the index consists of analyzing the documents and adding their IDs to the map:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="c1"&gt;// Don't add same ID twice.&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;A donut on a glass plate. Only the donuts.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nx"&gt;document&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="nx"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;donut is a donut&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works! Each token in the map refers to IDs of the documents that contain the token:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;code&gt;map[donut:[1 2] glass:[1] is:[2] on:[1] only:[1] plate:[1]]&lt;/code&gt;&lt;/pre&gt;
&lt;/section&gt;
&lt;section id="querying"&gt;
&lt;h3&gt;Querying&lt;a class="headerlink" href="#querying" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To query the index, we are going to apply the same tokenizer and filters we used for indexing:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Small wild cat&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;173&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;303&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;173&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;765&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;173&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, we can find all documents that mention cats. Searching 600K documents took less than a millisecond (18µs)!&lt;/p&gt;
&lt;p&gt;With the inverted index, the time complexity of the search query is linear to the number of search tokens. In the example query above, other than analyzing the input text, &lt;span class="docutils literal"&gt;search&lt;/span&gt; had to perform only three map lookups.&lt;/p&gt;
&lt;/section&gt;
&lt;section id="boolean-queries"&gt;
&lt;h3&gt;Boolean queries&lt;a class="headerlink" href="#boolean-queries" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The query from the previous section returned a disjoined list of documents for each token.
What we normally expect to find when we type &lt;em&gt;small wild cat&lt;/em&gt; in a search box is a list of results that contain &lt;em&gt;small&lt;/em&gt;, &lt;em&gt;wild&lt;/em&gt; and &lt;em&gt;cat&lt;/em&gt; at the same time. The next step is to compute the set intersection between the lists. This way we'll get a list of documents matching all tokens.&lt;/p&gt;
&lt;img alt="" src="https://artem.krylysov.com/images/2020-fts/venn.png" style="width: 313px;" /&gt;
&lt;p&gt;Luckily, IDs in our inverted index are inserted in ascending order. Since the IDs are sorted, it's possible to
compute the intersection between two lists in linear time. The &lt;span class="docutils literal"&gt;intersection&lt;/span&gt; function iterates two lists simultaneously and collects IDs that exist
in both:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;maxLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;maxLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;maxLen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;maxLen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Updated &lt;span class="docutils literal"&gt;search&lt;/span&gt; analyzes the given query text, lookups tokens and computes the set intersection between lists of IDs:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;intersection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="c1"&gt;// Token doesn't exist.&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Wikipedia dump contains only two documents that match &lt;em&gt;small&lt;/em&gt;, &lt;em&gt;wild&lt;/em&gt; and &lt;em&gt;cat&lt;/em&gt; at the same time:&lt;/p&gt;
&lt;pre class="code go literal-block"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Small wild cat&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="mi"&gt;130764&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wildcat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;species&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;complex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;comprising&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;small&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wild&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;species&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;European&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wildcat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Felis&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;silvestris&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;African&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wildcat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lybica&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;131692&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Catopuma&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;genus&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;containing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Asian&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;small&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wild&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;species&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Asian&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;golden&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;temminckii&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The search is working as expected!&lt;/p&gt;
&lt;p&gt;By the way, this is the first time I hear about &lt;em&gt;catopuma&lt;/em&gt;, here is one of them:&lt;/p&gt;
&lt;img alt="By Karen Stout - originally posted to Flickr as Asian Golden cat, CC BY-SA 2.0, https://commons.wikimedia.org/w/index.php?curid=11413240" src="https://artem.krylysov.com/images/2020-fts/asian-golden-cat-s.jpg" style="width: 300px;" /&gt;
&lt;/section&gt;
&lt;section id="conclusions"&gt;
&lt;h3&gt;Conclusions&lt;a class="headerlink" href="#conclusions" title="Permalink to this headline"&gt; #&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We just built a Full-Text Search engine. Despite its simplicity, it can be a solid foundation for more advanced projects.&lt;/p&gt;
&lt;p&gt;I didn't touch on a lot of things that can significantly improve the performance and make the engine more user friendly.
Here are some ideas for further improvements:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;p&gt;Extend boolean queries to support &lt;em&gt;OR&lt;/em&gt; and &lt;em&gt;NOT&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Store the index on disk:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rebuilding the index on every application restart may take a while.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Large indexes may not fit in memory.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Experiment with memory and CPU-efficient data formats for storing sets of document IDs. Take a look at &lt;a class="reference external" href="https://roaringbitmap.org/" target="_blank"&gt;Roaring Bitmaps&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support indexing multiple document fields.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sort results by relevance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The full source code is available on &lt;a class="reference external" href="https://github.com/akrylysov/simplefts" target="_blank"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/section&gt;</description><author>Artem Krylysov</author><pubDate>Tue, 28 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://artem.krylysov.com/blog/2020/07/28/lets-build-a-full-text-search-engine/</guid></item><item><title>Create your first REST API  in Django Rest Framework  A step by step guide creating APIs in Django Rest Framework</title><link>https://blog.adnansiddiqi.me/create-your-first-rest-api-in-django-rest-framework/</link><description>&lt;p&gt;In this post, I am going to talk about Django Rest Framework or DRF. DRF is used to create RESTful APIs in Django which later could be consumed by various apps; mobile, web, desktop, etc. We will be discussing how to install DRF on your machine and then will be writing our APIs for a system. Before we discuss DRF, let&amp;#8217;s talk a bit about REST itself. What is Rest From Wikipedia Representational state transfer (REST) is a software architectural style that defines a set of constraints to be used for creating Web services. Web services that conform to the REST architectural style, called RESTful Web services, provide interoperability between computer systems on the Internet. RESTful Web services allow the requesting systems to access and manipulate textual representations of Web resources by using a uniform and predefined set of stateless operations. Other kinds of Web services, such as SOAP Web services, expose their own arbitrary sets of operations.[1] &amp;#160; Rest API(Application Programming Interface) is a client-server architecture that is stateless and used a typical URL scheme for data exchange. It was first presented by Roy Fielding in 2000 in his famous dissertation. The URL that is used to provide communication between a client and server is often called an endpoint. Different HTTP methods are used for this purpose: GET:-  it returns the requested data which could be a list of records or a single record. POST:- It creates a new record. PUT/PATCH:- It updates an existing record. DELETE; It deletes the record. The returned data could either be in XML, JSON, or other formats but the first two are most common. OK, now you have learned a bit about REST API, let&amp;#8217;s discuss Django Rest Framework itself. What is Django Rest Framework Django Rest Framework is an open-source framework to write RESTful APIs in Python. It is based on the Django framework so knowledge of Django is quite beneficial though not necessary. So we are going to make APIs for a contact management system where a user will be able to use our APIs to create/update and delete contacts. The returned data will be in JSON format. Installation and Setup I am going to use Pipenv for setting up the development environment for our APIs. Pipenv makes it easier to isolate your development environment irrespective of what things are installed on your machine. It also lets you pick a different Python version that whatever is installed on your machine. It uses Pipfile to manage all your project-related dependencies. I am not gonna cover Pipenv here in detail so will only be using the commands that are necessary for the project. You can install Pipenv via PyPy by running pip install pipenv Once installed, we now have to select the Python version for our project. I am willing to use Python 3.8 version instead of the Py3.7 already installed on my machine. To install Python 3.8, all you have to do is to run the following command: pipenv install --python 3.8 And it will be installing like below: You may also run pipenv install --three where three means Python 3.x. Once installed you can activate the virtual environment by running the command pipenv shell ➜ ContactAPIs pipenv shell Launching subshell in virtual environment… . /Users/AdnanAhmad/.local/share/virtualenvs/ContactAPIs-tI040CTn/bin/activate ➜ ContactAPIs . /Users/AdnanAhmad/.local/share/virtualenvs/ContactAPIs-tI040CTn/bin/activate Once you are in the shell(You will see a prompt like  (ContactAPIs) ➜ ContactAPIs), you will be able to install required libraries. First, we will install Django by running the following command: pipenv install django Note it&amp;#8217;s pipenv, NOT pip. When you are into the shell you will be using pipenv. Underlying it is using pip but all entries are being stored in Pipfile. After than run pipenv install djangorestframework. The Pipfile will be looking like below: [[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] [packages] django = "*" djangorestframework = "*" [requires] python_version = "3.8" Now we have to create a Django project. To create a Django project we will be running the django-admin command like below: django-admin startproject contact_api . It will create a directory structure like below: (ContactAPIs) ➜ ContactAPIs tree contact_api contact_api ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py So far so good, let&amp;#8217;s see whether we can run the local development server. Run the command python manage.py runserver. If all goes well you should be seeing a window like below: &amp;#160; Beautiful, No? OK let&amp;#8217;s run some existing migrations. For that, we will run the command python manage.py migrate. (ContactAPIs) ➜ ContactAPIs python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying sessions.0001_initial... OK Django uses Sqlite3 by default but you may always use your favorite RDBMS engine by changing the settings. Alright, so all the system related tables created. We should be able to visit http://127.0.0.1:8000/admin/ but we can&amp;#8217;t log in. How can we while we don&amp;#8217;t have any credentials? So now, we will be creating a superuser. python manage.py createsuperuser --email me@example.com --username admin It will prompt you to set a password. Once done and you get into the Admin, you will be welcomed by a window similar to the below: Now we will be creating a Django App. For that purpose, first I will get into the contact_api folder and then will run the following command: (ContactAPIs) ➜ ContactAPIs cd contact_api (ContactAPIs) ➜ contact_api django-admin startapp contact After that the folder structure will look like below: (ContactAPIs) ➜ contact_api tree . . ├── __init__.py ├── asgi.py ├── contact │   ├── __init__.py │   ├── admin.py │   ├── apps.py │   ├── migrations │   │   └── __init__.py │   ├── models.py │   ├── tests.py │   └── views.py ├── settings.py ├── urls.py └── wsgi.py Django developers might find it unusual to create an app within the project folder but it was recommended on DRF official website. You can always follow your way which is to create an app out of the project folder. Now we will be including our DRF framework and the newly created app within INSTALLED_APPS. So head over to settings.py in contact_api folder and add the entries like below: INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'contact_api.contact', ] Notice the last two entries. We added rest_framework so that we can have API functionality. Second, we added our newly created app. Notice that path. Since the app created WITHIN the contact_api folder so we have to give the complete path with dot notation. We will now be creating models and views for our API endpoints. In the models.py file we will be writing our model. This model will be the sole responsibility of retrieving or inserting the data via APIs. from django.db import models # Create your models here. class Contact(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) email = models.CharField(max_length=50) address = models.CharField(max_length=100) So here is our model with a few fields. It&amp;#8217;s time to create the migration and then migrate it so that the schema could be generated in the DB file. We will be running the command python manage.py makemigrations contact which will produce an output like the below: (ContactAPIs) ➜ ContactAPIs python manage.py makemigrations contact Migrations for 'contact': contact_api/contact/migrations/0001_initial.py - Create model Contact The migration file is created. It&amp;#8217;s to migrate it! (ContactAPIs) ➜ ContactAPIs python manage.py migrate Operations to perform: Apply all migrations: admin, auth, contact, contenttypes, sessions Running migrations: Applying contact.0001_initial... OK (ContactAPIs) ➜ ContactAPIs Besides creating previous migrations, it created the one which we just created. We now will be registering our model in admin.py so that we could interact with the model in the admin interface: from django.contrib import admin from .models import Contact # Register your models here. admin.site.register(Contact) If you visit http://127.0.0.1:8000/admin, you will be finding the newly created Contact model over there. Next, we will be creating the View and Data Serializer. First, we will be creating the serializer. Serializers help to convert models and querySets into native Python data types so that they could then be rendered as JSON or XML. Since they serialize data hence you can always deserialize them back to models and querySets. The serialized file will look like below: from rest_framework import serializers from .models import Contact class Contactializer(serializers.HyperlinkedModelSerializer): class Meta: model = Contact fields = ('id', 'url', 'first_name', 'last_name', 'email', 'address') After importing the necessary classes, we created a class and mentioned the class we want to be serialized. We also mentioned what fields we want to expose hence serialize. Next, we will be creating the view and for that, we will be using ViewSet. Viewsets combines the logic of multiple views under a single class. Now we have to set up our API endpoints and for that, we have to do a bit of hard work. First, we have to create a file urls.py within our app folder that is contact folder. from rest_framework import routers from django.urls import path,include from . import views router = routers.DefaultRouter() router.register('contacts', views.ContactView) urlpatterns = [ path('',include(router.urls)) ] Here you are going to learn a new concept, Router. If you are coming from the background of Laravel, Rails, or even NodeJS, you would have an idea of what a router does; it routes the request to an appropriate resource. DRF provides three kinds of routers: Simple, Default, and Custom. The Default router is similar to Simple Router which returns all CRUD related endpoints plus URL of each record&amp;#8217;s endpoint and optional JSON view. Next up, we register our viewset into a root name which is contacts here. Hence all endpoints will contain contacts/ in the API endpoints. Once it is registered, you are going to use the same old include to set the paths of your endpoints by including router.urls. In RoR and Laravel world these are called resourceful routs because you do not have to create separate views and their respective URLs for create, update, get, post and delete.  Of course you can always add your own custom endpoint by adding a method and decorating with an @action decorator. For instance, check below: @action(detail=False, methods=['get']) def lol(self, request, pk=None): return Response({'status': 'OK'}) Here we added another custom route so when one visits http://127.0.0.1:8000/contacts/lol/, it returns a JSON response. We set detail=False because it is not a resourceful endpoint hence only serving a single endpoint only. Alright, things don&amp;#8217;t end here. Next, we have to add our APIs to the main urls.py and for that we are going to do the below in contact/urls.py from django.contrib import admin from django.urls import path,include urlpatterns = [ path('admin/', admin.site.urls), path('',include('contact_api.contact.urls')), ] So besides Admin we finally have our APIs included in the main project&amp;#8217;s urls.py  which makes it available to explore APIs besides Admin or other apps URLs. Now it&amp;#8217;s time to taste the fruit of our efforts. Head over to http://127.0.0.1:8000/contacts/ on your browser and you will be seeing something like below: It shows a fancy interface for adding records and other things. You also see an Extra Option button, it is for our custom method we just added.  Let&amp;#8217;s play with it. I have created an animated Gif for you to see how a record is being added both in HTML and JSON format. How records are being listed and how an individual record is being explored. &amp;#160; Of course, you will not see all this HTML based interface while you access it directly via CURL or other libs. (ContactAPIs) ➜ ContactAPIs curl http://127.0.0.1:8000/contacts/ [{"id":1,"url":"http://127.0.0.1:8000/contacts/1/","first_name":"Adnan","last_name":"Ahmad","email":"adnan@mail.com","address":"A29 Sweet House"},{"id":2,"url":"http://127.0.0.1:8000/contacts/2/","first_name":"Ali","last_name":"Ahmad","email":"ali@email.com","address":"5th Street New way Town"}]% Oh BTW, you can always visit http://127.0.0.1:8000/contacts/lol/ LOL!! Conclusion In this tutorial, you learned how you can create REST APIs in Python by using Django Rest Framework. I have just given you an intro and there&amp;#8217;s a lot more you can do like securing a certain API endpoint behind a...&lt;/p&gt;
The post &lt;a href="https://blog.adnansiddiqi.me/create-your-first-rest-api-in-django-rest-framework/"&gt;Create your first REST API  in Django Rest Framework &lt;br /&gt; &lt;span style="color: grey; font-size: 25px; font-weight: 300;"&gt;A step by step guide creating APIs in Django Rest Framework&lt;/span&gt;&lt;/a&gt; first appeared on &lt;a href="https://blog.adnansiddiqi.me"&gt;Adnan's Random bytes&lt;/a&gt;.</description><author>Adnan's Random bytes</author><pubDate>Mon, 27 Jul 2020 19:01:02 GMT</pubDate><guid isPermaLink="true">https://blog.adnansiddiqi.me/create-your-first-rest-api-in-django-rest-framework/</guid></item><item><title>How to choose a median result when running Google Lighthouse multiple times</title><link>https://maxrozen.com/how-to-choose-median-lighthouse-multiple-runs</link><description>Running Google Lighthouse five times will half the variability of your test results. So how do you figure out which run is the median?</description><author>Max Rozen</author><pubDate>Mon, 27 Jul 2020 18:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/how-to-choose-median-lighthouse-multiple-runs</guid></item><item><title>Don't forget the human</title><link>https://ellie.wtf/posts/dont-forget-the-human/</link><description>&lt;p&gt;Computers are cold and heartless. They don't lie, and they don't care if you scream and swear at them. You can abuse them all day long, and they'll still efficiently flip bits and push pixels.&lt;/p&gt;
&lt;p&gt;But... people aren't. Behind every piece of software, there's at least one human. Who has a heart, and who cares what you think. Who has hopes, and dreams, and fears. Who feels.&lt;/p&gt;
&lt;p&gt;This is something I've been wanting to write in one form or another for quite a while now, and I've been rewriting this post for a little too long.&lt;/p&gt;
&lt;p&gt;Sometimes it seems like we forget about the humans. Either we forget that there's a human behind the software we build, or we forget that we're shipping software &lt;em&gt;for people&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It seems to me that more and more, especially recently, nobody can share their work or their ideas without someone stepping in and criticising their ideas. Maybe they could have written it in a language that's faster, uses less memory, &lt;em&gt;something about bloat or native code.&lt;/em&gt; Maybe it doesn't have a feature that another project does, so why the hell should anyone use it?&lt;/p&gt;
&lt;p&gt;I remember earlier in my career, every time I opened a PR, I'd have a small feeling of anxiety. Was it good enough? What if I'm bad at programming? Would people hate it? What if I'm wrong? Fear of failure is one of the biggest obstacles to success, and all too often it stops people from sharing or achieving what they could. The feeling of "this isn't good enough to share" goes along with that.&lt;/p&gt;
&lt;p&gt;Even while writing this, I couldn't help but feel like it isn't quite perfect, isn't quite good enough to share. But that's the point of my blog; I want to make myself put things out there, even if they're not 100%.&lt;/p&gt;
&lt;p&gt;We should feel like it's ok to share work that isn't finished, that doesn't use the fastest, cleanest, most optimal approach. If I've made something for fun and want to share it, why not? If it doesn't use the technology you prefer, and you haven't paid me to build it, why would you shit all over someone else's work?&lt;/p&gt;
&lt;p&gt;Better yet. If you care that much, make your own. Instead of pulling down something of someone else's', build your own thing up.&lt;/p&gt;
&lt;p&gt;To some degree I understand people not being satisfied with professional software, that they have paid for, and that doesn't meet their expectations. But if it's open source, free, and available for all? Why would you ever complain about that? If it's not for you, just... move on.&lt;/p&gt;
&lt;p&gt;Friends of mine won't share their blog posts to HN, Reddit, etc, because they feel like their words aren't good enough. Or like people there are going to tear them apart. Or because they might have made a small mistake somewhere.&lt;/p&gt;
&lt;p&gt;The main thing I can see fuelling so many arguments is an inherent &lt;em&gt;need&lt;/em&gt; to be right. It's been written about so many times before, but for some reason people can't bear the idea that &lt;strong&gt;&lt;a href="https://xkcd.com/386/?ref=ellie.wtf" rel="external"&gt;someone on the internet is wrong&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Except, when it comes to the preferences of which tools or technology someone wants to build something with, in their own time, can you really be wrong?&lt;/p&gt;
&lt;p&gt;There's a stereotype held about people in tech, that we're all that super nerdy person who struggles socially, can't talk to people, and hide all day in the basement programming. And that somehow, this is excusable if you're &lt;em&gt;really good&lt;/em&gt; at writing code. But is it? If you're writing code for people to use, and you're working on it with people, not having people skills isn't really an option. Much like technical skills, it isn't an innate quality - you can work on improving your people skills, much like you can your tech skills.&lt;/p&gt;
&lt;p&gt;If you take anything at all from my post, hopefully it's this; if you really must say something, and you really feel like someone made the wrong choice, maybe think about your phrasing. Eg&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hey! Nice work. I was curious though, why'd you pick  over ?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;vs&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ugh, this would be so much better if it just used . I hate the way modern tech is going&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let's make our industry a much more friendly and welcoming place 💖&lt;/p&gt;</description><author>Ellie's Notes</author><pubDate>Mon, 27 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ellie.wtf/posts/dont-forget-the-human/</guid></item><item><title>Diving Into Bioinformatics From Scratch</title><link>https://philippzentner.com/im-tuning-to-life-science-heres-how.html</link><description>&lt;img alt="" src="https://philippzentner.com/media/posts/56/Screenshot-2020-07-30-at-16.10.09.png" /&gt;
                    Disclaimer: I have zero background in biology. Well, my dad is a bio-chemist and my sister a biotechnological assistant. Apart from that, nothing. This article aims to sum up how I'm tackling the problematic of having to learn the basics like what the nucleus is&amp;hellip;</description><author>Philipp Zentner</author><pubDate>Sun, 26 Jul 2020 23:29:05 GMT</pubDate><guid isPermaLink="true">https://philippzentner.com/im-tuning-to-life-science-heres-how.html</guid></item><item><title>How to Setup Peercoin on Raspberry Pi for Headless Minting</title><link>https://bartlomiejmika.com/posts/2020/how-to-setup-peercoin-on-raspberry-pi-for-headless-minting/</link><description>&lt;p&gt;Would you believe you can participate in cryptocurrency production using a simple Raspberry Pi computer? No need for powerful ASIC miners! Peercoin is an interesting altcoin that has &lt;strong&gt;minting&lt;/strong&gt; capability built-in, and minting is the ability to create new coins from the ones you already have. In this tutorial, you&amp;rsquo;ll learn how to set up a dedicated Raspberry Pi computer to mint the Peercoins in your wallet.&lt;/p&gt;</description><author>Bartlomiej Mika</author><pubDate>Sun, 26 Jul 2020 19:15:15 GMT</pubDate><guid isPermaLink="true">https://bartlomiejmika.com/posts/2020/how-to-setup-peercoin-on-raspberry-pi-for-headless-minting/</guid></item><item><title>Internet Friends</title><link>https://ferrucc.io/posts/internet-friends/</link><description>&lt;p&gt;The ability to make friendships through your passions is the best super power that the internet gives us.&lt;/p&gt;
&lt;p&gt;The best things that happened in my life happened through communities on the internet.&lt;/p&gt;
&lt;p&gt;Here’s a story of all the places I hanged out on the internet and made friends from.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Until the first year of high school I’ve been offline. &lt;/p&gt;
&lt;p&gt;My experience until then with the internet was running a Blogspot to sell snacks in middle school (with someone who&amp;rsquo;s still one of my best friends) and having a messenger account on my dad’s computer.&lt;/p&gt;</description><author>ferrucc.io</author><pubDate>Sun, 26 Jul 2020 18:24:09 GMT</pubDate><guid isPermaLink="true">https://ferrucc.io/posts/internet-friends/</guid></item><item><title>4 Things I Learned from Mastering Mongoose.js</title><link>https://www.swyx.io/4-things-i-learned-from-mastering-mongoose-js-25e</link><description>A quick book review of the new Mongoose.js book from Val Karpov</description><author>swyx's site RSS Feed</author><pubDate>Sun, 26 Jul 2020 12:53:19 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/4-things-i-learned-from-mastering-mongoose-js-25e</guid></item><item><title>Making a tiny 2x3 bitmap font</title><link>https://zserge.com/posts/tiny-font/</link><description>Somehow I got curious: what would be the smallest bitmap font that would still be readable?
why 2x3 grid There are plenty of existing retro 8x16 bitmap fonts, like the ones used in VGA graphics and text-mode consoles. We should probably be able to go much smaller than that. We only need to encode 26 different symbols. If our encoding is perfect - we need roughly 5 bits of information, or 5 pixels, each being either black or white.</description><author>zserge's blog</author><pubDate>Sun, 26 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/tiny-font/</guid></item><item><title>Broot content search</title><link>https://dystroy.org/blog/broot-c-search/</link><description>&lt;p&gt;An example of an efficient search workflow based on &lt;a href="https://dystroy.org/broot"&gt;broot&lt;/a&gt;, a general purpose file manager.&lt;/p&gt;</description><author>dystroy|Canop / blog</author><pubDate>Sun, 26 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dystroy.org/blog/broot-c-search/</guid></item><item><title>Where is the source code for ping?</title><link>https://ntietz.com/blog/where-is-ping/?utm_source=atom&amp;utm_medium=feed</link><description>&lt;p&gt;Lately, I've been working on implementing &lt;code&gt;ping&lt;/code&gt; on my own as a project to keep learning Rust and to deepen my knowledge of networks. I'm just going for a super basic utility here, nothing fancy, not even all the features of &lt;code&gt;ping&lt;/code&gt;. But since the language is new to me &lt;em&gt;and&lt;/em&gt; my lower-level network knowledge is weak, I decided that it could be helpful to compare notes, so to speak, with the real deal itself. So that's our question: where is the source code for the actual utility &lt;code&gt;ping&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Let's find out! I'm running Ubuntu, so the question is where do my binary packages come from and where does the corresponding source live? Naively, I expected this to be super easy to find. It's not &lt;em&gt;hard&lt;/em&gt; to find, for my system (Ubuntu), but it's not as easy as it would be on some others like Gentoo.&lt;/p&gt;
&lt;p&gt;The first step I took was, naturally, to turn to Google and search "ping source code". The first search result is a &lt;a href="https://gist.github.com/kbaribeau/4495181"&gt;GitHub gist&lt;/a&gt;, which links to a &lt;a href="https://ftp.arl.army.mil/~mike/ping.html"&gt;US Army page&lt;/a&gt; written by the original author of ping. Cool, so this is seems like the original source! This is really cool and a great historical artifact. Is this the same version that I'm running on my desktop, though? We need to dig deeper and see what's running on the local machine.&lt;/p&gt;
&lt;p&gt;If we use &lt;code&gt;man ping&lt;/code&gt; to look at the manual page for ping, we see "System Manager's Manual: iputils" at the top, which is our first hint at where ping comes from on our system: possibly the package is named iputils, and I do have a package named iputils-ping installed. From here, we can find the &lt;a href="https://packages.ubuntu.com/source/bionic/iputils"&gt;source package&lt;/a&gt; and... the links on that page to the Debian git repos are broken. Sigh.&lt;/p&gt;
&lt;p&gt;Back we go to Google and we find the &lt;a href="https://packages.debian.org/source/buster/iputils"&gt;source package for iputils&lt;/a&gt; on Debian, figuring it's probably the same. And now we're in luck, and we can get to the iputils git repo that Ubuntu presumably draws from by way of Debian: &lt;a href="https://salsa.debian.org/debian/iputils"&gt;https://salsa.debian.org/debian/iputils&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And thus we find the source: &lt;a href="https://salsa.debian.org/debian/iputils/-/blob/master/ping.c"&gt;https://salsa.debian.org/debian/iputils/-/blob/master/ping.c&lt;/a&gt; and &lt;a href="https://salsa.debian.org/debian/iputils/-/blob/master/ping.h"&gt;https://salsa.debian.org/debian/iputils/-/blob/master/ping.h&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It clocks in at a total of approximately 2k lines of code (well, there is also shared code), which is not much bigger than the original source. It's a marvel to me that this gem of software has stayed small, concise, and &lt;em&gt;useful&lt;/em&gt; for decades without acquiring much bloat, without changing forms. May more software be like ping.&lt;/p&gt;
&lt;p&gt;Now that we have the source, there's a lot more to learn. For example, if you receive pings intended for another process (because that happens with raw sockets, it turns out), you can setup a filter with Berkeley Packet Filter, and ignore any pings that aren't for you! This is really cool and something that I need to learn more about.&lt;/p&gt;
&lt;p&gt;What other gems am I missing out there?&lt;/p&gt;</description><author>ntietz.com blog - technically a blog</author><pubDate>Sun, 26 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ntietz.com/blog/where-is-ping/?utm_source=atom&amp;utm_medium=feed</guid></item><item><title>Out-Performing in Orange - An Introduction</title><link>http://spirals.blog/articles/orange-introduction/</link><description>&lt;div class="toc"&gt;
&lt;p&gt;Orange represents the “fifth stage” of human existence. If you’re new to Spiral, please first read:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/what-is-spiral-dynamics/"&gt;What is Spiral Dynamics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/beige-introduction/"&gt;Beginning in Beige&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/purple-introduction/"&gt;Progressing to Purple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/red-introduction/"&gt;Rising to Red&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/blue-introduction/"&gt;Believing in Blue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's highly encouraged you read these before this article. Things are going to get a bit intense.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;The Big League&lt;/h2&gt;
&lt;p&gt;Wait. What are YOU doing here? Who invited you?&lt;/p&gt;
&lt;p&gt;I’m serious. This is an &lt;em&gt;exclusive&lt;/em&gt; club.&lt;/p&gt;
&lt;p&gt;You wanna play with the big boys? Alrighty, pal. Let’s see if you’ve got what it takes.&lt;/p&gt;
&lt;p&gt;But I’m not here to fuck around. I won’t waste your time, so don’t even think about wasting mine.&lt;/p&gt;
&lt;p&gt;“Oh, they swear. They must be Red”.&lt;/p&gt;
&lt;p&gt;Fuck off with that basic Blue shit. Does a Red dress like this?&lt;/p&gt;
&lt;p&gt;&lt;img alt="Harvey Specter, Suits" src="http://spirals.blog/articles/orange-introduction/harvey.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Or drive cars like this?&lt;/p&gt;
&lt;p&gt;&lt;img alt="Lamborghini" src="http://spirals.blog/articles/orange-introduction/lambo.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I didn’t think so. We’re a different breed of “I”. We’re Orange.&lt;/p&gt;
&lt;h2&gt;Not for the faint of heart&lt;/h2&gt;
&lt;p&gt;I’ll tell it to you straight. Orange is not for everyone. It’s &lt;em&gt;&lt;strong&gt;fucking intense&lt;/strong&gt;&lt;/em&gt;, extremely challenging, and takes everything from you if you’re not careful. And I mean &lt;em&gt;&lt;strong&gt;everything&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Orange doesn’t understand taking Christmas breaks. Orange doesn’t stop working because Blue tells them the “day’s over”. Orange doesn’t EVER give up until it’s done. It’s not over till you’ve won.&lt;/p&gt;
&lt;p&gt;Let’s talk about winning for a minute. In Orange, you are either the best, the winner, the champion – or you fucking suck. There’s no “second place” in Orange. No bullshit, 5th grade, gold star, participation award. You win, or you lose. It’s that simple.&lt;/p&gt;
&lt;p&gt;And I’m not talking about no “Red” winning either. Red just wants to dominate because it likes its “self”. Orange dominates because &lt;strong&gt;losing is not an option&lt;/strong&gt;. It will do literally everything in its power to &lt;em&gt;crush&lt;/em&gt; you. Because it &lt;em&gt;can&lt;/em&gt;. Don’t ever verse an Orange in anything unless you’re prepared to lose. Or fight till the bitter end.&lt;/p&gt;
&lt;p&gt;Intimidated yet? &lt;strong&gt;I hope so&lt;/strong&gt;. This &lt;strong&gt;isn’t&lt;/strong&gt; a challenge for you “Low Red” s or “moving away from Blue” s to try and &lt;em&gt;“make it happen”&lt;/em&gt;. Take down your shitty motivational poster above your desk. Don’t objectify it. It’s not all sunshines and rainbows.&lt;/p&gt;
&lt;h3&gt;Whatever you think about Orange is probably wrong.&lt;/h3&gt;
&lt;p&gt;Yeah, you can get the house on the beach, and visit every country, and eat like a fucking king, all while wearing a freshly pressed, Armarni, pin-striped suit. And yeah, it’s fucking great. But it’s not all. &lt;em&gt;You gotta look behind the scenes.&lt;/em&gt; That “overnight success” bullshit you saw in the newspaper? What they &lt;em&gt;&lt;strong&gt;DIDN’T&lt;/strong&gt;&lt;/em&gt; report was that mother-fucker slaved away day and night for 10 years and lost his first marriage to get that business off the ground. Think twice, buddy.&lt;/p&gt;
&lt;p&gt;Before you prop this shit up on a pedestal and worship it like a fucking Blue God, I want you to know what it will cost you. You’ve been warned.&lt;/p&gt;
&lt;h2&gt;Breaking Blue: Enter Science&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Galileo Galilei" src="http://spirals.blog/articles/orange-introduction/galileo.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Let’s take a step back for a sec.&lt;/p&gt;
&lt;p&gt;To understand Orange, you have to know where Blue falls over. And it falls over, believe me.&lt;/p&gt;
&lt;p&gt;Blue is the best thing in the world for consistency, discipline, routine, and order. It’s terrible at thinking outside the box.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Industrial Revolution was a result of the failure of the more medieval forms of life. To solve the problems of existence then, it was &lt;em&gt;anything&lt;/em&gt; else. And when that occurred, then the human had to develop a different way of thinking. You see, if you don’t believe that the power (that be the power that be) knows everything, knows all rules as to how to live, then you have to begin to think that maybe you know some too. Or at least somebody else knows something about how to live. So they started to switch. &lt;strong&gt;People who made this move started to switch from the absolutist way of thinking to what we call a multiplicity.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;– Clare Graves - &lt;a href="https://youtu.be/tt3Uk1f3y_U?t=2361"&gt;In Conversation with Clare W. Graves.(Youtube)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ok, Graves, English, please?&lt;/p&gt;
&lt;p&gt;Let’s be clear on something. Blue doesn’t have all the answers. We know this because even if we follow &lt;strong&gt;EXACTLY&lt;/strong&gt;, &lt;em&gt;TO A “T”&lt;/em&gt;, all the rules (which is impossible these days), we don’t always get what Blue has always promised. The reward at the end.&lt;/p&gt;
&lt;p&gt;Governments fail. Churches become corrupt. Police are just humans and are fully capable of performing violently brutal acts of self-interest despite their title of authority. You won’t always get the gold watch after 20 years of service at your company.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Police Brutality" src="http://spirals.blog/articles/orange-introduction/police-brutality.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Put simply, the authorities fuck up. All the time.&lt;/p&gt;
&lt;p&gt;Around the 1700’s, politics and religion were almost synonymous. Law was (and still is in many respects) heavily influenced by the religious faith held by any given country. When this system started fraying at the seams, people needed an alternative.&lt;/p&gt;
&lt;p&gt;Enter Orange.&lt;/p&gt;
&lt;h2&gt;Taking things into our own hands&lt;/h2&gt;
&lt;p&gt;Maybe the higher-up’s DON’T know what they’re doing. That higher up could be a god, a boss, or a government. It doesn’t matter. What does matter is what you’ve been told your entire life to do isn’t working. We need a new way of thinking.&lt;/p&gt;
&lt;p&gt;The Industrial Revolution birthed an explosive, expansive slew of ideas, breakdowns of conventional society (of the time), dis-belief in monotheistic religious thought, etc.&lt;/p&gt;
&lt;p&gt;Here’s the core idea. “If &lt;em&gt;they&lt;/em&gt; don’t know what they’re doing, then all is fair game”. More specifically, if one becomes disillusioned with their powers that be, and manage to find a better way, the new Orange believes they have a &lt;strong&gt;right&lt;/strong&gt; to pursue this. Because it works (and the old way did not).&lt;/p&gt;
&lt;p&gt;The Scientific Revolution and the Industrial Revolution go hand in hand. Feeding off each other, together, they broke the limits of Blue thinking and pushed (like Red did from Purple) into the unknown. &lt;a href="https://spirals.blog/articles/i-vs-we/"&gt;The pendulum swings.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Personally, I don’t like the term “revolution”. I understand a “revolution” as something that changes, rotates, only to return to the same place. It’s my opinion that “shift” or “breakthrough” is a more applicable word to describe this movement.&lt;/p&gt;
&lt;h2&gt;Science works.&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Apollo 11" src="http://spirals.blog/articles/orange-introduction/rocket.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The Orange perspective spread like wildfire. Its propensity to focus on facts, data, and a systematic approach to get results (as opposed to “known Truths”) produced dramatically superior outcomes. &lt;strong&gt;And it was replicateable&lt;/strong&gt;. We improved the quality of human existence from the focus on information, NOT living in accordance with what we’re told. The Scientific Method broke-out of the “Church” and set a course to change (and discover) the new world.&lt;/p&gt;
&lt;p&gt;Inventors and scientists like James Watt, Isaac Newton, Charles Darwin, Thomas Edison, Nikola Tesla, Albert Einstein (amongst many others) drove forward the powerful vehicle that was developing. To this day, their Orange thinking and discoveries influence billions, with scientists using their findings every day.&lt;/p&gt;
&lt;p&gt;Individuals like these have a few things in common.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;They don’t give up. (Edison famously learned “how not to build a lightbulb” 1000 times)&lt;/li&gt;
&lt;li&gt;They challenge pre-existing thought (Darwin’s “On the Origin of Species” ruffled a few feathers in the Christian-English establishment)&lt;/li&gt;
&lt;li&gt;They’re driven by facts (Science doesn’t draw conclusions on guesses)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now we have the lightbulb, the radio, the computer, have been to the moon, and discovered the ocean’s greatest depths. We know, now, that lightning isn’t God’s wrath (sorry Thor) but the result of a buildup of static energy between two gaseous states of water.&lt;/p&gt;
&lt;p&gt;Science works.&lt;/p&gt;
&lt;h2&gt;The Entrepreneur and the WANTrepreneur&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Entrepreneur" src="http://spirals.blog/articles/orange-introduction/entrepreneur.jpg" /&gt;
&lt;em&gt;Photo by Simon Abrams @flysi3000&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As the Industrial/Scientific “breakthrough” became increasingly more productive and unavoidably prominent, it, in turn, influenced law, as society moved toward the “New Secular” (non-religious) perspective. The New World was a hot topic, as were shipping companies, and “opportunities”. So we created things called companies.&lt;/p&gt;
&lt;p&gt;In his book, “Black Swan”, Nassim Nicholas Taleb states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Today, a few take almost everything; the rest, next to nothing”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The new breakthroughs and shifts in perspective that Orange generates, create an unprecedented, disproportionate relationship to what we reap from our labor.&lt;/p&gt;
&lt;p&gt;He goes further to say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“In [Orange], inequalities are such that one single observation can disproportionally impact the aggregate or the total”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;The power of ideas&lt;/h3&gt;
&lt;p&gt;Electricity didn’t just change the world. It fundamentally re-invented the very meaning of what it meant to live in modern society. This just doesn’t happen in Blue. It’s too stable. Don’t rock the boat. The attention, significance, wealth, and power generated from these new Orange ideas were/are irresistible for many.&lt;/p&gt;
&lt;p&gt;The Entrepreneur rose into a competitive ascendance, fueled by intelligence and the power of its ideas. It was now concepts, not authority that provided the ways and means of changing things, and nothing is off-limits. Red gains power in a raw, physical sense, often through brute force or intimidation. &lt;em&gt;&lt;strong&gt;Orange gains power through intelligence and strategy&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“My success is determined only by me”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Today, much of Orange is channeled in strategy. You’ll often find Orange bragging or fixated on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chess&lt;/li&gt;
&lt;li&gt;Marketing&lt;/li&gt;
&lt;li&gt;Competitor analysis&lt;/li&gt;
&lt;li&gt;Social-media ad targeting&lt;/li&gt;
&lt;li&gt;Training to win&lt;/li&gt;
&lt;li&gt;Professional sports&lt;/li&gt;
&lt;li&gt;Sales&lt;/li&gt;
&lt;li&gt;Etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Orange lives and breathes in out-thinking, out-competing, out-working, out-earning everyone in their path. And they will literally die trying.&lt;/p&gt;
&lt;p&gt;For an Orange, strategy is everything. Whether it’s work, the pictures they’re uploading to their Instagram with 100K followers, or the partner they chose; everything comes down to strategy. And status, but more on this later.&lt;/p&gt;
&lt;p&gt;Still think it’s the shiny, suit-laden, cocaine infused, supermodel orgy on a private beach that you can show up to in a Maserati with little to no work? Think again. If Orange is not running through your blood, you will never work as hard as they will.&lt;/p&gt;
&lt;h3&gt;Low Orange: Why your next “app idea” is total shit&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Wantrepreneur" src="http://spirals.blog/articles/orange-introduction/wantrepreneur.jpg" /&gt;
&lt;em&gt;Photo by Austin Distel @austindistel&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The promise of being an inventor, ship/factory owner, or scientist was (and is) an attractive promise-land; a shining North Star to inspire those hungry and daring enough to leave the tiny, safe, Blue Box, and “bet the farm” on the “next best thing”. It attracts the masses, and only a few make it. Social media is riddled with the “(10 year) overnight success’”, but we never hear about the 999999999999 other failed attempts.&lt;/p&gt;
&lt;p&gt;Gold-rushes, your friend’s new business venture, pyramid schemes, Bitcoin, day trading, the “Digital Nomad” movement; they all promise the same thing. You don’t have to do Blue. They’re all fucking wrong.&lt;/p&gt;
&lt;p&gt;Real Orange is risky as all hell, and if you lose, you often don’t ever come back. But real Orange is not Blue-shy. A &lt;em&gt;&lt;strong&gt;true, healthy&lt;/strong&gt;&lt;/em&gt; Orange knows that Blue is the platform on which to build these ideas. Without it (to use a phrase from where I come from), “You’re up Shit Creek without a paddle”. If you don’t have Blue, healthy Orange is impossible. Yes, Oranges, I know you hate that word. “Don’t fucking tell me something is impossible.” you’ll say. Blue without Orange doesn’t work. Period.&lt;/p&gt;
&lt;p&gt;If you find yourself attracted to whatever you &lt;em&gt;think&lt;/em&gt; Orange is, read the next paragraph over 20 times out loud, and stick it on your monitor.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Real Orange starts and ends in &lt;em&gt;reality&lt;/em&gt;. It’s dull and boring. Low Orange starts and ends in your imagination, where everything is fun and exciting and almost certainly out of perspective. &lt;br /&gt;
– Anonymous&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Today, we witness this in the Silicon Valley culture. A bunch of hooded (why this is a stereotype I have no idea) hackers, tapping away at a stickered MacBook Pro, attempting to build the next Facebook/Airbnb/Uber/Google. Most are full of shit. Some aren’t. The ones that aren’t? They create such an imbalance for the rest of the world that it’s almost impossible not to be affected.&lt;/p&gt;
&lt;p&gt;The problem is the “successful 1/999999999 are so drastically over-represented in media, news, &lt;a href="https://www.youtube.com/watch?v=UF8uR6Z6KLc"&gt;motivational graduation speeches&lt;/a&gt;, and &lt;a href="https://fourhourworkweek.com/"&gt;Orange Books&lt;/a&gt;. No Orange actually works 4 hour weeks. Any real Orange would spit out their coffee if you told them you could be successful, only working 4 hours a week. Even Tim admits this. It’s excellent marketing non-the-less 👌.&lt;/p&gt;
&lt;p&gt;Your travel blog you spend writing in Canguu Bali won’t make you rich from affiliate marketing. Nobody wants your shitty pyramid-scheme protein shake. Fuck off. Don’t tell me you’re making money from your dropshipping unless you’re willing to show me your bank account. Don’t even get me started on life coaches.&lt;/p&gt;
&lt;p&gt;Go back to Blue, Low Orange’s. Stop fucking complaining and do the work. Don’t run away from tedious, dull work, because THAT is what you do for 99.9999% of the time to be successful. &lt;strong&gt;For years on end&lt;/strong&gt;. Starting a business won’t give you more time. It will take it.&lt;/p&gt;
&lt;p&gt;There is an incredibly disproportional relationship to “success” in Orange vs. everything “below” it. Blue does what it’s told, Red, what it wants, and Purple just wants to live. From the Orange perspective, arises the desire for more.&lt;/p&gt;
&lt;h2&gt;You win, or you lose&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Race" src="http://spirals.blog/articles/orange-introduction/race.jpg" /&gt;
&lt;em&gt;Photo by Braden Collum @bradencollum&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Are you beginning to get the picture? I sure hope so. Let’s talk about winning.&lt;/p&gt;
&lt;p&gt;In the game of ideas, the best one wins. Business and finances are a zero-sum game. When you’re playing a sport, there’s only one winner. One. Not two. You win, or you’re a loser. Second place is for pussies who can’t accept defeat. Are we clear?&lt;/p&gt;
&lt;p&gt;An Orange is addicted to the rush of winning. The closing of the sale. The sight of the customer pulling out their wallet to pay for the goods. The superiority and recognition you get when you defeat your opponent. They’ll take it wherever they can.&lt;/p&gt;
&lt;p&gt;How &lt;em&gt;healthy&lt;/em&gt; your Orange determines how far you’ll go into this. How much will you upset the other colors, the balance of the Spiral? Ever watch the Wolf of Wall Street? Yeah, you took that too far, Jordan.&lt;/p&gt;
&lt;p&gt;Orange’s train themselves, especially at a competitive sports level, to remove losing from the picture. It’s simply just not an option. An &lt;em&gt;inconceivable&lt;/em&gt; notion for Blue (or Red, or Purple).&lt;/p&gt;
&lt;h3&gt;High Risk - High Reward&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Free climb" src="http://spirals.blog/articles/orange-introduction/climb.jpg" /&gt;
&lt;em&gt;Photo by Fionn Claydon @fclaydon&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This addiction to winning coaxes Orange’s to take larger and more significant risks. They grow more boisterous and confident in their perceived ability (they’re often full of shit too) and reach out further.&lt;/p&gt;
&lt;p&gt;In Orange, the risks are monumental. A stock trader can put down their entire life savings to “win it big”. If they lose, they lose it all, and there’s no recovering from that. But they do it anyway. Why? Because the reward is so enticing.&lt;/p&gt;
&lt;p&gt;Healthy Orange dodges this kind of thinking, instead, combining their Blue/Orange to mitigate risk as much as possible and make a calculated decision. Blue + Orange still wins, but more safely.&lt;/p&gt;
&lt;p&gt;This high risk/reward is what attracts other unhealthy colors to the “idea” of Orange. You can indeed earn uncapped money in Orange (unlike Blue), but do you really have what it takes? Are you running from something? Be FUCKING careful. Anyone that tells you, you can get everything for nothing is selling you. Walk away.&lt;/p&gt;
&lt;h2&gt;Totality of fixation&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Programning" src="http://spirals.blog/articles/orange-introduction/programming.jpg" /&gt;
&lt;em&gt;Photo by Alvaro Reyes @alvarordesign&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s not over till you’ve won.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An Orange doesn’t stop until the job is done, or the result is achieved. Blue doesn’t get this.&lt;/p&gt;
&lt;p&gt;Here’s an illustration of how a Blue approaches the problem, vs. an Orange.&lt;/p&gt;
&lt;h4&gt;Blue:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;The printer at work breaks.&lt;/li&gt;
&lt;li&gt;Blue tries to fix it with their limited knowledge of printers&lt;/li&gt;
&lt;li&gt;When that doesn’t work, they call IT, who says “We’ll send someone up sometime today”&lt;/li&gt;
&lt;li&gt;The Blue goes and get’s a coffee because they’ve passed the puck onto some other shcmuck&lt;/li&gt;
&lt;li&gt;At the end of the day, when the IT guy never showed up, the boss asks to see the report. “I couldn’t print it, sir. The printer is broken”&lt;/li&gt;
&lt;li&gt;The boss (who deals with shit like this every day) is at a loss and has to solve it themself&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Orange:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;The printer at work breaks.&lt;/li&gt;
&lt;li&gt;Orange tries to fix it with their limited knowledge of printers&lt;/li&gt;
&lt;li&gt;When that doesn’t work, they ask every person in the office if they know how to resolve it.&lt;/li&gt;
&lt;li&gt;If nobody knows, they then get on their phone, google the serial number of the printer, and search “How do I fix a broken XYZ printer”&lt;/li&gt;
&lt;li&gt;They go through every option until it works&lt;/li&gt;
&lt;li&gt;If that’s still not working, they call IT. “We’ll send someone up sometime today”&lt;/li&gt;
&lt;li&gt;While they’re waiting, they continue to google to see if there’s anything they missed.&lt;/li&gt;
&lt;li&gt;When the IT guy doesn’t show up, they call again (knowing they will get the same response).&lt;/li&gt;
&lt;li&gt;While they’re on the phone to IT, during their lunch break, they Uber down to an office supply shop and buy a new printer of the exact model.&lt;/li&gt;
&lt;li&gt;They print it and give it to the boss, telling them they bought a new printer because it was broken, detailing everything they tried.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Do you recognize the difference? Orange doesn’t stop until it’s done. They are &lt;strong&gt;fixated&lt;/strong&gt; on doing whatever it takes to get the result. A Blue comes to the boss with problems. An Orange comes with solutions.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Reporter: “How did it feel to fail 1,000 times?” &lt;br /&gt;
Edison: “I didn’t fail 1,000 times. The light bulb was an invention with 1,000 steps.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To say an Orange is “driven” is an understatement. They don’t take “no” as an answer.&lt;/p&gt;
&lt;h2&gt;The Orange Perspective: Multiplistic &amp;amp; Significance&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Brainstorming" src="http://spirals.blog/articles/orange-introduction/brainstorming.jpg" /&gt;
&lt;em&gt;Photo by Daria Nepriakhina @epicantus&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;How is an Orange able to do the above? What sets them apart psychologically? What drives Orange?&lt;/p&gt;
&lt;p&gt;Orange expresses self. Like Red. &lt;em&gt;But not at all like Red&lt;/em&gt;. It does it in a way that’s calculated, playing in the grey spaces between what Blue thinks is right and wrong.&lt;/p&gt;
&lt;p&gt;In a technical sense, Blue is what we’d call “absolutist”. Something either is, or it isn’t. It’s black, or it’s white. It works, or it doesn’t. It’s my job, or it isn’t. This is great for some things (whether I should drink the glass of water with poison in it is an absolutistic problem, and &lt;strong&gt;should&lt;/strong&gt; be considered as such). This breaks down entirely when things get more complex.&lt;/p&gt;
&lt;p&gt;Orange, in a technical sense, is “multiplistic”. It’s able to come up with more than one way of doing something. It literally sees more. It tries more. It’s not afraid to fail, and try again, and fail. For “absolutistic” thinking, there is one way to do something. For “multiplistic” there are many ways, but only one &lt;em&gt;&lt;strong&gt;good&lt;/strong&gt;&lt;/em&gt; way. This is the quest of the Orange. To find that way.&lt;/p&gt;
&lt;p&gt;Oranges are very creative, thanks to their ability to think of multiple options. Combined with their strategic thinking, and “do n’t-stop-till-you-drop” attitude, they make brilliant inventors, creatives, designers, researchers, writers, marketers, CEOs, etc.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Here’s to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently. They’re not fond of rules. And they have no respect for the status quo. You can quote them, disagree with them, glorify or vilify them. About the only thing you can’t do is ignore them. Because they change things. They push the human race forward. And while some may see them as the crazy ones, we see genius. Because the people who are crazy enough to think they can change the world, are the ones who do.” &lt;br /&gt;
– Steve Jobs (The King of Orange)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Significance of Status&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Status" src="http://spirals.blog/articles/orange-introduction/status.jpg" /&gt;
&lt;em&gt;Photo by Sebastian Pociecha @sebastianpoc&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Orange loves attention. And status. It bathes in the significance that it “sees more than others”, and the external, material, success and recognition that this brings.&lt;/p&gt;
&lt;p&gt;Having come from strict Blue, where one could only achieve authority from what family you were born into or how long you worked somewhere, the freedom that Orange gets from it’s ideas is self-gratifying.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I created this. My mind. My smarts. My analysis. My hard work. So I deserve the rewards. And I want to be respected for it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Status is essential for the Orange, amongst other Oranges. Who has the bigger paycheck, more luxurious car, and wife with the biggest fake boobs? I’m not being crude. For an Orange, their status is equivalent to their “authority” in Blue. If you’re not successful, you’re nobody to me. Don’t waste my time.&lt;/p&gt;
&lt;p&gt;Where do you eat? What type of food. Have you been to the Maldives? Do you have a boat? How big is it? Oh, you only made 3 mil last year? That’s too bad. Better luck with the new Asia expansion.&lt;/p&gt;
&lt;h2&gt;Communication with Oranges&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Just do it!" src="http://spirals.blog/articles/orange-introduction/do-it.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Oranges are abrupt. They’re &lt;strong&gt;extremely time-sensitive&lt;/strong&gt;, intense, energetic, and are not afraid to yell at you.&lt;/p&gt;
&lt;p&gt;You have to understand, this is not coming from a place of malice. It’s just how we talk. There’s so much energy in Orange that it needs to be expelled. Sometimes this results in some explosive comments and activities. Don’t take it personally.&lt;/p&gt;
&lt;p&gt;Don’t come to us with excuses or tell us we can’t do something because it’s against the rules. Look us in the eye. Don’t lie to us. Give us the facts without the bullshit back story to it. Get to the point.&lt;/p&gt;
&lt;p&gt;We love ideas, experimenting, failing, and trying again, learning through trial and error. We love high energy. We speak quickly. And did I mention we often yell a lot? (Especially the Orange/Reds, but they’re kind of dickheads anyway).&lt;/p&gt;
&lt;p&gt;We get we’re intense. It’s just how we are. It’s honestly what is needed to get the job done. Please don’t hold it against us. Please don’t mistake it as Red.&lt;/p&gt;
&lt;h3&gt;An insatiable hunger&lt;/h3&gt;
&lt;p&gt;Underneath many Oranges is a hunger so intense that, seemingly, nothing will fill that gap (hint: this is one of its existential problems).&lt;/p&gt;
&lt;p&gt;An Orange always wants more. Always. More money, more sex, more travel, more experiences, more everything. And bigger. And better. Better each time. Don’t stop. Work for it. Just do it. Make it happen. Close the deal. Crush the market. Break through the barriers before you. Stop at nothing. Nothing.&lt;/p&gt;
&lt;p&gt;Are you beginning to see the problem?&lt;/p&gt;
&lt;p&gt;Are you listening Oranges?&lt;/p&gt;
&lt;p&gt;What are the effects of what you’re doing?&lt;/p&gt;
&lt;p&gt;How has the exploitive mining practices of your company in the South American Andes affected the local population? How long can your smear campaigns hide the fact you’re killing the local villagers?&lt;/p&gt;
&lt;p&gt;There’s only so long before Blue catches up, Mr. Invincible Tech God. And maybe more than just Blue.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The orange problem" src="http://spirals.blog/articles/orange-introduction/green.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Orange, when successfully living to solve Orange problems, creates other problems. Such is the nature of the Spiral. An excellent example of this is America during the COVID Crisis. The billionaires become trillionaires, while they complain on Twitter that Blues, Reds, and Purples don’t deserve a measly $600 per week because they lost their job to AI automation.&lt;/p&gt;
&lt;p&gt;How do we solve this? Blue can’t. It doesn’t have the complexity. So what do we do? Orange is all-powerful in today’s world. But it’s not invincible.&lt;/p&gt;
&lt;p&gt;That’s a topic for next time.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 26 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/orange-introduction/</guid></item><item><title>Please make your advice more specific</title><link>https://www.macchaffee.com/blog/2020/more-specifics/</link><description>&lt;p&gt;To those of you who give advice on which languages, methodologies, architectures, or whatever else to use, I want to start by saying thank you. Your advice is vital to the growth of millions of people like me who are early in their careers.&lt;/p&gt;
&lt;p&gt;But I've noticed a pattern with software engineering advice that leads to over-engineering and unnecessary arguments. So I have a request:&lt;/p&gt;
&lt;p align="center"&gt;&lt;em&gt;Please make your advice more specific&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It's too often overlooked that there isn't just one type of "software", thus it is rare for advice to be applicable to every situation. For example, advice for testing a small B2B web app might not work for embedded device firmware. But it might work for a large B2C web app. And since readers will rarely have experience in all of those situations, I think we should start being more explicit about the applicability of our advice.&lt;/p&gt;
&lt;p&gt;Being more specific might help address two big time sinks in the industry:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://en.wiktionary.org/wiki/cargo_culting"&gt;Cargo-culting&lt;/a&gt;, like when people read how great Kubernetes works for Netflix, but then they decide to use it for a little Django app (that was me a few years ago).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wiktionary.org/wiki/bikeshedding"&gt;Bikeshedding&lt;/a&gt;, like when people argue incessantly that a language is useless because it can't be used in some niche.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A good start might be answering questions like the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does your advice apply to my scale? (local restaurant website vs. Youtube.com)&lt;/li&gt;
&lt;li&gt;Does your advice apply to my type of product? (library, web app, CLI tool, firmware, on/off-premise, etc.)&lt;/li&gt;
&lt;li&gt;Does your advice apply to my type of users? (developers, enterprises, regular people, etc.)&lt;/li&gt;
&lt;li&gt;If not, what should I use instead? (like &lt;a href="https://adamdrake.com/command-line-tools-can-be-235x-faster-than-your-hadoop-cluster.html"&gt;replacing Hadoop with &lt;code&gt;find/xargs/awk&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, it's hard to find the right balance between hand-holding readers or just saying "buyer beware". But hopefully spending time to add an extra subheading on "Applicability" to READMEs or blog posts will pay for itself in time spent over-engineering and arguing over minutiae.&lt;/p&gt;</description><author>Mac's Tech Blog</author><pubDate>Sun, 26 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.macchaffee.com/blog/2020/more-specifics/</guid></item><item><title>Memory safety in Rust - part 1</title><link>https://hashrust.com/blog/memory-safey-in-rust-part-1/</link><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Did you know that around 70% serious security bugs in &lt;a href="https://www.chromium.org/Home/chromium-security/memory-safety" rel="external"&gt;Chrome&lt;/a&gt; and &lt;a href="https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/" rel="external"&gt;Microsoft's products&lt;/a&gt; are memory safety issues. &lt;a href="https://langui.sh/2019/07/23/apple-memory-safety/" rel="external"&gt;iOS, macOS&lt;/a&gt; and &lt;a href="https://security.googleblog.com/2019/05/queue-hardening-enhancements.html" rel="external"&gt;Android&lt;/a&gt; have similar numbers. Most of these security vulnerabilities occur because these software systems are written in memory unsafe languages like C and C++.&lt;/p&gt;
&lt;p&gt;In this first article of a two part series I will discuss the concept of memory safety and explain how it is linked with memory management. In the &lt;a href="https://hashrust.com/blog/memory-safety-in-rust-part-2/"&gt;next part&lt;/a&gt; I will talk about memory safety in Rust.&lt;/p&gt;
&lt;h2 id="memory-safety"&gt;Memory safety&lt;/h2&gt;
&lt;p&gt;While defining &lt;a href="http://www.pl-enthusiast.net/2014/07/21/memory-safety/" rel="external"&gt;memory safety&lt;/a&gt; can be &lt;a href="https://arxiv.org/pdf/1705.07354.pdf" rel="external"&gt;surprisingly subtle&lt;/a&gt;, an informal understanding will suffice for this article. In short, a program is memory safe if it does not access invalid memory. For example, in the following C program, writing to &lt;code&gt;buffer[8]&lt;/code&gt; is a &lt;a href="https://inst.eecs.berkeley.edu/~cs161/fa08/papers/stack_smashing.pdf" rel="external"&gt;buffer overflow&lt;/a&gt; bug because it writes past the last byte owned by the buffer:&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-storage"&gt;char&lt;/span&gt;&lt;span class="z-variable"&gt; buffer&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;8&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-variable"&gt;buffer&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;8&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; =&lt;/span&gt;&lt;span class="z-punctuation z-definition z-string z-string"&gt; 'x'&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;a href="https://blog.usejournal.com/binary-exploitation-buffer-overread-c8561e7c47f1" rel="external"&gt;buffer overread&lt;/a&gt; bug occurs when a program reads past the allocated memory. &lt;a href="https://heartbleed.com/" rel="external"&gt;Heartbleed&lt;/a&gt; was a buffer overread bug. Buffer overflow and overread bugs are easy to fix. The compiler just has to emit code to check bounds on every array access. While there is a little performance penalty, it is worth the cost.&lt;/p&gt;
&lt;p&gt;Another class of memory safety bugs are closely related to how memory is allocated and deallocated. &lt;a href="https://bufferoverflows.net/use-after-free-vulnerability-uaf/" rel="external"&gt;Use after free&lt;/a&gt; and &lt;a href="https://sensepost.com/blog/2017/linux-heap-exploitation-intro-series-riding-free-on-the-heap-double-free-attacks/" rel="external"&gt;double free&lt;/a&gt; are two examples of those. Unlike out of bounds access, remedies for these class of bugs are not as simple. To see why, we need to understand manual memory management.&lt;/p&gt;
&lt;h2 id="manual-memory-management"&gt;Manual memory management&lt;/h2&gt;
&lt;p&gt;In C the programmer is responsible for managing the memory. If the programmer has allocated a chunk of memory in their program using &lt;code&gt;malloc&lt;/code&gt;, it is their responsibility to release that chunk by calling &lt;code&gt;free&lt;/code&gt; exactly once. While this is a very simple rule, following it in any non-trivial program is very hard. Although rare, even the Linux kernel developers, who are world's top C programmers, make these &lt;a href="https://www.cvedetails.com/vulnerability-list/vendor_id-33/product_id-47/cvssscoremin-7/cvssscoremax-7.99/Linux-Linux-Kernel.html" rel="external"&gt;mistakes&lt;/a&gt;.
Since manual memory management is so tricky, can something be done about it?&lt;/p&gt;
&lt;h2 id="garbage-collection"&gt;Garbage collection&lt;/h2&gt;
&lt;p&gt;Can memory management be automated, such that the burden is taken off of the programmer? Garbage collection is an attempt at that. In garbage collected languages like Java and C#, the programmer is free to allocate memory but has no obligation to free it. The garbage collector keeps track of allocated memory that is no longer used and periodically reclaims it. While it works in providing memory safety, it comes at a performance cost due to the garbage collector running in the background.&lt;/p&gt;
&lt;p&gt;Moreover, the programmer has very limited control over when the garbage collector will run, making it difficult for latency sensitive programs like automated trading systems in maintaining the latency under a threshold. This lack of control extends to other areas of the language. For example, programmers also give up most of the control over whether to allocate on stack or heap. Fortunately there is an alternative to garbage collection.&lt;/p&gt;
&lt;h2 id="raii"&gt;RAII&lt;/h2&gt;
&lt;p&gt;RAII stands for Resource Acquisition Is Initialization. I find this acronym really bad at explaining what it does. The idea is much simpler — when a variable in a program is no longer used, free the memory owned by that variable. If the compiler can do this analysis, then it can insert the appropriate code to free the memory. This idiom first originated in C++ where its implementation piggybacks on the compiler generating calls to the destructor when a variable's lifetime ends.&lt;/p&gt;
&lt;p&gt;This approach has a couple of benefits. First, memory is freed much more deterministically — right after a variable holding that memory falls out of scope. And second, this technique is not limited to memory. Other resources like file handles, database connections etc. can also be cleaned up using the exact same approach. This is in contrast to garbage collection, which is responsible only for memory. Other resources in garbage-collected languages still need to be cleaned up manually.&lt;/p&gt;
&lt;p&gt;It looks like RAII solves all memory safety problems related to memory management and indeed modern C++ smart pointers, which are based on RAII, almost work. But &lt;a href="https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/" rel="external"&gt;C++ still falls short&lt;/a&gt;. In the next part, I will discuss how Rust does even better than C++ in achieving memory safety.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this article, I introduced the concept of memory safety. I discussed how some of the memory safety bugs are related to memory management and some techniques to avoid doing manual memory management. In the next part, I will focus on Rust's approach to memory safety.&lt;/p&gt;</description><author/><pubDate>Sat, 25 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hashrust.com/blog/memory-safey-in-rust-part-1/</guid></item><item><title>A single-node Kubernetes cluster without virtualization or a container registry</title><link>http://notes.eatonphil.com/a-single-node-kubernetes-cluster-without-virtualization-or-a-container-registry.html</link><description>&lt;p&gt;This post is a recipe for setting up a minimal Kubernetes cluster on
Fedora without requiring virtualization or a container registry. These
two features make the system cloud-agnostic and the cluster entirely
self-contained. The post will end with us running a simple Flask app
from a local container.&lt;/p&gt;
&lt;p&gt;This setup is primarily useful for simple CI environments or
application development on Linux. (Docker Desktop has better tooling
for development on Mac or Windows.)&lt;/p&gt;
&lt;h3 id="getting-kubernetes"&gt;Getting Kubernetes&lt;/h3&gt;&lt;p&gt;The core of this effort is &lt;a href="https://k3s.io/"&gt;K3s&lt;/a&gt;, a Kubernetes
distribution that allows us to run on a single node without
virtualization.&lt;/p&gt;
&lt;p&gt;But first off, &lt;a href="https://docs.docker.com/engine/install/fedora/"&gt;install Docker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then install K3s:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-sfL&lt;span class="w"&gt; &lt;/span&gt;https://get.k3s.io&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sh&lt;span class="w"&gt; &lt;/span&gt;-
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It may prompt you to adjust some SELinux policies like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;dnf&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-y&lt;span class="w"&gt; &lt;/span&gt;container-selinux&lt;span class="w"&gt; &lt;/span&gt;selinux-policy-base
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;rpm&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;https://rpm.rancher.io/k3s-selinux-0.1.1-rc1.el7.noarch.rpm
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Swap these out with whatever it prompts and retry the K3s install.&lt;/p&gt;
&lt;p&gt;Finally, &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/"&gt;install
kubectl&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-LO&lt;span class="w"&gt; &lt;/span&gt;https://storage.googleapis.com/kubernetes-release/release/&lt;span class="sb"&gt;`&lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;https://storage.googleapis.com/kubernetes-release/release/stable.txt&lt;span class="sb"&gt;`&lt;/span&gt;/bin/linux/amd64/kubectl
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now copy the global K3s kubeconfig into &lt;code&gt;~/.kube/config&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;/etc/rancher/k3s/k3s.yaml&lt;span class="w"&gt; &lt;/span&gt;~/.kube/config
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;chown&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$USER&lt;/span&gt;:&lt;span class="nv"&gt;$GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/.kube/config
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And enable K3s:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;k3s
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you're on Fedora 31+ you'll need to disable cgroups v2 and reboot:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;grubby&lt;span class="w"&gt; &lt;/span&gt;--args&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;systemd.unified_cgroup_hierarchy=0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--update-kernel&lt;span class="o"&gt;=&lt;/span&gt;ALL
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;reboot
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, you can run &lt;code&gt;kubectl&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;pods
No&lt;span class="w"&gt; &lt;/span&gt;resources&lt;span class="w"&gt; &lt;/span&gt;found&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;default&lt;span class="w"&gt; &lt;/span&gt;namespace.
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="a-simple-application"&gt;A simple application&lt;/h3&gt;&lt;p&gt;We'll create a small Flask app, containerize it, and write a
Kubernetes deployment and service config for it.&lt;/p&gt;
&lt;p&gt;We begin with &lt;code&gt;app.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'Hello World, Flask!'&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'__main__'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then a &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;python:3-slim&lt;/span&gt;

&lt;span class="k"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;flask
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;/app

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python3&lt;span class="w"&gt; &lt;/span&gt;/app/app.py
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then the deployment in &lt;code&gt;manifest.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;apps/v1&lt;/span&gt;
&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Deployment&lt;/span&gt;
&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;helloworld&lt;/span&gt;
&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;matchLabels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;helloworld&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;helloworld&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;helloworld&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;helloworld&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id="running-in-kubernetes"&gt;Running in Kubernetes&lt;/h3&gt;&lt;p&gt;First we build, save, and import the image into &lt;code&gt;k3s&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tar&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;k3s&lt;/span&gt; &lt;span class="n"&gt;ctr&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;helloworld.tar&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;kubectl&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;manifest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yaml&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;kubectl&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kubectl&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;pods&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;grep&lt;/span&gt; &lt;span class="n"&gt;helloworld&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;cut&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;curl&lt;/span&gt; &lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;
&lt;span class="n"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;World&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And that's it!&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Latest post is a recipe for creating a self-contained, single-node Kubernetes cluster for CI environments using a basic Flask app.&lt;a href="https://t.co/fegAZFEQzO"&gt;https://t.co/fegAZFEQzO&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1287163839306444800?ref_src=twsrc%5Etfw"&gt;July 25, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sat, 25 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/a-single-node-kubernetes-cluster-without-virtualization-or-a-container-registry.html</guid></item><item><title>Linux - Ubuntu initial dev setup</title><link>https://pankajpipada.com/posts/2020-07-24-ubuntu-setup/</link><description>Initial dev setup for Ubuntu Linux.</description><author>Scramblings</author><pubDate>Fri, 24 Jul 2020 08:30:00 GMT</pubDate><guid isPermaLink="true">https://pankajpipada.com/posts/2020-07-24-ubuntu-setup/</guid></item><item><title>SUP to Discovery Park Lighthouse</title><link>https://sam.hooke.me/trip/2020/07/discovery-park-lighthouse/</link><description>&lt;div id="map-main"&gt;&lt;/div&gt;




&lt;p&gt;No trip report yet.&lt;/p&gt;</description><author>Sam Hooke</author><pubDate>Fri, 24 Jul 2020 06:00:00 GMT</pubDate><guid isPermaLink="true">https://sam.hooke.me/trip/2020/07/discovery-park-lighthouse/</guid></item><item><title>8 Landing Page Tips from Rob Hope</title><link>https://www.swyx.io/8-landing-page-tips-from-rob-hope-338l</link><description>I submitted my book's landing page for Rob Hope's review and he obliged! Brutal feedback incoming.</description><author>swyx's site RSS Feed</author><pubDate>Fri, 24 Jul 2020 01:19:19 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/8-landing-page-tips-from-rob-hope-338l</guid></item><item><title>8 Q&amp;amp;A's for Bootcamp Students in 2020</title><link>https://www.swyx.io/8-q-a-s-for-pre-bootcamp-students-in-2020-1phh</link><description>I did a Q&amp;amp;A for Fullstack Academy Bootcamp Prep students - copying out my answers here!</description><author>swyx's site RSS Feed</author><pubDate>Thu, 23 Jul 2020 20:37:24 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/8-q-a-s-for-pre-bootcamp-students-in-2020-1phh</guid></item><item><title>Unofficial VS Code Snippets for AWS Amplify</title><link>https://www.swyx.io/unofficial-vs-code-snippets-for-aws-amplify-1959</link><description>making my own vs code snippets helpers for working with AWS Amplify</description><author>swyx's site RSS Feed</author><pubDate>Thu, 23 Jul 2020 19:08:16 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/unofficial-vs-code-snippets-for-aws-amplify-1959</guid></item><item><title>Frustrated by Formik? Here's a simpler way to do forms in React</title><link>https://maxrozen.com/frustrated-formik-simpler-react-forms</link><description>Do you find yourself struggling for hours to solve problems with Formik? I've started using a different library that's much simpler.</description><author>Max Rozen</author><pubDate>Thu, 23 Jul 2020 18:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/frustrated-formik-simpler-react-forms</guid></item><item><title>Musings on an unexpected motorcycle trip</title><link>https://nicolaiarocci.com/musings-on-an-unexpected-motorcycle-trip/</link><description>&lt;p&gt;I went on a motorcycle trip. A fellow TOMCC&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; member was planning a solo
trip to Campo Imperatore (&amp;ldquo;Emperor&amp;rsquo;s Fields&amp;rdquo;), the well known alpine
meadow in the Apennine ridge. He called me as he was looking for some advice,
and well, I ended up joining him.&lt;/p&gt;
&lt;p&gt;What sparked my interest was the destination, of course, because Campo
Imperatore is a superb place to visit, especially on a motorcycle, but also
Antonio&amp;rsquo;s peculiar take on the journey. By self-admission, he is old-school.
His motorcycle forays, no matter how long they are, all have something in
common: as little technology as possible. He also goes out of his league to
avoid highways and, god forbid, toll-roads. He is keen on secondary roads and,
most importantly, he does not plan any route. Antonio will write down a few
waypoints on paper, just the names of maybe two or three places worth visiting,
and that&amp;rsquo;s it. If the trip is going to be very long, he might take a (paper)
road atlas with him. The little details, like filling the gaps between
waypoints, or how one would go to reach the waypoints themselves, well, they
are all left out for the adventure.&lt;/p&gt;</description><author>Nicola Iarocci</author><pubDate>Thu, 23 Jul 2020 08:05:25 GMT</pubDate><guid isPermaLink="true">https://nicolaiarocci.com/musings-on-an-unexpected-motorcycle-trip/</guid></item><item><title>You don't need no Service Mesh</title><link>https://serce.me/posts/2020-07-23-you-dont-need-no-service-mesh</link><description>In this article, I explore an anti-hype opinion on service meshes and aim to provide a clearer perspective on whether they are the right solution for specific problems.</description><author>SerCe's blog</author><pubDate>Thu, 23 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://serce.me/posts/2020-07-23-you-dont-need-no-service-mesh</guid></item><item><title>From Dev to Devrel</title><link>https://justingarrison.com/blog/2020-07-23-dev-to-devrel/</link><description>My experience switching from an engineer to a developer advocate</description><author>Justin Garrison's Homepage</author><pubDate>Thu, 23 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://justingarrison.com/blog/2020-07-23-dev-to-devrel/</guid></item><item><title>The little Wi-Fi AP that could</title><link>https://ounapuu.ee/posts/2020/07/23/the-little-wifi-ap-that-could/</link><description>Depends on your definition of _could_.</description><author>./techtipsy</author><pubDate>Thu, 23 Jul 2020 01:17:30 GMT</pubDate><guid isPermaLink="true">https://ounapuu.ee/posts/2020/07/23/the-little-wifi-ap-that-could/</guid></item><item><title>Reshoring Supply Chains: A Practical Policy Agenda</title><link>https://americanaffairsjournal.org./2020/05/reshoring-supply-chains-a-practical-policy-agenda/</link><description>&lt;p&gt;Outsourcing has put America in a precarious position. It quietly became one of the greatest threats to national security over the course of several decades, unrealized until the Coronavirus pan(dem)ic revealed the fragility of our situation. David Adler and Dan Breznitz, in the American Affairs Journal, discuss the issue and offer some concrete suggestions for fixing it. I encourage you to give it a read. See also: &lt;a href="http://berthub.eu/articles/posts/national-outsourcing/"&gt;&lt;em&gt;On National and Enterprise Outsourcing&lt;/em&gt;&lt;/a&gt;, and &lt;a href="https://pdfs.semanticscholar.org/e9da/f5cc1c94c6e34e29095ca168e8fa2d750df9.pdf"&gt;&lt;em&gt;Out-Sourced Profits: The Cornerstone of Successful Subcontracting&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;


                &lt;p&gt;&lt;a href="https://americanaffairsjournal.org./2020/05/reshoring-supply-chains-a-practical-policy-agenda/"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Wed, 22 Jul 2020 18:07:18 GMT</pubDate><guid isPermaLink="true">https://americanaffairsjournal.org./2020/05/reshoring-supply-chains-a-practical-policy-agenda/</guid></item><item><title>Consolidating Multiple Lightroom Catalogs onto a NAS</title><link>http://evantravers.com/articles/2020/07/22/consolidating-multiple-lightroom-catalogs-onto-a-nas/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/07/lightroom_transition.png" /&gt;&lt;/p&gt;&lt;p&gt;I referenced in &lt;a href="https://twitter.com/evantravers/status/1285761066769756160"&gt;a recent tweet&lt;/a&gt; that I've been struggling with how to store my photography library. I have been researching, experimenting, and working on this for months now. I don't think I found a full guide for all this, so I decided to write it up so that maybe I can help one other person.&lt;/p&gt;
&lt;p&gt;For years, I had simply been buying progressively bigger external hard drives… usually in pairs so that I would have a back up. After getting two cameras that shot 24MP and above… that strategy really got outpaced by the sheer volume of data my lovely wife shot this past fall.&lt;/p&gt;
&lt;p&gt;In desperation, I eventually settled on a complicated &amp;quot;multiple catalog&amp;quot; scheme. I split out our family history photo Catalog on one 2TB drive, and putting each professional shoot in a new Catalog on subsequent drives as they filled up. This strategy allowed my wife and I collaborate on a shoot simply by passing the hard drive with the photos and Catalog on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Some quick context&lt;/strong&gt;: Lightroom's photo management has two parts: A Catalog file, and the photo files. The Catalog stores all the metadata and edits, and points to the photo files. For some reason, Lightroom won't accept Catalogs on network drives, but the photo files themselves can live on a network drive or NAS.&lt;/p&gt;
&lt;p&gt;The &amp;quot;multiple catalog&amp;quot; strategy meant that I kept together each Project Catalog and its corresponding Photo Files in a folder on an external hard drive. While I couldn't search across my whole collection, but I could manage them in chunks… which at least let me make sure that each chunk had a backup on another drive. (This led to a crazy-making spreadsheet that listed each drive, each Project Catalog, and where it's backup was located, and how old that backup was… 🤦)&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="" src="https://images.evantravers.com/articles/2020/07/drives.jpg" /&gt;
  &lt;figcaption&gt;
    &lt;b&gt;Some&lt;/b&gt; of the drives that I have been juggling... it's a nightmare.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This all worked fine… until I ran out of room on the Family History Photo Catalog drive! I was faced with buying two more 5TB drives, one for the main and one for a periodic backup… and I realized that I would basically be in the price range of just buying a NAS like a Synology or a Drobo. (I wound up on a &lt;a href="https://www.amazon.com/gp/product/B075MZTQBT/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1"&gt;Synology DS718+&lt;/a&gt; and I like it, but there's lots of better resources comparing and selling different devices.) While I started saving, I started scheming how to move the diaspora Project Catalogs back to the promised land of a single source of truth…&lt;/p&gt;
&lt;p&gt;It took a lot of experiments, researching videos and blog posts, but here's what I settled on.&lt;/p&gt;
&lt;p&gt;We want to end up in a state with a &lt;em&gt;single&lt;/em&gt; Main Catalog, pointing at files on the NAS. To accomplish this, we will first make sure all the files are safe on the NAS. Then we will individually point all the Catalogs at the files on the NAS. Finally, we will merge together the catalogs and ensure the data is safe.&lt;/p&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Copy all the individual Catalogs to the NAS via USB.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connect up the Synology to your working computer (network mount or whatever.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For each Project Catalog, open it up. We are going to redirect this Project Catalog to the newly copied files on the NAS. Use &lt;code&gt;Update Folder Location…&lt;/code&gt; from the folder on the original source (in my case, an external drive named LaCie) to the new location on the Synology.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Update Folder Location" src="https://images.evantravers.com/articles/2020/07/update_folder_location.png" /&gt;&lt;/p&gt;
&lt;p&gt;Now your catalog has all the edits and metadata, but it's pointed away from your external drive to the network drive. 👍&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch back to your Main Catalog. (I just used the entry in the &lt;code&gt;Open Recent…&lt;/code&gt; menu.)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Switch to catalog" src="https://images.evantravers.com/articles/2020/07/open_recent.png" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select from the File menubar: &lt;code&gt;Import from Another Catalog…&lt;/code&gt; and choose the Project Catalog you &lt;em&gt;just&lt;/em&gt; updated that now points to photos on the Synology.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Import from another catalog" src="https://images.evantravers.com/articles/2020/07/import_from_another_catalog.png" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For File Handling, choose &lt;code&gt;Add New Photos to Catalog Without Moving&lt;/code&gt;.&lt;/p&gt;
 &lt;figure&gt;
   &lt;img alt="import dialog" src="https://images.evantravers.com/articles/2020/07/import_from_catalog.png" /&gt;
   &lt;figcaption&gt;
     If you choose the option for moving the files, this import can take fifteen minutes… I think it compares each file over the network, and that's &lt;em&gt;very&lt;/em&gt; slow. By choosing to take the photos where they are, the merged metadata from the newly re-pointed Project Catalog merges into your Main Catalog pointing at files on the NAS, &lt;em&gt;much&lt;/em&gt; faster.
   &lt;/figcaption&gt;
 &lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now that the Catalogs have merged, your File pane on the left should show the fact that you have multiple folders at play. You could leave it like this, but I wanted all my photos in one folder structure to make backup to online easier. Move the folder(s) into your desired folder structure.&lt;/p&gt;
 &lt;figure&gt;
   &lt;img alt="move files" src="https://images.evantravers.com/articles/2020/07/moving_files_on_disk.png" /&gt;
   &lt;figcaption&gt;
     &lt;ul&gt;
       &lt;li&gt;If there are no conflicts (usually the case) it takes milliseconds.&lt;/li&gt;
       &lt;li&gt;If there is a folder existing in that space, you can either rename the folder to something related to the shoot (John and Jane Doe's Wedding) or drag all the files over to the folder individually… but this will take much more time.&lt;/li&gt;
     &lt;/ul&gt;
   &lt;/figcaption&gt;
 &lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;At this point, I usually make sure everything worked right. I'll typically right click on a photo in the Gallery and choose &lt;code&gt;Show in Finder&lt;/code&gt; and &lt;code&gt;Show in Library&lt;/code&gt; to ensure this photo is in the right folder on the filesystem and the right place in the Lightroom Library.&lt;/p&gt;
&lt;p&gt;&lt;img alt="show in finder" src="https://images.evantravers.com/articles/2020/07/show_in_finder.png" /&gt;&lt;/p&gt;
 &lt;figure&gt;
   &lt;img alt="correct path" src="https://images.evantravers.com/articles/2020/07/correct_path.png" /&gt;
   &lt;figcaption&gt;Looks like the file is on the Network Drive! Success!&lt;/figcaption&gt;
 &lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can now safely remove the duplicate or empty folders in Lightroom Catalog.&lt;/p&gt;
&lt;p&gt;&lt;img alt="remove empty" src="https://images.evantravers.com/articles/2020/07/remove_empty_folder.png" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Obsessively check and re-check to make sure you aren't losing anything, then remove and clean up the old folders outside your new organized folder.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img alt="phew" src="https://media0.giphy.com/media/z23hGvopHu7w4/giphy.gif?cid=ecf05e47vafx64iaq263cmk1lqr9bi70zo91lqmckn2ay125&amp;amp;rid=giphy.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Phew! We are done. Y'all would &lt;em&gt;not&lt;/em&gt; believe the relief I felt when I merged the last one, clicked around, and knew for certain where all my data was and that it was on a redundant drive.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="correct path" src="https://images.evantravers.com/articles/2020/07/finished.png" /&gt;
  &lt;figcaption&gt;That's a &lt;em&gt;lot&lt;/em&gt; of photos.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Going forward, I will use a modified version of this process. Since the local SSD is faster than the network drive by a long shot, I'll work each shoot on a new Catalog local to that laptop. After I'm done, I'll use the merge workflow above to move all the files and merge the metadata into my Main Catalog.&lt;/p&gt;</description><author>trv.rs</author><pubDate>Wed, 22 Jul 2020 13:47:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/07/22/consolidating-multiple-lightroom-catalogs-onto-a-nas/</guid></item><item><title>The Fourth Discontinuity: The Co-Evolution of Humans and Machines</title><link>https://macleodsawyer.com/library/the-fourth-discontinuity-the-co-evolution-of-humans-and-machines/</link><description>&lt;blockquote&gt;
&lt;p&gt;From Mary Shelley’s &lt;em&gt;Frankenstein&lt;/em&gt; to current films like &lt;em&gt;The Terminator&lt;/em&gt; about menacing androids, writers have expressed concern about computers and biogenetic creations taking over or altering human life. In this engrossing and lively book, Bruce Mazlish discusses the complex relationship between humans and machines, pondering the implications of humans becoming more mechanical (our bodies increasingly hooked up to artificial parts), and of computer robots being programmed to think.&lt;br /&gt;
&lt;br /&gt;
Mazlish argues that just as Copernicus, Darwin, and Freud overturned our illusions of separation from and domination over the cosmos, the animal world, and the unconscious, it is now necessary to relinquish a fourth fallacy or discontinuity–that humans are discontinuous and distinct from the machines they make. Drawing on history and legend, science and science fiction, Mazlish examines how events and individuals have shaped the ways that humans relate to machines. He describes early Greek and Chinese automatons (forerunners of the robot); he discusses the seventeenth-century debate over what was called the “animal machine”; he shows how the Industrial Revolution created a truly mechanical civilization; he looks at what thinkers such as Descartes, Linnaeus, Darwin, Freud, Pavlov, Charles Babbage, T.H. Huxley, and Samuel Butler contributed to our understanding of human nature as contrasted with animal or machine; and he surveys the modern revolutions in biogenetics and computer and brain sciences that have brought humans and machines closer together than ever before. Mazlish argues provocatively that human nature is best understood in the context of the machines and tools we have created and that humans and our creations—computer robots—will eventually evolve into two new species coexisting in a symbiotic relationship.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;From &lt;a href="https://yalebooks.yale.edu/book/9780300065121/fourth-discontinuity"&gt;Yale University Press&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Wed, 22 Jul 2020 10:23:37 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/library/the-fourth-discontinuity-the-co-evolution-of-humans-and-machines/</guid></item><item><title>Links - July 22, 2020</title><link>https://faingezicht.com/links/2020/07/22/links/</link><description/><author>Avy Faingezicht</author><pubDate>Wed, 22 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/links/2020/07/22/links/</guid></item><item><title>Run your containers as non-root</title><link>https://ricardoanderegg.com/posts/local-files-permissions-docker-non-root-security/</link><description>&lt;p&gt;Docker runs as root. The programs executing inside containers too. Make it a bit better.&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;# do everything you need as root (maybe installing some dependencies)&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic;"&gt;# create a non-root user&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;RUN&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;addgroup&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;--gid&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold;"&gt;1001&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;appgroup
&lt;span style="color: #204A87; font-weight: bold;"&gt;RUN&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;useradd&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;--create-home&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;--gid&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold;"&gt;1001&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;--uid&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold;"&gt;1001&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;appuser

&lt;span style="color: #8F5902; font-style: italic;"&gt;# set new workdir&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;WORKDIR&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;/home/appuser&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic;"&gt;# activate non-root user&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;USER&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;appuser&lt;/span&gt;

&lt;span style="color: #8F5902; font-style: italic;"&gt;# copy new files with correct permissions&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;COPY&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;--chown&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;appuser:appgroup&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;app.py&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you need to mount or use files from your file system, give permissions to the UID/GID defined above:&lt;/p&gt;</description><author>Posts on rand[om]</author><pubDate>Wed, 22 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ricardoanderegg.com/posts/local-files-permissions-docker-non-root-security/</guid></item><item><title>Apollo vs Relay Modern: An unbiased look at which GraphQL client to use</title><link>https://maxrozen.com/apollo-vs-relay-which-graphql-client-to-use-2019</link><description>If you're building an app using GraphQL, picking a client to use can be hard. Apollo? Relay? Urql? Let's look into some options.</description><author>Max Rozen</author><pubDate>Wed, 22 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/apollo-vs-relay-which-graphql-client-to-use-2019</guid></item><item><title>Transitioning to GUI'd Emacs on macOS</title><link>https://lambdaland.org/posts/2020-07-22-gui-emacs/</link><description>&lt;p&gt;I went on an adventure today. I left behind the stable comforts of the terminal and compiled bleeding-edge Emacs that uses a native window system.&lt;/p&gt;
&lt;p&gt;This is a big deal for me. As long as I can remember, I’ve used Emacs from within a terminal. I’ve decided to give the GUI’d Emacs a whirl.&lt;/p&gt;
&lt;h2 id="my-journey"&gt;My Journey&lt;/h2&gt;
&lt;p&gt;I’m running macOS Catalina (10.15.5). Originally I tried using the pre-built packages via brew (&lt;code&gt;brew cask install emacs&lt;/code&gt;) and those available at &lt;a class="link-external" href="https://emacsformacosx.com" rel="external"&gt;Emacs for Mac OS X&lt;/a&gt;. However, all these pre-built binaries crashed on Catalina. I guess it’s a problem with Catalina. 🙄&lt;/p&gt;
&lt;p&gt;So, I decided to try building from source. I cloned the Emacs source code directly from &lt;a class="link-external" href="https://git.savannah.gnu.org/git/emacs.git" rel="external"&gt;Savannah&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ git clone https://git.savannah.gnu.org/git/emacs.git&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I cd’d into that directory:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ cd emacs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point you’ve got the bleeding-edge development Emacs. You might want to check out and pull a different branch or tag. I decided to check out the &lt;a class="link-external" href="https://www.reddit.com/r/emacs/comments/g9vdd0/bringing_gnu_emacs_to_native_code_at_the_european/" rel="external"&gt;native-compilation&lt;/a&gt; branch:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ git checkout feature/native-comp&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;$ git pull origin feature/native-comp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(I’m pretty sure those are the right commands; stuff got a little funky while I was building.)&lt;/p&gt;
&lt;p&gt;I exported a magic&lt;sup class="footnote-reference" id="fr-1-1"&gt;&lt;a href="https://lambdaland.org/posts/2020-07-22-gui-emacs/#fn-1"&gt;1&lt;/a&gt;&lt;/sup&gt; environment variable that I got from a &lt;a class="link-external" href="https://emacs.stackexchange.com/a/54433/19088" rel="external"&gt;helpful Emacs StackExchange post&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ export LIBXML2_CFLAGS=&amp;quot;-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After exporting that variable, I ran &lt;code&gt;configure&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ ./configure&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then I ran &lt;code&gt;make&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ make&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That will create a binary at &lt;code&gt;src/emacs&lt;/code&gt; that you can run to test to make sure that all is working as it should. If you’re satisfied with that emacs configuration, you can bundle it up into a stand-alone application:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ make install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create &lt;code&gt;Emacs.app&lt;/code&gt; inside of the &lt;code&gt;nextstep/&lt;/code&gt; directory. You are free to move that around:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;$ mv nextstep/Emacs.app /Applications/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also went into &lt;code&gt;System Preferences &amp;gt; Security&lt;/code&gt; and gave Emacs Full Disk Access. I heard of some people having difficulty accessing iCloud files from Emacs and this cleared it up. I haven’t had any difficulty—I just wanted Emacs to have full access anyway.&lt;/p&gt;
&lt;h2 id="niceties"&gt;Niceties&lt;/h2&gt;
&lt;p&gt;I still use the terminal a &lt;em&gt;lot&lt;/em&gt; (though I might use it less directly if I can get comfortable with &lt;code&gt;ansi-term&lt;/code&gt; mode) so I made a few shortcuts for myself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I symlinked &lt;code&gt;/usr/local/bin/emacs&lt;/code&gt; to &lt;code&gt;/Applications/Emacs.app/Contents/MacOS/Emacs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt; $ cd /usr/local/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt; $ ln -s /Applications/Emacs.app/Contents/MacOS/Emacs emacs&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;/usr/local/bin&lt;/code&gt; is already in my &lt;code&gt;PATH&lt;/code&gt;, so now I can just type &lt;code&gt;emacs&lt;/code&gt; on the command line and it will fire it up just as it used to&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I created an alias like this in my &lt;code&gt;.zshrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt; alias 'e'='emacs -nw'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That way, when I’m in a terminal and type &lt;code&gt;e &amp;lt;filename&amp;gt;&lt;/code&gt; it will open up the file in Emacs &lt;em&gt;in the terminal&lt;/em&gt;. I might change that behavior at some point in the future, but that will help me transition for the time being.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I installed the &lt;a class="link-external" href="https://github.com/purcell/exec-path-from-shell" rel="external"&gt;exec-path-from-shell package&lt;/a&gt; so that Emacs could fire off processes like &lt;code&gt;elixir&lt;/code&gt; when using &lt;code&gt;lsp-mode&lt;/code&gt;. Otherwise, you get errors like this inside the &lt;code&gt;*lsp::stderr*&lt;/code&gt; buffer:&lt;/p&gt;
&lt;pre class="giallo" style="color: #D8DEE9; background-color: #2E3440;"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt; line 66: exec: elixir: not found&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Why did I do this? Because I was a little bored. I also wanted to experiment with some of the more extensive key binding opportunities that a full-bodied Emacs offers.&lt;/p&gt;
&lt;p&gt;I’ll write updates to my blog as time goes on. I might decide to switch back to regular-old Emacs in the terminal. Right now, however, I’m enjoying the GUI’d version.&lt;/p&gt;
&lt;p&gt;You can see my Emacs config on &lt;a class="link-external" href="https://github.com/ashton314/.dotfiles" rel="external"&gt;my GitHub&lt;/a&gt;. Feel free to drop me a line if you have any questions.&lt;/p&gt;
&lt;h2 id="update-2020-07-23"&gt;UPDATE 2020-07-23&lt;/h2&gt;
&lt;p&gt;After using Emacs 28.0.5 for a day, here’s what I came away with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;No crashes. Things did start getting a little strange when I tried selecting text with the mouse in ansi-term without switching from character-mode to line-mode; I ended up killing that ansi-term session and creating a new one.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I really missed having frames all in the same place and switching between them with &lt;code&gt;C-x 5 o&lt;/code&gt;. I found a &lt;em&gt;very&lt;/em&gt; acceptable replacement; as of Emacs 27, you can enable the built-in &lt;code&gt;tab-bar-mode&lt;/code&gt; and switch between “tabs” with &lt;code&gt;C-x t o&lt;/code&gt;, create new ones with &lt;code&gt;C-x t 2&lt;/code&gt;, etc. It looks just like switching between frames does in the terminal, minus the display of which tab you’re on. I haven’t figured out how to turn that on yet.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using the tab-bar stuff, I created a tab and fired up ansi-term. I was able to switch back and forth between my editor tab and the console tab as I would between iTerm tabs or if I were using &lt;code&gt;C-z&lt;/code&gt; to suspend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inputting special characters via the keyboard has changed. No longer can I hit &lt;code&gt;alt-shift--&lt;/code&gt; to insert an em-dash. Instead, I turn on TeX mode input (&lt;code&gt;C-\ TeX RET&lt;/code&gt;) and I can type the TeX character sequence (in the case of an em-dash, you just type a normal dash three times) and it will be inserted into the buffer.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, I’m finding this switch a decently comfortable one. I’m not giving up very much, and I’m gaining a decent amount. I’ve had some difficulty getting all the colors in the theme how I like them—I might just give up for a bit and see if I get used to them.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol class="footnotes-list"&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;I’m not entirely sure what it does. I know that it didn’t work before using this environment variable, and now it works after I tried using it. &lt;a href="https://lambdaland.org/posts/2020-07-22-gui-emacs/#fr-1-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>Lambda Land</author><pubDate>Wed, 22 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-07-22-gui-emacs/</guid></item><item><title>The sad, slow-motion death of Do Not Track</title><link>https://lwn.net/Articles/826575/</link><description>Talks about the valiant but almost-dead 10-year effort to prevent tracking with the Do Not Track header.</description><author>Ben Hoyt's technical writing</author><pubDate>Wed, 22 Jul 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/826575/</guid></item><item><title>Books every developer should read</title><link>https://maxrozen.com/books-every-developer-should-read</link><description>Whether you want to start a career as a developer, or have been a developer for 20 years, you should check out these books.</description><author>Max Rozen</author><pubDate>Tue, 21 Jul 2020 18:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/books-every-developer-should-read</guid></item><item><title>Your (Lossy) Walled Garden</title><link>https://one.mikro2nd.net/pages/your-lossy-walled-garden/</link><description>Everybody&amp;rsquo;s Trying to Build Walled Gardens Increasingly I&amp;rsquo;m running across the following situation: I see a teaser-with-a-link somewhere on the &amp;rsquo;net (likely Twitter or HN) that piques my interest. Perhaps its relevant to something I&amp;rsquo;m thinking about or working on. I click the link.
I find myself on some website or other — Squatify, Shrugstack, BlinkedIn, whatever — and they won&amp;rsquo;t allow me to read/listen/watch the stuff I came to look at without signing in.</description><author>one mikro2nd</author><pubDate>Tue, 21 Jul 2020 14:36:59 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/your-lossy-walled-garden/</guid></item><item><title>Tuesday roundup for 2020-07-21</title><link>https://rjp.is/blogging/posts/2020-07-21-roundup/</link><description>Various things, links, and excitement.</description><author>infrequent oscillations</author><pubDate>Tue, 21 Jul 2020 13:31:28 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020-07-21-roundup/</guid></item><item><title>What is the Hardest Hangman Word?</title><link>https://blog.lukesalamone.com/posts/hardest-hangman-word/</link><description>&lt;p&gt;&lt;img alt="Example hangman game" src="https://i.imgur.com/p33HisS.png" /&gt;&lt;/p&gt;
&lt;p&gt;It seems like a simple enough question. Which word should you choose so that it takes your opponent the most guesses to discover it? Should you choose a long word to use up your opponent&amp;rsquo;s guesses? Or perhaps a short word with obscure letters? In this document I look into this question. But first, a bit of background.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re not familiar with the rules of hangman, it is a guessing game played between two people. Player A chooses a secret word, and tells player B the length of the secret word. Player B guesses letters which she thinks might be in the word. If she chooses a correct letter, player A reveals the locations of &lt;em&gt;each instance&lt;/em&gt; of the guessed letter. However, if player B guesses an incorrect letter, this counts as a &amp;ldquo;strike&amp;rdquo; against her. After an agreed-upon number of strikes, player B loses.&lt;/p&gt;</description><author>Luke Salamone's Blog</author><pubDate>Tue, 21 Jul 2020 12:34:05 GMT</pubDate><guid isPermaLink="true">https://blog.lukesalamone.com/posts/hardest-hangman-word/</guid></item><item><title>Monitoring Your Own Infrastructure Using Grafana, InfluxDB, and CollectD</title><link>https://serhack.me/articles/monitoring-infrastructure-grafana-influxdb-connectd/</link><description>For some companies, infrastructure is the heart of its business. Specifically, I am referring to those companies which need to manage data and applications located on more than one server. -&lt;a href="https://serhack.me/articles/monitoring-infrastructure-grafana-influxdb-connectd/"&gt;Continue to read the article on SerHack.me&lt;/a&gt;</description><author>SerHack - Security Researcher</author><pubDate>Tue, 21 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://serhack.me/articles/monitoring-infrastructure-grafana-influxdb-connectd/</guid></item><item><title>Housing as UBI</title><link>https://nutcroft.mataroa.blog/blog/housing-as-ubi/</link><description>&lt;h2 id="unthinkability"&gt;Unthinkability&lt;/h2&gt;
&lt;p&gt;It's unthinkable that in 2020 not everyone lives in a home. Home, as in the most simple, barebones place that one can sleep and get shelter from the rain and cold.&lt;/p&gt;
&lt;p&gt;It's even more unthinkable that in the world's richest cities and countries, this statement is still true.&lt;/p&gt;
&lt;p&gt;And finally, it is unthinkable in terms of Paul Graham's &lt;a href="http://www.paulgraham.com/startupideas.html#self"&gt;future present&lt;/a&gt;, that artists, makers, innovators, and inventors are pushed out of cities because &lt;em&gt;&lt;a href="http://wintermute.org/brendan/?e=168"&gt;the rent is too damn high&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="in-order-of-importance"&gt;In order of importance&lt;/h2&gt;
&lt;p&gt;One could condemn the above argument inasmuch as housing is more difficult than anything else we have achieved in 2020. Yet the constantly rising number of empty homes, &lt;a href="https://www.theguardian.com/society/2019/mar/11/empty-homes-england-rises-property"&gt;in London&lt;/a&gt; for example, and other major urban centres, proves that this is not a case of feasibility, but rather of profitability.&lt;/p&gt;
&lt;p&gt;Home and &lt;a href="https://www.nrdc.org/resources/wasted-how-america-losing-40-percent-its-food-farm-fork-landfill"&gt;food waste&lt;/a&gt; are both issues of economic equality, rather than resource scarcity. Their resolution will mean substantial life quality boost on a global scale.&lt;/p&gt;
&lt;p&gt;Housing in particular seems to be the immediate next step for life quality. For lower social strata, rent is the single largest expense that cannot be reduced unless one devolves into homelessness. &lt;a href="https://en.wikipedia.org/wiki/Basic_income"&gt;UBI&lt;/a&gt; is what has been increasingly brought up as the solution for the problems automation creates in the future of work, yet if we could subtract rent from the monthly budget of low income workers, we might not even need UBI.&lt;/p&gt;
&lt;h2 id="antithesis"&gt;Antithesis&lt;/h2&gt;
&lt;p&gt;Ultra cheap housing shares some of the problems of UBI. To name one: if people aren't mandated to work to survive, why would they?&lt;/p&gt;
&lt;p&gt;There is &lt;a href="https://en.wikipedia.org/wiki/Basic_income_pilots"&gt;not enough research&lt;/a&gt; on the matter, but it feels obvious that if housing was cheap (or UBI guaranteed) nobody would work as a low-paid unskilled worker ever again. They would either live a workless life or acquire knowledge to assume a more pivotal role for the professional part of their life.&lt;/p&gt;
&lt;p&gt;In that case, would Amazon deliverers be replaced by drones? Would robots serve at McDonalds?&lt;/p&gt;
&lt;h2 id="inevitability"&gt;Inevitability&lt;/h2&gt;
&lt;p&gt;David Fairhurst, chief people officer at McDonald’s Europe in 2014, &lt;a href="https://www.hospitalityandcateringnews.com/2014/04/retaining-women-is-key-as-mcdonalds-warns-of-workforce-cliff/"&gt;came up&lt;/a&gt; with an unforeseen issue. He claims that Europe and the US will soon experience the &lt;em&gt;workforce cliff&lt;/em&gt;. We have too many colossal enterprises, getting much bigger, and not enough people to work on them.&lt;/p&gt;
&lt;p&gt;David believes this problem will start materializing during the current decade. If that does happen, enterprises will supposedly not only have to turn to automation for help but also strive for its rapid advancement. If the degree of automation required for that obstacle to be surpassed is achieved, a new level of &lt;a href="https://en.wikipedia.org/wiki/Post-scarcity_economy"&gt;post-scarcity&lt;/a&gt; will surface. &lt;/p&gt;
&lt;p&gt;It's tempting to make the prediction that if workforce cliff happens, handling post-scarcity while maintaining the current production growth of the global economy will be the defining characteristic of the 21st century. Until one starts thinking about the inevitability of the environmental collapse unless we &lt;a href="https://www.theguardian.com/global-development-professionals-network/2017/jul/03/paris-climate-deal-wont-work-our-future-depends-degrowth"&gt;de-grow&lt;/a&gt;. Or the &lt;a href="https://en.wikipedia.org/wiki/Yellow_vests_movement"&gt;increasing economic inequality&lt;/a&gt;. Or would it be &lt;a href="https://en.wikipedia.org/wiki/George_Floyd_protests"&gt;racism&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Capitol_Hill_Autonomous_Zone"&gt;citizen governance&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Whatever the case; what an era to live in.&lt;/p&gt;</description><author>nutcroft</author><pubDate>Tue, 21 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/housing-as-ubi/</guid></item><item><title>New edge dev infrastructure</title><link>https://vercel.com/blog/new-edge-dev-infrastructure</link><description>New edge dev infrastructure.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://vercel.com/blog/new-edge-dev-infrastructure"&gt;Read on vercel.com&lt;/a&gt;</description><author>Max Leiter</author><pubDate>Tue, 21 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://vercel.com/blog/new-edge-dev-infrastructure</guid></item><item><title>Scaling relational SQL databases</title><link>https://stribny.name/posts/scaling-relational-sql-databases/</link><author>Posts by Petr Stribny</author><pubDate>Mon, 20 Jul 2020 21:54:59 GMT</pubDate><guid isPermaLink="true">https://stribny.name/posts/scaling-relational-sql-databases/</guid></item><item><title>Columnarised Highlights</title><link>https://rjp.is/blogging/posts/2020/07/columnarised-highlights/</link><description>In which we format some text, with colours.</description><author>infrequent oscillations</author><pubDate>Mon, 20 Jul 2020 20:38:46 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/07/columnarised-highlights/</guid></item><item><title>A Runbook for Upgrading Your Parent's Junky Old Laptop to a Chromebook</title><link>https://josh.works/upgrade-parents-junky-old-laptop-to-chromebook</link><description>&lt;h4 id="tldr-im-creating-a-runbook-for-a-very-specific-delicate-and-potentially-time-consuming-and-emotionally-charged-operation-to-replace-my-70-year-old-newly-widowed-mother-in-laws-ancient-desktop-computer-with-a-easy-for-me-to-manage-chromebook"&gt;tl;dr: I’m creating a &lt;code class="language-plaintext highlighter-rouge"&gt;runbook&lt;/code&gt; for a very specific, delicate, and potentially time-consuming and emotionally-charged operation to &lt;code class="language-plaintext highlighter-rouge"&gt;replace my 70-year-old newly-widowed mother-in-law's ancient desktop computer with a easy-for-me-to-manage Chromebook&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;Update: I posted to &lt;a href="https://www.reddit.com/r/chromeos/comments/it2fn2/how_much_should_i_spend_to_get_a_solid_chromebook/"&gt;r/ChromeOS&lt;/a&gt; this question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much should I spend to get a solid Chromebook for aging mother-in-law?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;My mother-in-law is almost 75. Her husband managed the computer stuff for her, and he died in January.&lt;/p&gt;

  &lt;p&gt;I’m the tech-savvy son in law who gets the phone calls to help her connect to the WiFi again, or help her print stuff.&lt;/p&gt;

  &lt;p&gt;I’d love to buy her a chromebook - I think it’ll serve her well, be easy for her to use, and will make it way easier for me to help her with computer things.&lt;/p&gt;

  &lt;p&gt;Money isn’t an object, per se. I’m willing to spend $700 on a good machine if that’s what does the job.&lt;/p&gt;

  &lt;p&gt;But even if I am to spend that amount, I still don’t know where to start.&lt;/p&gt;

  &lt;p&gt;So, do any of you have aging parents who you’ve gotten setup with a Chromebook?&lt;/p&gt;

  &lt;p&gt;What laptop did you get? Are you happy with it? Any regrets or things you wish you did differently?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here’s results from the thread:&lt;/p&gt;

&lt;p&gt;My MIL has simple needs:&lt;/p&gt;

&lt;p&gt;She has simple needs:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Facebook&lt;/li&gt;
  &lt;li&gt;~facetime/hangouts/zoom~ facetime won’t be possible on a Chromebook. No problem&lt;/li&gt;
  &lt;li&gt;AOL email (AOL is horrible)&lt;/li&gt;
  &lt;li&gt;banking and stuff&lt;/li&gt;
  &lt;li&gt;read her kids’ instagrams, Tumblrs, etc&lt;/li&gt;
  &lt;li&gt;print stuff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Printing could be tricky:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’d be cautious about getting a Chromebook if printing is a requirement. I’ve not had much luck getting Chrome OS to recognise printers and I have to transfer PDFs to another machine. I’ve tried with two HP printers which work fine on Windows and Ubuntu, but your mileage may vary if she has a different model of printer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But then:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;If your printer is Google Cloud Print compatible then its super easy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oh, yeah, but &lt;em&gt;of course&lt;/em&gt; &lt;a href="https://www.theverge.com/2019/11/22/20977888/google-cloud-print-shut-down-date-support"&gt;Google is sunsetting Google Cloud Print in 3 months&lt;/a&gt;. 🙄&lt;/p&gt;

&lt;p&gt;So… we’ll see. I’ll buy something, might end up replacing her printer too.&lt;/p&gt;

&lt;p&gt;Wikipedia says a &lt;code class="language-plaintext highlighter-rouge"&gt;runbook&lt;/code&gt; is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In a computer system or network, a runbook is a compilation of routine procedures and operations that the system administrator or operator carries out. System administrators in IT departments and NOCs use runbooks as a reference.&lt;/p&gt;

  &lt;p&gt;Runbooks can be in either electronic or in physical book form. Typically, a runbook contains procedures to begin, stop, supervise, and debug the system. It may also describe procedures for handling special requests and contingencies. An effective runbook allows other operators, with prerequisite expertise, to effectively manage and troubleshoot a system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Runbook"&gt;&lt;em&gt;source&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the definition for the runbook &lt;em&gt;I&lt;/em&gt; will create:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In &lt;strike&gt;a computer system or network&lt;/strike&gt; &lt;code class="language-plaintext highlighter-rouge"&gt;life&lt;/code&gt;, a runbook is a compilation of routine procedures and operations that the &lt;strike&gt;system administrator or operator&lt;/strike&gt; &lt;code class="language-plaintext highlighter-rouge"&gt;individual&lt;/code&gt; carries out. &lt;strike&gt;System administrators in IT departments and NOCs&lt;/strike&gt; &lt;code class="language-plaintext highlighter-rouge"&gt;People&lt;/code&gt; use runbooks as a reference.&lt;/p&gt;

  &lt;p&gt;Runbooks can be in either electronic or in physical book form. Typically, a runbook contains procedures to begin, stop, supervise, and debug the &lt;strike&gt;system&lt;/strike&gt; &lt;code class="language-plaintext highlighter-rouge"&gt;situation&lt;/code&gt;. It may also describe procedures for handling special requests and contingencies. An effective runbook allows other &lt;strike&gt;operators&lt;/strike&gt; &lt;code class="language-plaintext highlighter-rouge"&gt;people&lt;/code&gt;, with prerequisite expertise, to effectively manage and troubleshoot a &lt;strike&gt;system&lt;/strike&gt; &lt;code class="language-plaintext highlighter-rouge"&gt;situation&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="how-i-decided-on-a-runbook-instead-of-a-guide"&gt;How I decided on a “runbook” instead of a “guide”&lt;/h3&gt;

&lt;p&gt;A day after I announced the first version of this, a friend replied:&lt;/p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I've got 90%ish of my laptop set-up in a single bash script. Would probably pay for the chromebook equivalent of that + documentation explaining what has been setup. Something that creates all of the necessary accounts and software and explains it....&lt;/p&gt;&amp;mdash; Jack Pincus (@jwpincus) &lt;a href="https://twitter.com/jwpincus/status/1290721824418877441?ref_src=twsrc%5Etfw"&gt;August 4, 2020&lt;/a&gt;&lt;/blockquote&gt;


&lt;p&gt;He said:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’ve got 90%ish of my laptop set-up in a single bash script. Would probably pay for the chromebook equivalent of that + documentation explaining what has been setup. Something that creates all of the necessary accounts and software and explains it….&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I replied with (essentially)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;That’s what I’m trying to do&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then I used a word in my response that was a big &lt;code class="language-plaintext highlighter-rouge"&gt;aha&lt;/code&gt; moment:&lt;/p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;i don't think i'll be able to make it that clean of a process, but I'm thinking more of a Runbook for a given situation.&lt;br /&gt;&lt;br /&gt;- &amp;quot;if this, that&amp;quot;&lt;br /&gt;- &amp;quot;this portion is Very Important, the rest of this is not&amp;quot;.&lt;br /&gt;- pre-written scripts for common objections&lt;br /&gt;&lt;br /&gt;etc.&lt;/p&gt;&amp;mdash; Josh Thompson (@josh_works) &lt;a href="https://twitter.com/josh_works/status/1290767936739672064?ref_src=twsrc%5Etfw"&gt;August 4, 2020&lt;/a&gt;&lt;/blockquote&gt;


&lt;hr /&gt;

&lt;h2 id="runbook-origin-story-aka-24-hours-ago-aug-3-2020"&gt;Runbook Origin Story, aka 24 hours ago (Aug 3, 2020)&lt;/h2&gt;

&lt;p&gt;I spent a few hours recently helping my 75-year-old mother-in-law reconnect her junky old Windows laptop to the internet. Across five phone calls, and many pictures of her computer screen, we got her internet working again.&lt;/p&gt;

&lt;p&gt;As I did this, I live-tweeted the experience. It was about 20 tweets. A few pictures my mother-in-law sent me, and a poll.&lt;/p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;My mother in law is frustrated that her internet wasn't working today. It's been broken all day. I've called her a few times between other events to try to help debug it. &lt;br /&gt;&lt;br /&gt;This is a screenshot I just received (via email) that she took *with her phone* &lt;a href="https://t.co/5KnfCGZ2F4"&gt;pic.twitter.com/5KnfCGZ2F4&lt;/a&gt;&lt;/p&gt;&amp;mdash; Josh Thompson (@josh_works) &lt;a href="https://twitter.com/josh_works/status/1290420667444338688?ref_src=twsrc%5Etfw"&gt;August 3, 2020&lt;/a&gt;&lt;/blockquote&gt;


&lt;p&gt;Part of the debugging process involved her taking pictures of her computer screen, because I couldn’t tell what she was looking at. (I don’t ever use a Windows operating system, so I was operating blind.)&lt;/p&gt;

&lt;p&gt;She was frustrated with it all, so I’d first suggested plugging-in/unplugging the router. It would be easier to walk her through that then the unfamiliar OS.&lt;/p&gt;

&lt;p&gt;After it didnt work (and hours passed) we did this back and forth. She took a picture and emailed it to me.&lt;/p&gt;

&lt;p&gt;It took a few minutes to arrive, then I’d look at it, tell her what to click, and wait for another screenshot:&lt;/p&gt;

&lt;p&gt;&lt;img alt="first picture" src="/images/2020-08-03-screen-01.JPG" /&gt;&lt;/p&gt;

&lt;p&gt;about 15 minutes and another phone call later, I got this:&lt;/p&gt;

&lt;p&gt;&lt;img alt="second picture" src="/images/2020-08-03-chromebook-rotated.JPG" /&gt;&lt;/p&gt;

&lt;p&gt;All she ended up needing was to click her home wifi network and connect to it, per these screenshots.&lt;/p&gt;

&lt;p&gt;Months ago, I’d read things like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://www.reddit.com/r/chromeos/comments/h82m1d/secure_browsing_for_elderly_chromebook_or_windows/"&gt;Secure browsing for elderly: chromebook or Windows 10 S (reddit)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.reddit.com/r/chromeos/comments/cdgq1q/a_chromebook_for_elderly_people/"&gt;A chromebook for elderly people (reddit)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.reddit.com/r/chromeos/comments/34v0w2/people_who_bought_a_chromebook_for_an_elderly_or/"&gt;People who bought a Chromebook for an elderly or tech illiterate parent/relative, what has yours and their experience been so far? (reddit, five years old! 😭)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On this last one, read through this answer. Emphasis mine.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I convinced my wife and her two brothers to purchase the Asus Chromebox for their mother this past December for Christmas.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;She had been complaining about how slow her desktop had been for years&lt;/strong&gt;. Every year we all put money together to update something electronic for her. One year it was a camera, then she lost that camera (lol) so we got her another the next year. Then it was a Bluray player. The computer had been on the list for years.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;In my family and circle’s I am the “go to person” to fix computer or technology related problems. I never gave my self that title but unfortunately for me I’m stuck with it.&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;I don’t know about you but I can’t count how many times I’ve been asked to “fix”, “speed up”, or “I think I might have a virus, my computer is so slow can you take a look at it”. &lt;strong&gt;What I have found over the years is that almost always there isn’t a virus. The fix for all of those problems more times than not is you need a new machine. Your Sh** is old&lt;/strong&gt;. And honestly I just grew tired of getting this from so many “tech illiterate” people.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Windows (I can’t speak for Mac) is a pain to maintain. There are a lot of people who would say otherwise but unless you find that sort of thing easy, it just is.&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;So with all that (hopefully funny backstory) said I wanted to get my mother in law a Chrome device. And like I said we got the Asus Chromebox.&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;Let me tell you, it is by far my mother in laws favorite device we ever got her.&lt;/strong&gt; We got it off of Amazon on black Friday. &lt;strong&gt;We paid $119.99&lt;/strong&gt; US and I bought an extra stick of ram from corsair I believe. That would upgrade the ram from 2gb to 4gb.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;She no longer has a slow computer. It boots up in less than 10 seconds. Everything is saved and synced. No windows updates. No fragmented hard drives. No virus/malware. She can still play solitare via a chrome store app. It plays video’s great when she sees them while looking at her facebook. The browser doesn’t lag and isn’t slow. ChomeOS updates automatically and is seamless. I know a lot of people that had their windows machines freeze while on a windows update. Essentially making their computer a brick, until someone like me comes and fixes it for them. If ChromeOS ever gets into trouble, it is as simple as doing a “powerwash” which is basically a factory reset and everything goes back to new. But since everything in ChromeOS is synced, as soon as you log back in everything is restored just how it was.&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Chromebooks/boxes come with at least 100gb of online storage and Drive is “mounted” in chromeOS it’s self so it acts just like if it were a hard drive in the computer. ChromeOS is incredibly simple. There aren’t a lot of options menus. You can’t get lost in the OS.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;ChromeOS I would argue is amazing for tech illiterate people&lt;/strong&gt;. I’m far from tech illiterate but ChromeOS has been an absolute breath of fresh air for me as well! There really isn’t much of a learning curve, outside of understanding how to install/remove a chrome app or extension.&lt;/p&gt;

  &lt;p&gt;There are, however, some take-aways. For one you can not install any software like you would on windows or mac. There is one program my mother in law uses and I have found no way of a work around for her and the chromebox. Skype is not available right out of the box for ChromeOS. There is a a work around but requires using a program to convert the Android Version to work in ChromeOS.&lt;/p&gt;

  &lt;p&gt;I have lots more I could say, but I’m getting the evil eye from the wife, time to get off of Reddit!&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;I can’t recommend a Chromebook/Box more, especially for non tech folks. And is wonderful for us who have to run tech support. Makes our job so much easier! I tell people to first examine their primary needs and research if they can be met with ChromeOS, before buying. Understand it’s limitations. If you go into it knowing exactly what you are getting, then it is a wonderful experience.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was hooked. I want a Chromebook for my mother-in-law! $120? I would have bought that &lt;em&gt;yesterday&lt;/em&gt; if I knew exactly what to do and how long it would take to setup.&lt;/p&gt;

&lt;p&gt;I’d have spent another $120 on a guide that gave me exactly what I needed, super-custom to my exact use-case and background. &lt;code class="language-plaintext highlighter-rouge"&gt;:chefs-kiss:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I want (and will therefore create) a Runbook to figure out what Chromebook to get her, set it up for her, and help her be successful with it. This can easily take many hours. I want my effort to be helpful to you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It won’t be quite as straight forward as a bash script - think of it as a &lt;code class="language-plaintext highlighter-rouge"&gt;Runbook for Humans&lt;/code&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Later that day, here’s what happened:&lt;/p&gt;

&lt;p&gt;&lt;img alt="write it now" src="/images/2020-07-21-write-it-now.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;source: &lt;a href="https://twitter.com/sarahdoingthing/status/889082755203518464?s=20"&gt;@sarahdoingthing&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, I’ve got a lot of the questions I’ll need answered jotted down, and I wanna see if there’s any interest in buying a guide like this. Would it be worth $10 to you? $100? $1000?&lt;/p&gt;

&lt;p&gt;In the pole, someone expressed it might be worth as much as $2000, so I am including that option below.&lt;/p&gt;

&lt;p&gt;Maybe it’s worth $1000 but you don’t even have $5 to spend to acquire the guide. Whatever I end up creating, I’ll make available to you.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Here’s the current planned detail of the guide, as it exists in my head right now:&lt;/p&gt;

&lt;h3 id="questions-ill-answer"&gt;Questions I’ll answer&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;When I recognized it was the right time to actually take action&lt;/li&gt;
  &lt;li&gt;How I phrased the pain-points so she would agree that it was a problem&lt;/li&gt;
  &lt;li&gt;How I used the time I spent debugging her problems convincing her that she should use a different type of laptop&lt;/li&gt;
  &lt;li&gt;what actual machine to buy&lt;/li&gt;
  &lt;li&gt;how to set up an account for your parent&lt;/li&gt;
  &lt;li&gt;how to handle them using a non-gmail account (I assume this is a requirement)&lt;/li&gt;
  &lt;li&gt;how to take remote access of the machine and accomplish tasks yourself. (This beats your mother-in-law emailing you cell phone pictures.)&lt;/li&gt;
  &lt;li&gt;her reactions and first-run experience with my documented process&lt;/li&gt;
  &lt;li&gt;how I tweak my plans based on her responses&lt;/li&gt;
  &lt;li&gt;how to use all of this information to aid your own parents through a similar process&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="the-benefits-you-will-receive-from-this-guide"&gt;The benefits you will receive from this guide&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Help your parent(s) feel a sense of dignity and control through this process, even though it might feel like it’s displacing an important, familiar thing needlessly&lt;/li&gt;
  &lt;li&gt;Remove a point of frustration that might be emotionally charged, thanks to issues related to maintaining competence and control over one’s affairs. (I suspect I’ll be looking for a &lt;code class="language-plaintext highlighter-rouge"&gt;step-by-step guide to helping your aging parents stop driving&lt;/code&gt; soon)&lt;/li&gt;
  &lt;li&gt;how to help your parent(s) use as much Gmail as they have to, while most likely using their primary email address with an &lt;code class="language-plaintext highlighter-rouge"&gt;AOL&lt;/code&gt; or &lt;code class="language-plaintext highlighter-rouge"&gt;yahoo&lt;/code&gt; or &lt;code class="language-plaintext highlighter-rouge"&gt;comcast&lt;/code&gt; email account. (and they get tons of spam in it :eyeroll: )&lt;/li&gt;
  &lt;li&gt;How to handle a password manager with them. Use or don’t use Chrome/Firefox password tools?&lt;/li&gt;
  &lt;li&gt;Oh, 1Password? If you use 1Password, and have your parent’s credentials in a 1Password vault that is shared with your siblings and/or in-laws, but you’re the one who manages that account, what should you do?&lt;/li&gt;
  &lt;li&gt;the above presumes that you came to have your parent’s credentials &lt;em&gt;at their request&lt;/em&gt;, of course.&lt;/li&gt;
  &lt;li&gt;once it’s set up, can it be easy enough to set up that they can unbox it themselves?&lt;/li&gt;
  &lt;li&gt;how much does it cost to ship a laptop through the mail, anyway? Is it safe? Legal?&lt;/li&gt;
  &lt;li&gt;Is it &lt;em&gt;actually&lt;/em&gt; possible to “easily” “remote in” and “fix things” for your parents? The reader might be skeptical of how “easy and simple” software often is, and is curious to know exactly what to expect.&lt;/li&gt;
  &lt;li&gt;An example to point to, when convincing your parent to take the plunge.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Look, this guide is from this guy on the internet that did &lt;em&gt;this exact same thing with his mother-in-law who was similar to you because {reasons}&lt;/em&gt;, and look at this quote here where she says how thankful is she did this thing:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;Hi, I’m Barb, and since I switched to this chromebook thing I spend 20 extra minuts a day facetiming with my grandkids! I love that!&lt;/p&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;h2 id="the-un-faq"&gt;The un-faq&lt;/h2&gt;

&lt;p&gt;These are &lt;em&gt;diqualifying&lt;/em&gt; conditions. Do not purchase this guide if:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Your parents are familiar with the Apple ecosystem, because I have always used Android and MacOS, don’t have an iPad or an iPhone. I feel strongly inclined to do MacOS.&lt;/li&gt;
  &lt;li&gt;You don’t want to use a Chromebook or learn a Windows operating system&lt;/li&gt;
  &lt;li&gt;You expect a perfectly-polished, high-production-value product&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;The poll got some answers, so I’m tossing up real-live purchase buttons to guage interest at your level of buy-in&lt;/p&gt;

&lt;h2 id="purchase-options"&gt;Purchase Options&lt;/h2&gt;

&lt;p&gt;In the twitter poll, I gave options from $0 to $2000, so giving all those options below. For the record, this is &lt;em&gt;prepurchasing&lt;/em&gt; options. I’ve not built anything yet, other than some notes floating around my laptop. I use “someone put money down” as an expression of strong interest.&lt;/p&gt;

&lt;h3 id="1-money-is-no-object-1900"&gt;1. Money Is No Object ($1900)&lt;/h3&gt;

&lt;p&gt;You want an excellent runbook and value your time.&lt;/p&gt;

&lt;div class="stripe_button_container"&gt;
  &lt;div class="button_container"&gt;
    &lt;button class="stripe_button" id="checkout-button-sku_Hlof76lIQGPrOW" style="background-color: #6772E5; color: #FFF; padding: 8px 12px; border: 0; border-radius: 4px; font-size: 1em;" type="button"&gt;
      Pre-purchase ($1900)
    &lt;/button&gt;

    &lt;div id="error-message"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="2-meaningful-money-but-if-it-saves-you-5-25-hours-and-hard-feelings-and-frustration-youre-all-in-495"&gt;2. Meaningful money, but if it saves you 5-25 hours and hard feelings and frustration, You’re All In ($495)&lt;/h3&gt;

&lt;p&gt;You’d be spending one or two days of income to have a bullet-proof solution to upgrading your aging parent’s laptops. The story from Reddit had you nodding along hard. &lt;em&gt;This is exactly what you experience and want&lt;/em&gt;. But five years ago? What hardware do I need now? Can I dual-boot the operating system? How do I actually convince him/her/them to start using it?&lt;/p&gt;

&lt;div class="stripe_button_container"&gt;
  &lt;div class="button_container"&gt;
    &lt;button class="stripe_button" id="checkout-button-sku_HlotwPoptCsYBY" style="background-color: #6772E5; color: #FFF; padding: 8px 12px; border: 0; border-radius: 4px; font-size: 1em;" type="button"&gt;
      Pre-purchase ($495)
    &lt;/button&gt;

    &lt;div id="error-message"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="3-you-expect-non-trivial-value-from-this-guide-99"&gt;3. You expect non-trivial value from this guide ($99)&lt;/h3&gt;

&lt;p&gt;You probably have spent at least $99 on something that will deliver much less value to you than this guide will.&lt;/p&gt;

&lt;p&gt;If that’s true, but this is not at $495 or $1900 problem to you, this would be your best bet.&lt;/p&gt;

&lt;p&gt;Low cost, you’ll get whatever I create. It’s a cheap gamble that $99 could save you from “donating” many thousands of dollars over the next six months.&lt;/p&gt;

&lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;20 (scarce, non-work, nights-and-weekend) hours @$100/hr = $2000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class="stripe_button_container"&gt;
  &lt;div class="button_container"&gt;
    &lt;button class="stripe_button" id="checkout-button-sku_HloZ1DXv53t7fT" style="background-color: #6772E5; color: #FFF; padding: 8px 12px; border: 0; border-radius: 4px; font-size: 1em;" type="button"&gt;
      Pre-purchase ($99)
    &lt;/button&gt;

    &lt;div id="error-message"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="4-what-you-might-spend-on-dinner-with-a-friend-49"&gt;4. What You Might Spend on Dinner with a Friend ($49)&lt;/h3&gt;

&lt;p&gt;If you think you’d spend $20 but not $50, this guide might not be for you. It will be so good that $50 will be a screaming deal.&lt;/p&gt;

&lt;div class="stripe_button_container"&gt;
  &lt;div class="button_container"&gt;
    &lt;button class="stripe_button" id="checkout-button-sku_Hloz9JPn2QkUAQ" style="background-color: #6772E5; color: #FFF; padding: 8px 12px; border: 0; border-radius: 4px; font-size: 1em;" type="button"&gt;
      Pre-purchase ($49)
    &lt;/button&gt;

    &lt;div id="error-message"&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="5-send-you-the-guide-when-im-done-0"&gt;5. Send You The Guide When I’m Done ($0)&lt;/h3&gt;

&lt;p&gt;If you just want to follow along, or are on the fence about the value of what I’ll make, punch your email in below.&lt;/p&gt;

&lt;p&gt;I’ll end up writing my process up carefully, and I’ll certainly share it out when I’m done. I am good at writing detailed guides that save people dozens of hours and large amounts of frustration. I’ll share the guide when I’m done, and I’ll send updates as I go. I love to work in public; if you subscribe and follow along, you’ll get to see what I’m building as I go, and I’d love to get your input along the way.&lt;/p&gt;

&lt;p&gt;And if down the road you decide it’s worth paying for, you’ll have the option.&lt;/p&gt;

&lt;p&gt;Enter your email, and you’ll get all that when it’s available:&lt;/p&gt;



&lt;p&gt;&lt;em&gt;if you don’t see the subscribe form above, &lt;a href="https://josh-thompson.ck.page/79563b40c7"&gt;click here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id="faq"&gt;FAQ&lt;/h2&gt;

&lt;p&gt;If your question isn’t asked, shoot me a note at &lt;a href="https://twitter.com/josh_works"&gt;@josh_works&lt;/a&gt; or &lt;code class="language-plaintext highlighter-rouge"&gt;joshthompson@hey.com&lt;/code&gt;. I’ll answer it and update this list.&lt;/p&gt;

&lt;h3 id="what-all-is-included"&gt;What all is included&lt;/h3&gt;

&lt;p&gt;A runbook for technical people who help their non-technical aging parents/family/friends with their technology problems.&lt;/p&gt;

&lt;p&gt;Specifically, writing up how to help the following persona:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A 70 mother-in-law with good relationships with her kids/grandkids&lt;/li&gt;
  &lt;li&gt;extremely resistant to change&lt;/li&gt;
  &lt;li&gt;feels bad needing constant help from her family&lt;/li&gt;
  &lt;li&gt;the tech trouble reminds her that her husband died recently and she misses him&lt;/li&gt;
  &lt;li&gt;on good terms with the person using this runbook (you!)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This runbook will rely on building/deepening trust between you and the recipient, and that requires having something to build on. I’m sure it’ll be helpful even if the relationship is poor, but I wanted to mention it.&lt;/p&gt;

&lt;p&gt;A detailed guide with links to the exact product, tools, services that I use&lt;/p&gt;

&lt;p&gt;Lots of perspecive of how this is landing with my mother-in-law&lt;/p&gt;

&lt;p&gt;etc.&lt;/p&gt;

&lt;p&gt;Might do video walk-throughs. &lt;a href="https://josh.works/mythical-creature-refactor-ogre"&gt;Here’s an example of how I do these&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id="what-if-you-want-your-money-back"&gt;What if you want your money back&lt;/h3&gt;

&lt;p&gt;Then I 100% wanna give it to you. Just let me know and I’ll send it right back, all fees included, between now and forever.&lt;/p&gt;

&lt;h3 id="you-might-want-the-100-or-500-or-2000-verison-but-dont-know-whichif-any-yet"&gt;You might want the $100, or $500, or $2000 verison, but don’t know which/if-any yet&lt;/h3&gt;

&lt;p&gt;Yeah, totally get it. I’d say pop your email address into the $0 form, and reply to one of the emails when you feel so inclined.&lt;/p&gt;

&lt;h3 id="you-have-other-questions-id-like-to-ask-you"&gt;You have other questions I’d like to ask you&lt;/h3&gt;

&lt;p&gt;Great! Pop your email in below; the very first email you’ll get asks:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’d really love to know what prompted your interest. Are you going through something similar right now? Do you think you might be doing something like this soon? Any advice or words of caution that you’d share?&lt;/p&gt;
&lt;/blockquote&gt;



&lt;p&gt;&lt;em&gt;if you cannot see the email collection form above, you will have to turn off your JavaScript blocker or &lt;a href="https://josh-thompson.ck.page/79563b40c7"&gt;visit this page&lt;/a&gt; to submit an email address&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;feel free to reach out at &lt;code class="language-plaintext highlighter-rouge"&gt;joshthompson@hey.com&lt;/code&gt; if you’ve got questions&lt;/em&gt;&lt;/p&gt;</description><author>Josh Thompson</author><pubDate>Mon, 20 Jul 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/upgrade-parents-junky-old-laptop-to-chromebook</guid></item><item><title>`Medusa` mythical creature: part 1</title><link>https://josh.works/mythical-creature-medusa-start</link><description>&lt;hr /&gt;
&lt;h5 id="preparing-for-turing-series-index"&gt;Preparing for Turing Series Index&lt;/h5&gt;

&lt;p&gt;What follows is an eight-part series that will help you pick up useful information about a number of topics related to Ruby, specifically geared for students learning the Ruby programming language, as part of the Turing School’s Backend Software Development Program&lt;/p&gt;

&lt;p&gt;It’s generally intended that you progress sequentially, but there’s no “right way” or “right order” to encounter these topics. You could convince me I have the order exactly backwards. I’d disagree, but only slightly.&lt;/p&gt;

&lt;p&gt;I encourage you to skim around these chapters, get the “shape” of what’s to come, in your mind, and then dive in wherever you want. Good luck, and bug reports are welcome.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-01-intro"&gt;Chapter 1: Make Mod 1 Easier Than It Otherwise Would Be&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-02-first-tests-and-making-them-pass"&gt;Chapter 2: Your first passing tests!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-mythical-creatures"&gt;Chapter 3: Objects in Ruby and Mythical Creatures: &lt;code class="language-plaintext highlighter-rouge"&gt;unicorn.rb&lt;/code&gt;, &lt;code class="language-plaintext highlighter-rouge"&gt;dragon.rb&lt;/code&gt;, and &lt;code class="language-plaintext highlighter-rouge"&gt;hobbit.rb&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-arrays-hashes-nested-collections"&gt;Chapter 4: Arrays, Hashes, and Nested Collections&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-refactor-wizard"&gt;Chapter 5: Refactoring common errors - in &lt;code class="language-plaintext highlighter-rouge"&gt;wizard.rb&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-refactor-ogre"&gt;Chapter 6: Refactoring practice - Getting rid of &lt;code class="language-plaintext highlighter-rouge"&gt;attr_accessors&lt;/code&gt; in &lt;code class="language-plaintext highlighter-rouge"&gt;ogre.rb&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-medusa-start"&gt;Chapter 7: Building out the &lt;code class="language-plaintext highlighter-rouge"&gt;medusa&lt;/code&gt; mythical creature&lt;/a&gt;  &lt;strong&gt;&lt;em&gt;you are here&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-refactor-medusa"&gt;Chapter 8: Refactoring the &lt;code class="language-plaintext highlighter-rouge"&gt;medusa&lt;/code&gt; mythical creature&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-troubleshooting-guide"&gt;Appendix: Troubleshooting Errors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;Wow. I made parts 1 and 2 of this video months ago, forgot to make them findable.&lt;/p&gt;

&lt;h2 id="turings-mythical-creatures-medusa"&gt;Turing’s Mythical Creatures: Medusa&lt;/h2&gt;

&lt;div class="container"&gt;

&lt;/div&gt;

&lt;p&gt;When you’re done, check out &lt;a href="/mythical-creature-refactor-medusa"&gt;part 2&lt;/a&gt;.&lt;/p&gt;</description><author>Josh Thompson</author><pubDate>Mon, 20 Jul 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/mythical-creature-medusa-start</guid></item><item><title>`Medusa` mythical creature: part 2</title><link>https://josh.works/mythical-creature-refactor-medusa</link><description>&lt;hr /&gt;
&lt;h5 id="preparing-for-turing-series-index"&gt;Preparing for Turing Series Index&lt;/h5&gt;

&lt;p&gt;What follows is an eight-part series that will help you pick up useful information about a number of topics related to Ruby, specifically geared for students learning the Ruby programming language, as part of the Turing School’s Backend Software Development Program&lt;/p&gt;

&lt;p&gt;It’s generally intended that you progress sequentially, but there’s no “right way” or “right order” to encounter these topics. You could convince me I have the order exactly backwards. I’d disagree, but only slightly.&lt;/p&gt;

&lt;p&gt;I encourage you to skim around these chapters, get the “shape” of what’s to come, in your mind, and then dive in wherever you want. Good luck, and bug reports are welcome.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-01-intro"&gt;Chapter 1: Make Mod 1 Easier Than It Otherwise Would Be&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-02-first-tests-and-making-them-pass"&gt;Chapter 2: Your first passing tests!&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-mythical-creatures"&gt;Chapter 3: Objects in Ruby and Mythical Creatures: &lt;code class="language-plaintext highlighter-rouge"&gt;unicorn.rb&lt;/code&gt;, &lt;code class="language-plaintext highlighter-rouge"&gt;dragon.rb&lt;/code&gt;, and &lt;code class="language-plaintext highlighter-rouge"&gt;hobbit.rb&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-arrays-hashes-nested-collections"&gt;Chapter 4: Arrays, Hashes, and Nested Collections&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-refactor-wizard"&gt;Chapter 5: Refactoring common errors - in &lt;code class="language-plaintext highlighter-rouge"&gt;wizard.rb&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-refactor-ogre"&gt;Chapter 6: Refactoring practice - Getting rid of &lt;code class="language-plaintext highlighter-rouge"&gt;attr_accessors&lt;/code&gt; in &lt;code class="language-plaintext highlighter-rouge"&gt;ogre.rb&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-medusa-start"&gt;Chapter 7: Building out the &lt;code class="language-plaintext highlighter-rouge"&gt;medusa&lt;/code&gt; mythical creature&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/mythical-creature-refactor-medusa"&gt;Chapter 8: Refactoring the &lt;code class="language-plaintext highlighter-rouge"&gt;medusa&lt;/code&gt; mythical creature&lt;/a&gt;  &lt;strong&gt;&lt;em&gt;you are here&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="/turing-backend-prep-troubleshooting-guide"&gt;Appendix: Troubleshooting Errors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;Wow. I made this video months ago, forgot to make it findable.&lt;/p&gt;

&lt;h2 id="turings-mythical-creatures-medusa-refactor"&gt;Turing’s Mythical Creatures: Medusa refactor&lt;/h2&gt;

&lt;p&gt;Watch/read &lt;a href="/mythical-creature-medusa-start"&gt;part 1&lt;/a&gt; if you’ve not already:&lt;/p&gt;

&lt;p&gt;Here’s a walk-through for strategies and tactics to refactor the mythical creature we built last time. The refactored code is much improved, and your own understanding of your own code will be much improved as well.&lt;/p&gt;

&lt;p&gt;Part 2 is a 14 minute video, contains a &lt;em&gt;lot&lt;/em&gt; of information. Block out 30-40 minutes to work through it.&lt;/p&gt;

&lt;div class="container"&gt;

&lt;/div&gt;</description><author>Josh Thompson</author><pubDate>Mon, 20 Jul 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://josh.works/mythical-creature-refactor-medusa</guid></item><item><title>Migrating From Middleman to Another Static Site</title><link>http://evantravers.com/articles/2020/07/20/migrating-from-middleman-to-another-static-site/</link><description>&lt;p&gt;For about a year I've been flirting with leaving behind &lt;a href="https://middlemanapp.com/"&gt;Middleman&lt;/a&gt; and trying another &lt;a href="https://www.staticgen.com/"&gt;static site generator&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While I &lt;em&gt;still&lt;/em&gt; haven't done it, I've been slowly documenting the hacks and tricks that build my current website, so that I'll be able to preserve the same URLs and such.&lt;/p&gt;
&lt;p&gt;I've taken a couple of stabs at some of the other generators, usually by making a branch, deleting a bunch of code, and trying to hot-change out the underlying engine from middleman. It's fun and quick, but as soon as I want to write another blog post or make a change the branch falls behind. To combat this, I quickly threw together a migration script the other weekend.&lt;/p&gt;
&lt;p&gt;The script isn't particularly clever, but I wanted to use it as an excuse to point out some good practices for migration style scripts.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;# MIGRATION SCRIPT&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# ----------------&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;#&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# The purpose of this is to pull the content out of my existing site into a&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# format that makes sense for a new static site generator.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;#&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# As it is taking me a while to decide which one I want to try, having&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# something that I can &amp;quot;live&amp;quot; update will be _very_ important.&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should use comments... I know there's a lot of debate about whether code should document itself, but I often find that a one-file script doesn't have enough context to really document itself, so writing some pseudocode in comments can help guide your process.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;require&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;fileutils&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;require&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;SRC&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;../evantravers.com/source&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;DST&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;./content/&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# Reset&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;if&lt;/span&gt; &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;directory?&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DST&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;remove_dir&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DST&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DST&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should make your script repeatable and non-destructive. The above lines set a &lt;code&gt;SRC&lt;/code&gt; and &lt;code&gt;DST&lt;/code&gt; directory that are different... so any changes won't damage the &lt;code&gt;SRC&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In addition, each time the script is run it deletes the whole generated folder. While this is &amp;quot;expensive&amp;quot; it reduces weird side effects that can cause confusion. (For instance, if I change the format of a filename, then I could end up with two versions of the same file.)&lt;/p&gt;
&lt;p&gt;Really, if you do &lt;em&gt;anything&lt;/em&gt;, do that. You will thank me someday.&lt;/p&gt;
&lt;p&gt;The rest of the script does some massaging and renaming of files to remove some of the Middleman specific naming and formatting.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;# Middleman requires some weird naming conventions... it'd be nice to be able&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# to remove those.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;def&lt;/span&gt; &lt;span&gt;clean_filename&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;str&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;basename&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;str&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;.&lt;/span&gt;&lt;span&gt;gsub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;\d&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;.&lt;/span&gt;&lt;span&gt;gsub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;.html&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;.&lt;/span&gt;&lt;span&gt;gsub&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;.markdown&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;.md&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# Move over the articles&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# URL format: /articles/YYYY/MM/DD/slugified-title/&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkdir_p&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DST&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;articles&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;Dir&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;glob&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;SRC&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;/articles/*.&amp;amp;lbracemd,markdown&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;each&lt;/span&gt; &lt;span&gt;do&lt;/span&gt; &lt;span&gt;|&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;date&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;Date&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;parse&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;path&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DST&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;articles&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;date&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;year&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;to_s&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;date&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;strftime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;%m&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;date&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;strftime&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;%d&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkdir_p&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;copy_file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;file&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;clean_filename&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;file&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the bulk of the work... I just wanted bare markdown files in a directory structure that matched some of the static generators I've been looking at.&lt;/p&gt;
&lt;p&gt;Middleman generates articles (&lt;code&gt;middleman article &amp;quot;&amp;lt;name of article&amp;gt;&amp;quot;&lt;/code&gt;) in your configured location for articles with the filename of &lt;code&gt;YYYY-MM-DD-slugified-name-of-article.html.markdown&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I have &lt;em&gt;no&lt;/em&gt; clue why the &lt;code&gt;.html.markdown&lt;/code&gt;, I think it's a remnant of some parser or other. I would prefer to store my content with a simple &lt;code&gt;.md&lt;/code&gt;, so that's what I do here.&lt;/p&gt;
&lt;p&gt;In the end, the above code transforms:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;├──&lt;/span&gt; &lt;span&gt;articles&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;├──&lt;/span&gt; &lt;span&gt;2020&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;07&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;20&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;migrating&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;middleman&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;another&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;site&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;html&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;markdown&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;└&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;└&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;├──&lt;/span&gt; &lt;span&gt;articles&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;├──&lt;/span&gt; &lt;span&gt;2020&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;│&lt;/span&gt;  &lt;span&gt;├──&lt;/span&gt; &lt;span&gt;07&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;│&lt;/span&gt;  &lt;span&gt;│&lt;/span&gt;  &lt;span&gt;├──&lt;/span&gt; &lt;span&gt;20&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;│&lt;/span&gt;  &lt;span&gt;│&lt;/span&gt;  &lt;span&gt;│&lt;/span&gt;  &lt;span&gt;└──&lt;/span&gt; &lt;span&gt;migrating&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;from&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;middleman&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;another&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;site&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;md&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;│&lt;/span&gt;  &lt;span&gt;└&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;│&lt;/span&gt;  &lt;span&gt;└&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;└&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The best part... if I ever change my mind, I can adjust the script and the name and folders will change appropriately. 👌&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;# Move over the images&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# URL format: standard (based on folder)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cp_r&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;SRC&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;https://images.evantravers.com/&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;DST&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty boring call out to &lt;code&gt;cp -r&lt;/code&gt; here... only note is the consistent use of &lt;code&gt;DST&lt;/code&gt; constant to avoid mistakes.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;# Move special essays and pages&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# URL format: /name-of-file/&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;git.html.md&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;about-me.html.md&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;humans.txt&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;thanks.html.md&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;each&lt;/span&gt; &lt;span&gt;do&lt;/span&gt; &lt;span&gt;|&lt;/span&gt;&lt;span&gt;special&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;copy_file&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;SRC&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;special&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DST&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;clean_filename&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;special&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# Move over style assets&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;# These are currently .scss files&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;FileUtils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cp_r&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;SRC&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;css&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;File&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;join&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;DST&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;style&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don't want to grab &lt;em&gt;every&lt;/em&gt; file that Middleman uses, so I specifically grab some content files that I would want to bring over to a new site. I can use my same &lt;code&gt;clean_filename&lt;/code&gt; method to remove that weird &lt;code&gt;.html.md&lt;/code&gt; file extension.&lt;/p&gt;
&lt;p&gt;This script is pretty ugly and foolish, and you could write or re-write this in any language that you choose, but I wanted to point out these basic principles: Make it non-destructive and make it repeatable. Because of these principles, the next time I run the script (after this post!) my experimental playground for new static site generators will be automatically updated with this very post, cleaned up and placed in the right folder. 👍 If there are any useful scripting principles that I missed, feel free to reach out on twitter, and I'll consider including them.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;I've got a post about a migration script for plain-text notes to Zettelkasten format that will go into this more deeply. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Mon, 20 Jul 2020 14:15:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/07/20/migrating-from-middleman-to-another-static-site/</guid></item><item><title>Why The Bioinformatic Industry Needs To Privatize</title><link>https://philippzentner.com/problems-bioinformatic-industry-privatization.html</link><description>&lt;img alt="Enabling Novel X-ray Sources to Deliver Tumor-Killing Radiation" src="https://philippzentner.com/media/posts/57/national-cancer-institute-zz_3tCcrk7o-unsplash.jpg" /&gt;
                    Disclaimer: This article is based on a multitude of conversations with mainly bioinformaticians that have many years of experience in working with and in academics, biotech, CROs/pharma companies. This post sums up these shared experiences. The bioinformatics industry is relatively young. Well, at least immature,&amp;hellip;</description><author>Philipp Zentner</author><pubDate>Mon, 20 Jul 2020 13:49:51 GMT</pubDate><guid isPermaLink="true">https://philippzentner.com/problems-bioinformatic-industry-privatization.html</guid></item><item><title>Hot Reloading with Local Docker Development</title><link>https://olshansky.info/posts/hot-reloading-with-local-docker-development/</link><description>tl;dr You can find the source code for a bare-bones dockerized python HTTP server with hot reloading using fastapi on this Github page.</description><author>🦉 olshansky 🦁</author><pubDate>Mon, 20 Jul 2020 07:01:38 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/posts/hot-reloading-with-local-docker-development/</guid></item><item><title>Waves (prints) • Art</title><link>https://muffinman.io/art/waves-prints/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;Generative process allows me to work with huge number of elements and tiny details. These details are sometimes impossible to plot, as they would just get lost in the process. That&amp;#x27;s why I love large format prints - they allow tiny details to be seen and shine through.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;July 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;60x84cm (can&amp;#x27;t remember for the small one 🙈)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Farbiano Cotton Paper 300gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="2600" src="./0.jpg" width="1836" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1050" src="./w_500-h_500--1.jpg" width="1202" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./2.jpg"&gt;&lt;img alt="" class="gallery__image" height="1875" src="./w_500-h_500--2.jpg" width="2500" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./3.jpg"&gt;&lt;img alt="" class="gallery__image" height="2000" src="./w_500-h_500--3.jpg" width="2000" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Mon, 20 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/waves-prints/</guid></item><item><title>On right action and American politics</title><link>https://benovermyer.com/blog/2020/07/on-right-action/</link><description>&lt;p&gt;We try to do what's right in the best way we can. This is a statement that generally guides human behavior. You can summarize this as "right action."&lt;/p&gt;
&lt;p&gt;What defines right action differs from person to person, however. In looking at the approaches of Americans to the problem of politics and national leadership, we can observe two primary examples.&lt;/p&gt;
&lt;p&gt;The first defines the quality of being right as the degree of perceived adherence to one's world view. The second defines the quality of being right as the degree to which a measurable result adheres to the desired outcome.&lt;/p&gt;
&lt;p&gt;So, when judging the policy of a political figure, someone with the first approach will judge that policy as correct if it conforms to one's value set. Someone with the second approach will judge that policy as correct if it has been measurably proven to be so.&lt;/p&gt;
&lt;p&gt;These two approaches overlap to varying degrees in a single individual. The policy in question will be judged more dispassionately and in greater alignment with the second approach if the policy has less alignment with an existing identity value of the individual. That is, a person is more likely to be rational about a topic if that topic doesn't matter to them much. However, if the topic impedes or aligns with a core value of the person in question, they are far more likely to be irrational in their reaction to policy on that topic.&lt;/p&gt;
&lt;p&gt;It should seem reasonable to suggest that an empirical approach to every decision is ideal. The problem is that humans are incapable of being rational about &lt;em&gt;every&lt;/em&gt; decision in their lives. However, in striving to be rational about as much as possible, one can approach the ideal even if it remains elusive.&lt;/p&gt;
&lt;p&gt;Judging a policy based on its measured results or on historical measured data is far preferable to the alternative. When evaluating those measurements, it's important to trust the opinion of experts over the opinion of unqualified individuals. This lends itself to more accurate prediction of results, which in turn allows for more effective policy choice.&lt;/p&gt;
&lt;p&gt;Further, once a policy has been in place for an amount of time that allows for statistically significant results, that policy can and should be reevaluated to determine its correctness. This reinforces a structure of continual improvement.&lt;/p&gt;
&lt;p&gt;Too often in American politics, policymakers make value judgments based on personal identity and not on measured results. Voters decide on their representatives the same way. This conflicts with the &lt;a href="https://en.wikipedia.org/wiki/Age_of_Enlightenment" rel="external"&gt;original philosophical climate&lt;/a&gt; that gave birth to the United States of America in the first place. Benjamin Franklin, Thomas Jefferson, and James Madison were all proponents of Enlightenment philosophy. The phrasing of the &lt;a href="https://en.wikipedia.org/wiki/United_States_Declaration_of_Independence" rel="external"&gt;Declaration of Independence&lt;/a&gt; includes language to this effect; in describing the right of people to establish new government, the Declaration states that they lay "... its foundation on such principles and organizing its powers in such form, as to them shall seem most likely to effect their Safety and Happiness."&lt;/p&gt;
&lt;p&gt;It's not enough to content oneself with baser instincts. Instead of choosing the path of blind acceptance, we must choose to temper our molten feelings with the cool water of empirical logic. Only then can we forge a strong future.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Mon, 20 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/07/on-right-action/</guid></item><item><title>Top 29 Developer Docs</title><link>https://dev.to/pomber/top-29-developer-docs-44l0</link><description>A list of the projects with the best developer documentation</description><author>Rodrigo Pombo</author><pubDate>Sun, 19 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dev.to/pomber/top-29-developer-docs-44l0</guid></item><item><title>The Fabric of Reality: The Science of Parallel Universes</title><link>https://macleodsawyer.com/library/the-fabric-of-reality-the-science-of-parallel-universes/</link><description>&lt;p&gt;One Word: &lt;em&gt;&lt;strong&gt;Brilliant&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;</description><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Sat, 18 Jul 2020 04:04:02 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/library/the-fabric-of-reality-the-science-of-parallel-universes/</guid></item><item><title>Blocking Facebook on Android</title><link>https://hth.is/2020/07/18/blocking-facebook-on-android/</link><description>The problem Link to heading While going through my backlog of various bookmarks, I came upon one CCC presentation titled &amp;lsquo;How Facebook tracks you on Android&amp;rsquo; that sees researchers from the organization &amp;lsquo;Privacy International&amp;rsquo; go through their findings on the ways Facebook tracks users on Android, outside of any use of their own applications and without any permissions from users. They do this through the implementation of the Facebook SDK in the various applications available on the Play-Store.</description><author>Hrafn Thorvaldsson</author><pubDate>Sat, 18 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hth.is/2020/07/18/blocking-facebook-on-android/</guid></item><item><title>searchmysite.net: Building a simple search for non-commercial websites</title><link>https://michael-lewis.com/posts/searchmysite.net-building-a-simple-search-for-non-commercial-websites/</link><description>&lt;p&gt;Note: this post is now on blog.searchmysite.net at &lt;a class="external-link" href="https://blog.searchmysite.net/posts/searchmysite.net-building-a-simple-search-for-non-commercial-websites/" rel="noopener" target="_blank"&gt;https://blog.searchmysite.net/posts/searchmysite.net-building-a-simple-search-for-non-commercial-websites/&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="introduction"&gt;
  Introduction
  &lt;a class="heading-link" href="#introduction"&gt;
    &lt;i class="fa-solid fa-link" title="Link to heading"&gt;&lt;/i&gt;
    &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
  &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve written previously about &lt;a href="https://michael-lewis.com/posts/what-went-wrong-with-the-internet-and-how-to-fix-it/"&gt;what went wrong with the internet and how to fix it&lt;/a&gt;, and one of the ideas I mentioned was a new model for search. Given &amp;ldquo;talk is cheap, show me the code&amp;rdquo;, I decided to implement it. Okay, it wasn&amp;rsquo;t quite that easy, but here it is: &lt;a class="external-link" href="https://searchmysite.net" rel="noopener" target="_blank"&gt;https://searchmysite.net&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The key features are that it:&lt;/p&gt;</description><author>Michael Ian Lewis</author><pubDate>Sat, 18 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://michael-lewis.com/posts/searchmysite.net-building-a-simple-search-for-non-commercial-websites/</guid></item><item><title>Semi-Automatic npm and GitHub Releases with `gh-release` and `auto-changelog`</title><link>https://www.swyx.io/release-automation</link><description>A snippet I use all the time</description><author>swyx's site RSS Feed</author><pubDate>Fri, 17 Jul 2020 21:57:45 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/release-automation</guid></item><item><title>Automatically testing for accessibility (a11y) issues with jest-axe</title><link>https://maxrozen.com/automatic-a11y-testing-with-jest-axe</link><description>Automatically test your code for accessibility issues in the same way you catch bugs with jest-axe.</description><author>Max Rozen</author><pubDate>Fri, 17 Jul 2020 18:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/automatic-a11y-testing-with-jest-axe</guid></item><item><title>On Psychedelics and Meditation</title><link>http://spirals.blog/articles/psychedelics-and-meditation/</link><description>&lt;p&gt;I’d like, if you’ll permit me, to tell a story on something that has arisen in many conversations for me of late in my travels. It’s a conversation that has never quite sat right with me for some reason, and I feel compelled, now, to articulate a little further as to why.&lt;/p&gt;
&lt;p&gt;I’m talking about the use of drugs as a tool for spiritual enlightenment, versus the practice of meditation. There seems to be much divide between these two camps, with people often falling into one or the other (in my experience). Stoic students of meditation are often heard exclaiming that they have no need for an external stimulus. And conversely, many others (usually the kind that like to mix partying and spirituality together) have not seemed to pick up the habit of sitting alone with one’s thoughts.&lt;/p&gt;
&lt;p&gt;I’m not here today to argue which is better or worse. I’m here to tell a story on how the two relate to each other, and what they both offer if done “correctly.”&lt;/p&gt;
&lt;h2&gt;The Hedge Maze&lt;/h2&gt;
&lt;p&gt;Imagine, for a moment, that you’re in a giant hedge maze. It’s tall, luscious leaves stretch far above your head, and you are quite incapable of peering above it. For as long as you can remember, you’ve wandered aimlessly through this vexing puzzle of plants, seeking only one thing—the exit. And yet you’re not entirely sure why.&lt;/p&gt;
&lt;p&gt;Life is the hedge maze. Nobody has any idea what it is, or &lt;em&gt;why&lt;/em&gt; it is. But one thing is for sure; we’re all in it.&lt;/p&gt;
&lt;h2&gt;Magic Boots&lt;/h2&gt;
&lt;p&gt;Some of us maze-runners will eventually stumble across something rather spectacular. A magical pair of boots awaits many who care to look and offer rewards for those who put them on. You see, these boots are special; they allow you to jump. High. It is just the thing a weary maze-runner needs to peer above the hedge and look for “the exit.”&lt;/p&gt;
&lt;p&gt;For those that are fortunate enough to happen upon these lofty loafers, life becomes &lt;em&gt;&lt;strong&gt;very&lt;/strong&gt;&lt;/em&gt; exciting. A “heightened” state of awareness brings an individual a far greater ability to “take in” information, be creative, and experience emotions, ideas, and realizations—some of which they would not have encountered even in their “wildest” of dreams. Super shoes feel great.&lt;/p&gt;
&lt;p&gt;But, like all good magic, there’s a downside too. Some of us become over-reliant, even addicted, to the supposed “vision” these super-shoes provide. If we become disillusioned with the endless walls of leaves, and the twists and turns of life, it’s effortless to slip on our boots and shoot for the moon. Life is interesting again, and we can SEE. Until we can’t.&lt;/p&gt;
&lt;p&gt;Like all growth, doing the work is half the job. &lt;strong&gt;The other half is integrating it.&lt;/strong&gt; How do you take the lessons, the shifts, the realizations of the “trip,” and meld them back into “normal life”? Some get over-confident in their jumping expeditions, and on a not-so-good day, land the wrong way! “Broken ankles” are a common sight in the “drugged up, spiritually aware” communities.&lt;/p&gt;
&lt;p&gt;Put another way, you run the risk of having NO idea how to even contemplate what you just experienced. This can literally send people mad. Be careful.&lt;/p&gt;
&lt;h2&gt;The Step-Ladder&lt;/h2&gt;
&lt;p&gt;There are others who, over many moons, collect the odd branch and pieces of wood they find along the way. It’s a slow process; however, they gradually acquire enough resources to build a small step ladder.&lt;/p&gt;
&lt;p&gt;If one plays at this game long enough, they’ll develop enough skill to build something large enough to stand on. And maybe, just maybe, peak over the leering green wall.&lt;/p&gt;
&lt;p&gt;Meditation is a slow practice. It’s challenging in all ways conceivable, can take many years to see any effects (though certainly not always!), and requires &lt;em&gt;constant&lt;/em&gt;, &lt;strong&gt;patient&lt;/strong&gt;, deliberating. Do not expect to download Headspace, close your eyes, and experience non-duality and astral travel. Please.&lt;/p&gt;
&lt;p&gt;Our step ladder is something we carry around with us. We add to it over time, strengthening, and lengthening. There is minimal risk in propping it up against the wall, climbing up for a peek, and stepping back down. It’s much safer than the Moon Boots.&lt;/p&gt;
&lt;h2&gt;Boots and Ladders - A love story&lt;/h2&gt;
&lt;p&gt;Perhaps our argument between psychedelics and meditation is a false dichotomy. Substances certainly have their uses (there is extensive research into their use for therapeutic applications as of writing), especially for those who’ve become disheartened by the hedge maze.&lt;/p&gt;
&lt;p&gt;Sometimes, just what we need is a few micrograms of LSD or Psilocybin to &lt;strong&gt;show us what is possible&lt;/strong&gt;. It can change your life and has done so for millions.&lt;/p&gt;
&lt;p&gt;However, extensive work &lt;strong&gt;must&lt;/strong&gt; also be placed in a daily practice of self-reflection. Meditation provides the tools to understand what we experience on drugs and integrate it into our lives. It also stops us from over-relying on the euphoric, temporary states of “enlightenment.” It’s safer and better for us in the long run. When combined with “smart” use of substances, the two may provide incredible healing, powerful realizations, and a broader perspective.&lt;/p&gt;
&lt;p&gt;What are your thoughts on the matter?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cover photo by Sigmund @sigmund&lt;/em&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Fri, 17 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/psychedelics-and-meditation/</guid></item><item><title>Tailscale, RFC1918, and DNS Rebinding Protection</title><link>https://caiustheory.com/tailscale-rfc1918-and-dns-rebinding-protection/</link><description>&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; &lt;em&gt;Originally this post was written to be a workaround for Tailscale routing all DNS traffic over its own link when you configured it to push out existing DNS Server IPs. This turned out to be a bad assumption on my part. Thanks to &lt;a href="https://twitter.com/apenwarr"&gt;apenwarr&lt;/a&gt; for helping me understand that shouldn&amp;rsquo;t be the case, and encouraging me to debug it properly rather than making assumptions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Naturally it turned out to be a &lt;a href="https://www.urbandictionary.com/define.php?term=pebkac"&gt;PEBKAC&lt;/a&gt;. I&amp;rsquo;d pushed out &lt;code&gt;162.159.25.4&lt;/code&gt; as the DNS Server IP which is a nameserver rather than a forwarder. This in turn meant people were getting empty answers back to DNS queries, which stopped once they quit tailscale. (Go figure, Tailscale removes the resolver from the network stack when it quits.) The post has been updated to remove that invalid assumption. 🤦🏻‍♂️&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Imagine we have a fleet of machines sat in a private network somewhere on a &lt;code&gt;172.16.20.20/24&lt;/code&gt; IP range, with entries pointing at them published on public DNS servers. Eg, &lt;code&gt;dig +short workhorse.fake.tld&lt;/code&gt; returns &lt;code&gt;172.16.20.21&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Initially this all works swimmingly, until someone comes along that is using a DNS forwarder that with DNS rebinding protection enabled. Daniel Miessler has a &lt;a href="https://danielmiessler.com/blog/dns-rebinding-explained/"&gt;wonderfully succinct explanation on his blog&lt;/a&gt; about DNS Rebinding attacks, but to protect against it you stop your resolver returning answers to DNS queries from public servers which resolve to IP addresses within standard internal network ranges. (ie, &lt;a href="https://www.ietf.org/rfc/rfc1918.txt"&gt;rfc1918&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;This means for those users they can successfully connect to our Tailscale network and access everything by IPs directly, but can&amp;rsquo;t access any of the internal infrastructure by hostname. eg, &lt;code&gt;dig +short workhorse.fake.tld&lt;/code&gt; will return an empty answer for them.&lt;/p&gt;
&lt;p&gt;Once we figured out the root cause of that, for workarounds we figured we could either run a DNS forwarder within our own infrastructure, or get all our staff to change their home DNS settings and hope they were never on locked down networks ever again.&lt;/p&gt;
&lt;p&gt;We chose the former, and thankfully &lt;a href="http://www.thekelleys.org.uk/dnsmasq/doc.html"&gt;dnsmasq&lt;/a&gt; is really easy to configure in this fashion and we already have a node which is acting as the tailscale subnet relay, so we dropped the following config in &lt;code&gt;/etc/dnsmasq.conf&lt;/code&gt; on there:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;# Only listen for requests from VPN/local for debugging
interface=tailscale0
interface=lo
# Google DNS
server=8.8.8.8
server=8.8.4.4
# Quad9
server=9.9.9.9
# Cloudflare
server=1.1.1.1
server=1.0.0.1
# Race all servers to see which wins
all-servers
# Try and stop DNS rebinding, except where we expect it to happen
bogus-priv
stop-dns-rebind
rebind-localhost-ok
rebind-domain-ok=/fake.tld/
domain-needed
filterwin2k
no-poll
no-resolv
cache-size=10000
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One quick puppet run later, and our Tailscale subnet relays are happily running both tailscale and dnsmasq, serving out answers as fast as they can to other Tailscale nodes. Add port 53 to the &lt;a href="https://www.tailscale.com/kb/1018/acls"&gt;Tailscale ACL&lt;/a&gt; and away we went.&lt;/p&gt;</description><author>Caius Theory</author><pubDate>Thu, 16 Jul 2020 23:00:00 GMT</pubDate><guid isPermaLink="true">https://caiustheory.com/tailscale-rfc1918-and-dns-rebinding-protection/</guid></item><item><title>Word embedding fun</title><link>https://dorotac.eu/posts/embeddings/</link><description>&lt;h1&gt;Word embedding fun&lt;/h1&gt;
&lt;p&gt;I'm terrible at naming things. When others come up with slick user names like "el_duderino", or "pseudolus", I struggle to come up with anything better than "blob123". Right now I'm busy setting up a new project which needs a name, and I struggle with inspiration.&lt;/p&gt;
&lt;p&gt;What if there was a machine to transform terrible ideas into good ones? Take a trope, and tweak it a little to get something original?&lt;/p&gt;
&lt;h2&gt;Word vectors&lt;/h2&gt;
&lt;p&gt;I'm not going to pretend that I know exactly what the term "&lt;a href="https://en.wikipedia.org/wiki/Word_embedding"&gt;word embedding&lt;/a&gt;" means. What matters is that words in a human language can be associated to vectors in a linear space. With a little thinking, we can leverage that property to find words with similar meanings, or solve analogies like this one:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What is to woman as king is to man?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course, it's "queen". The example is the classic one, so please read &lt;a href="https://blog.acolyer.org/2016/04/21/the-amazing-power-of-word-vectors/"&gt;this&lt;/a&gt; because I couldn't explain it better than that article.&lt;/p&gt;
&lt;p&gt;Okay, so what about the trope? Let's try with a political meme:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What's the anarchist version of "&lt;a href="https://knowyourmeme.com/memes/cultures/fully-automated-luxury-gay-space-communism"&gt;fully automated luxury gay space communism&lt;/a&gt;"?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Playing with words&lt;/h2&gt;
&lt;p&gt;To answer the question, I installed &lt;em&gt;gensim&lt;/em&gt; from pip, and fetched some &lt;a href="https://radimrehurek.com/gensim/auto_examples/howtos/run_downloader_api.html"&gt;ready-made data&lt;/a&gt;. Using Python3 interactively, I started this way:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import gensim.downloader as api
corpus = api.load('text8')
from gensim.models.word2vec import Word2Vec
model = Word2Vec(corpus)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that I had a vector space with words, I started playing with it, translating the meme word by word. If "fully" is a "communism" term, what's its "anarchism" version?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; model.wv.similar_by_vector(-model.wv['communism'] + model.wv['anarchism'] + model.wv['fully'])
[('fully', 0.7874691486358643), ('correctable', 0.5339317321777344), ('strictly', 0.533452033996582), ('wholly', 0.5306737422943115), ('totally', 0.5066695213317871), ('properly', 0.4988959729671478), ('locally', 0.4917019009590149), ('entirely', 0.4908182919025421), ('statically', 0.48547613620758057), ('completely', 0.4838995933532715)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turns out it's still "fully". Going all the way, we get "fully introductory ornamental gay space humanism". That's a bit surprising! According to the model, "communist" is to "communism" as "anarchist" is to "humanism". I blame it on the model being relatively small.&lt;/p&gt;
&lt;h2&gt;Readable encyclopedic excellent lesbian topological altruism&lt;/h2&gt;
&lt;p&gt;This is the best nugget I got out of the &lt;em&gt;text8&lt;/em&gt; corpus. It seems to be giving a nice selection of words with similar meanings, although changing the political option doesn't seem to do much. Other examples of computer-generated silliness include "perfectly analytical aquarium bisexual seti individualist" and "fully extensible cheddar gay space anarchism". I'm going to keep "fully extensible cheddar" for a different project…&lt;/p&gt;
&lt;h2&gt;Using a larger model&lt;/h2&gt;
&lt;p&gt;Seeing the obvious drawbacks in accuracy and lack of sensitivity to political stances, I tried to use a serious model, based on the Wikipedia. &lt;em&gt;Gensim&lt;/em&gt; doesn't disappoint in that department either:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;model = api.load("fasttext-wiki-news-subwords-300")
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After coming back from the tea break, we are in a 300-dimensional model, containing the condensed knowledge of Wikipedia. Let's see how it fares:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; model.wv.similar_by_vector(-model.wv['communist'] + model.wv['anarchist'] + model.wv['communism'])
[('anarchism', 0.883374810218811), ('anarchist', 0.8050785064697266), ('Anarchism', 0.7585680484771729), ('anarcho-syndicalism', 0.7496938705444336), ('anarcho-communism', 0.7432658672332764), ('anarchists', 0.7426955699920654), ('anarcho-socialism', 0.7400932312011719), ('anarchistic', 0.7102389931678772), ('anarcho-capitalism', 0.7090942859649658), ('anarchisms', 0.7069689035415649)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Good! It could derive that the "anarchism" equivalent of "communist" is "anarchist".&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; model.wv.similar_by_vector(-model.wv['communism'] + model.wv['anarchism'] + model.wv['fully'])
[('fully', 0.8348307609558105), ('fullly', 0.6537811756134033), ('fuly', 0.6530433893203735), ('thoroughly', 0.6464489102363586), ('completely', 0.6422995328903198), ('properly', 0.6398820877075195), ('adequately', 0.6317397356033325), ('fully-', 0.6239138841629028), ('comprehensively', 0.6175973415374756), ('partially', 0.606654167175293)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uh, there's a bit of repetition there. What about other words?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; model.wv.similar_by_vector(-model.wv['communism'] + model.wv['anarchism'] + model.wv['space'])
[('space', 0.8099461793899536), ('sub-space', 0.6615338325500488), ('spaces', 0.6537838578224182), ('work-space', 0.6258285045623779), ('non-space', 0.6244523525238037), ('space--and', 0.6012811064720154), ('workspace', 0.6001818776130676), ('WPspace', 0.5913711786270142), ('space-', 0.5863816738128662), ('space--', 0.5790454745292664)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Disappointing :( I had to dig through a lot of results to get anything not related to the original word. Here are some examples: "adequately anarchist high-end lesbian column-free libertarianism", "completely computerized boutique-style heterosexual  hypersphere anti-capitalism".&lt;/p&gt;
&lt;h2&gt;Different APIs&lt;/h2&gt;
&lt;p&gt;There's another API to create analogies: it's the &lt;code&gt;most_similar&lt;/code&gt; call. It works like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; model.most_similar(positive=['anarchism', 'space'], negative=['communism'])
[('sub-space', 0.6117153763771057), ('spaces', 0.5981306433677673), ('work-space', 0.5736098885536194), ('non-space', 0.5651520490646362), ('workspace', 0.5563109517097473), ('space--and', 0.542439341545105), ('WPspace', 0.5411180257797241), ('space-', 0.5368467569351196), ('meta-space', 0.5321565866470337), ('space--', 0.5256682634353638)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The results are a little different, although I don't know why. Perhaps it's about a different way of measuring similarity.&lt;/p&gt;
&lt;h2&gt;Word salad&lt;/h2&gt;
&lt;p&gt;Using models to reveal some hidden properties of political options didn't work out, but the smaller model was a decent thesaurus. I suspect this is due to less words, creating more varied results near the best answer. I don't know how the 2 APIs differ. While I expected the similarity function to work based on Euclidean distance, it seems to be based on cosine distance instead. Perhaps that's the reason the anchor word sometimes ends up in results as well.&lt;/p&gt;
&lt;p&gt;All in all, I think word vectors are going to end up being a nice toy, when some weirdness is needed for brainstorming. Let "aquarium" be an example: it's far out in terms of adjectives, but it is indeed not entirely unrelated to "luxury".&lt;/p&gt;</description><author>dcz's posts</author><pubDate>Thu, 16 Jul 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/embeddings/</guid></item><item><title>LAHC: a must for your software engineering toolbox</title><link>https://thedarkside.frantzmiccoli.com/tricks/2020/07/16/late-acceptance-hill-climbing-engineering-toolbox.html</link><description>&lt;p&gt;tl;dr Late Acceptance Hill Climbing, LAHC, is a so simple and so efficient 
optimization algorithm that I think  it belongs to any software person toolbox.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I have always been fond of metaheuristic optimization algorithms.
Evolutionary algorithms and the likes fascinate me, simply because of 
biomimetism, and also, a bit, because they work. 
They can apply to every optimization problems. The caveat is that even you can
apply it everywhere, those approaches give approximate solutions and often take
quite some time to run. So beware of using the right tool at hand.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Your scientist were so preoccupied with whether or not they could they didn't 
stop to think if they should" src="/res/malcolm.gif" /&gt;&lt;/p&gt;

&lt;p&gt;A few years ago, I wrote &lt;a href="https://frantzmiccoli.github.io/Gimuby"&gt;Gimuby&lt;/a&gt;, 
a quite complete Ruby library to experiment with genetic algorithms and a 
variant called the island model. I kept the taste for that kind of things.&lt;/p&gt;

&lt;p&gt;The first Covid-19 lockdown gave me the opportunity to try to do some live
coding so if you wish to see 
&lt;a href="https://www.youtube.com/watch?v=5uO-CfSJWng"&gt;3h of live programming 
around LAHC&lt;/a&gt;, 
be my guest. If you need a library for Ruby, the product of this session,
&lt;a href="https://github.com/frantzmiccoli/Lahcuby"&gt;Lahcuby&lt;/a&gt;, is available.&lt;/p&gt;

&lt;h2 id="academics"&gt;Academics&lt;/h2&gt;

&lt;p&gt;The algorithm has been introduced by 
&lt;a href="https://doi.org/10.1016/j.ejor.2016.07.012"&gt;Burke and Bykov, 2016&lt;/a&gt;, I did not
run any benchmark but the paper claims state of the art performance compared to
similar methods. But this is not what I find the most interesting here, even
though without it nobody would have mentioned it.&lt;/p&gt;

&lt;p&gt;If you consider a random problem and a random metaheuristic algorithm 
to solve it, there are many parameters to consider. First about how you represent
the problem and its potential solutions, but also how you set the different
parameters of your algorithm, and those two things interact with one another.
For example, the way you represent an itinerary of a 
&lt;a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem"&gt;traveling salesman&lt;/a&gt;,
how you mix two itineraries in a third one, how you select which itineraries
to keep and how and how often you randomly change an itinerary. All those things
have an impact on one another when you are trying to get the best possible 
result. Meaning that fine tuning your optimization algorithm is an 
optimization problem by itself.&lt;/p&gt;

&lt;p&gt;Your next T-shirt should say:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I used metaheuristics on my optimization problem,
  and all I got was this lousy hyperparameter optimization problem&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The cool thing with LAHC is its simplicity, there is a single parameter.
Your mileage may not vary, and you may find consistency in your results. I do 
not believe in silver bullets, but this might be as close as you can get.&lt;/p&gt;

&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;

&lt;p&gt;Lets start with a simple gradient descent algorithm:&lt;/p&gt;

&lt;div class="language-python highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_initial_solution&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;max_iteration_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;max_iteration_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    
    &lt;span class="n"&gt;alternative_solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_variation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;alternative_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alternative_solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;alternative_cost&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
        
    &lt;span class="c1"&gt;# we have found a better solution
&lt;/span&gt;    &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alternative_solution&lt;/span&gt;
    &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alternative_cost&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I am starting with this because LAHC is very close to a gradient descent, but it
should not get stuck in local minimums. Actually “gradient descent”, is just
another way to say “hill climbing”.&lt;/p&gt;

&lt;p&gt;Here are the two differences:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Instead of keeping only a solution, the algorithm keeps a solution plus an 
history of the previously encountered costs, we will call it the &lt;code class="language-plaintext highlighter-rouge"&gt;Memory&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Instead of accepting an alternative solution only if it is better than the 
current one, the alternative solution is also accepted if it is better than the
cost at the current &lt;code class="language-plaintext highlighter-rouge"&gt;Memory Index&lt;/code&gt;. If such a case occurs the alternative 
solution cost gets stored in the &lt;code class="language-plaintext highlighter-rouge"&gt;Memory&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All the rest is intendance:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Initializing the &lt;code class="language-plaintext highlighter-rouge"&gt;Memory&lt;/code&gt;, the authors set it to be the initial cost. 
My personal views are different, it could be set with random solutions’ costs
to lessen the risk of a bad initialization. I keep the authors view in the
implementation below to show a simpler version.&lt;/li&gt;
  &lt;li&gt;Rotating the &lt;code class="language-plaintext highlighter-rouge"&gt;Memory Index&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Deciding to end the loop, the authors suggest to set a minimum number of
iterations and then wait for enough idle iterations - i.e iterations where the 
current solution does not get updated. To keep things simple I just set a 
maximum number of iterations here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note here that the only parameter here is the &lt;code class="language-plaintext highlighter-rouge"&gt;Memory Size&lt;/code&gt;.&lt;/p&gt;

&lt;div class="language-python highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;&lt;span class="n"&gt;memory_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;  &lt;span class="c1"&gt;# The only algorithm parameter
&lt;/span&gt;
&lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_initial_solution&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cost_memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;memory_size&lt;/span&gt;  &lt;span class="c1"&gt;# Memory initialization
&lt;/span&gt;
&lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;max_iteration_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;max_iteration_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# Exit condition 
&lt;/span&gt;    &lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    
    &lt;span class="n"&gt;alternative_solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_variation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;alternative_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_cost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alternative_solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;better_than_solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alternative_cost&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;
    
    &lt;span class="n"&gt;memory_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iteration_count&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;memory_size&lt;/span&gt;
    &lt;span class="n"&gt;current_memorized_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cost_memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;memory_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;better_than_memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alternative_cost&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;current_memorized_cost&lt;/span&gt;
    
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;better_than_solution&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;better_than_memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# We have found a better solution
&lt;/span&gt;        &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alternative_solution&lt;/span&gt;
        &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alternative_cost&lt;/span&gt;
        
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;better_than_memory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  
        &lt;span class="c1"&gt;# We update the memory, that will constrain the algorithm to finer 
&lt;/span&gt;        &lt;span class="c1"&gt;# grain solutions over time 
&lt;/span&gt;        &lt;span class="n"&gt;cost_memory&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;memory_index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;alternative_cost&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;My main criticism about LAHC is its name, Late Acceptance Hill Climbing.
The acceptance is not late.&lt;/p&gt;

&lt;p&gt;The benchmark against which solution is accepted is lagged or large - meaning 
there is more than one reference points. Would it be better to have it named
LaBeHC, Lagged/Large Benchmark Hill Climbing?&lt;/p&gt;

&lt;h2 id="benefits"&gt;Benefits&lt;/h2&gt;

&lt;h3 id="low-tuning-required"&gt;Low tuning required&lt;/h3&gt;

&lt;p&gt;As discussed above depending on the problem and also on the implementation, 
the logic behind obtaining a solution variation is often impacting the optimal 
configuration of hyperparameters. Here, the only hyperparameter, 
&lt;code class="language-plaintext highlighter-rouge"&gt;Memory Size&lt;/code&gt;, is enough to allow more changes in the solution to have a better 
solution space exploration.
Over time, no matter how big the &lt;code class="language-plaintext highlighter-rouge"&gt;Memory Size&lt;/code&gt;, with the process going on, the
algorithm will progressively switch from exploration to exploitation to 
refine most optimal solution.&lt;/p&gt;

&lt;h3 id="low-entry-barrier"&gt;Low entry barrier&lt;/h3&gt;

&lt;p&gt;The presented LAHC implementation is only about 25 extra lines compared to a 
gradient descent. It is probably about the same size of a grid search but it
should provide much better results.&lt;/p&gt;

&lt;p&gt;This means that, unlike most metaheuristics, you can implement it inside your
program in a couple of hours regardless of your technical stack.&lt;/p&gt;

&lt;h3 id="same-benefits-as-other-metaheuristics"&gt;Same benefits as other metaheuristics&lt;/h3&gt;

&lt;p&gt;I did not put to the test the result of the original paper, but the approach is
respected and I think it deserves due credit. In my experience, I replaced both
gradient descent and grid search by this, and observed great results in both
cases… one major counter example being 
&lt;a href="https://www.youtube.com/watch?v=5uO-CfSJWng"&gt;the live programming session&lt;/a&gt; - 
the curse of the live demo.&lt;/p&gt;</description><author>The Dark Side</author><pubDate>Thu, 16 Jul 2020 13:08:36 GMT</pubDate><guid isPermaLink="true">https://thedarkside.frantzmiccoli.com/tricks/2020/07/16/late-acceptance-hill-climbing-engineering-toolbox.html</guid></item><item><title>Born on the Links: A Concise History of Golf</title><link>https://macleodsawyer.com/library/born-on-the-links-a-concise-history-of-golf/</link><description>&lt;p&gt;From the hairie (a golf ball made from cows hair), to the featherie (feathers from geese, wrapped in paint), to the gutta-percha (made from rubber).&lt;/p&gt;
&lt;p&gt;This books tells the story of the way the rules were written (or not, for the first two hundred years), the bans on golf, the price of admission, winnings and losses of the greatest players and games of all time, and to the marketability of the game itself and the ‘superstars’ that the game requires.&lt;/p&gt;
&lt;p&gt;This was an interesting book that dragged on for large swaths on needless descriptors of specific games with every stroke, putt, and tee setting.  I didn’t see a reason for doing so, there were a few detailed games that were very well written and exciting, but for the most part this was not needed.&lt;/p&gt;
&lt;p&gt;I enjoyed the book, and anyone who is a fan of golf should pick it up - but you may just need to skim those sections as they take up quite a bit of the second half of the book.&lt;/p&gt;</description><author>Macleod Sawyer | Web Portal Feed</author><pubDate>Thu, 16 Jul 2020 05:06:36 GMT</pubDate><guid isPermaLink="true">https://macleodsawyer.com/library/born-on-the-links-a-concise-history-of-golf/</guid></item><item><title>We don't know what we don't know</title><link>https://wdkwwdk.com/posts/we-dont-know/</link><description>&lt;p&gt;Sometimes it's important to remind ourselves that we don't know what we don't know!&lt;/p&gt;
&lt;p&gt;I recently began to spend more effort considering and emphasizing what pieces might be missing from a particular engineering puzzle. Like many engineers, I rely heavily on mental models when tackling technical problems. The problem is, these mental models are seldom complete, with gaps or assumptions, which leads to mistakes or discounting approaches to a question we didn't know to consider.&lt;/p&gt;
&lt;p&gt;Let's spend some time considering what it means not to know what we don't know and how we can remind ourselves of some of our own biases.&lt;/p&gt;
&lt;h2 id="my-first-experience-with-wdkwwdk"&gt;&lt;a class="zola-anchor" href="#my-first-experience-with-wdkwwdk"&gt;My first experience with WDKWWDK&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For me, this realization first came during a meeting.&lt;/p&gt;
&lt;p&gt;We were trying to tackle a specific security challenge that required selecting a cryptographic protocol with particular properties. I was in the position to make the recommendations, which came down to &lt;a href="http://www.noiseprotocol.org"&gt;Noise&lt;/a&gt; based on some &lt;a href="https://latacora.com"&gt;industry experts'&lt;/a&gt; suggestions.&lt;/p&gt;
&lt;p&gt;The problem we had is we weren't able to locate an implementation of the protocol for our embedded CPU. While I was evolving into a security lead for the team with a better than average understanding of security principles, I was utterly ill-prepared to write a crypto implementation that would pass any scrutiny.&lt;/p&gt;
&lt;p&gt;However, with the most knowledge, the team asked me to develop the implementation.&lt;/p&gt;
&lt;p&gt;I objected, indicating that writing a cryptographic implementation is detailed work, and it's challenging to be sure that the implementation is correct.&lt;/p&gt;
&lt;p&gt;The team countered, saying that it must be correct if the implementation can communicate with another library (on a known CPU architecture).&lt;/p&gt;
&lt;p&gt;The problem is it's possible to write a compatible protocol implementation, that has significant security problems. Re-using nonces or timing attacks could ruin our day, and we'd easily miss out on the security properties we desired.&lt;/p&gt;
&lt;p&gt;The team countered again, indicating that if I knew about problems like nonce re-use or timing attacks, that I should avoid those problems. &lt;/p&gt;
&lt;p&gt;Any problem I can describe in theory should be a problem I can avoid.&lt;/p&gt;
&lt;p&gt;Eventually, I had to figure out to approach this engineering conversation as an admission, I don't know what I don't know, so I'm ill-prepared to solve problems I don't even know to avoid. &lt;/p&gt;
&lt;p&gt;Not only did I need to admit what I didn't know, but as a team, we had to admit combined that we didn't know what we didn't know. In many scenarios, we may be able to get away with this, but here, a failure meant we failed to deliver on our security promises to our customers.&lt;/p&gt;
&lt;h2 id="is-this-the-dunning-kruger-effect"&gt;&lt;a class="zola-anchor" href="#is-this-the-dunning-kruger-effect"&gt;Is this the Dunning-Kruger effect?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For those who aren't familiar, a simplified version of the Dunning-Kruger effect states that a cognitive bias exists where individuals with limited knowledge or competence in a given intellectual domain greatly overestimate their expertise or skill in that domain. And that those with a great deal of expertise tend to underestimate their results. &lt;/p&gt;
&lt;p&gt;This cognitive bias is fascinating and may explain some of the &amp;quot;solutions&amp;quot; or &amp;quot;projects&amp;quot; we see that claim perfect security while not holding up to basic scrutiny.&lt;/p&gt;
&lt;p&gt;While the Dunning-Kruger effect may apply here, we often forget that this cognitive bias only means that people scoring in the 12th percentile had ranked themselves in the 62nd percentile. But those in the 90th percentile had self-assessed to be within the ~75th percentile. &lt;/p&gt;
&lt;p&gt;&lt;img alt="Image from Dunning-Kruger Research" src="https://www.researchgate.net/profile/David_Dunning2/publication/12688660/figure/fig1/AS:394431292297232@1471051156893/Perceived-ability-to-recognize-humor-as-a-function-of-actual-test-performance-Study-1.png" /&gt;
&lt;a href="https://www.researchgate.net/figure/Perceived-ability-to-recognize-humor-as-a-function-of-actual-test-performance-Study-1_fig1_12688660"&gt;Dunning-Kruger effect on research gate for more information&lt;/a&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;With this in mind, on average, individuals without much exposure do not rank themselves as experts in an area they don't know.&lt;/p&gt;
&lt;p&gt;We can still draw an important lesson here; that we need to be aware of and careful of our biases, whether it be the Dunning-Kruger effect or something else.&lt;/p&gt;
&lt;h2 id="unconscious-fear"&gt;&lt;a class="zola-anchor" href="#unconscious-fear"&gt;Unconscious Fear&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img alt="xkcd 1053" src="https://imgs.xkcd.com/comics/ten_thousand.png" /&gt;
&lt;a href="https://xkcd.com/1053/"&gt;xkcd 1053&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As engineers, I think we get used to analyzing complex problems and coming back with answers. Especially those of us who are known for digging in and finding the solutions.&lt;/p&gt;
&lt;p&gt;When given a task, there may also be a particular fear associated with not having the answer. If your leadership or team members expect you are an expert in a domain and are assigned a problem, it feels like a failure to return without the full solution. &lt;/p&gt;
&lt;p&gt;For me, it's even come to the point where others have tried shame me in front of my peers for not knowing some technical detail off hand. This behaviour creates perverse incentives that it's better to stick with an assumption than admit we don't know something. I know I've unconciously affected others in this same way, which is one of my regrets. &lt;/p&gt;
&lt;p&gt;A large part of this is realizing it's not a failure to admit that we have missing knowledge. We may not remember some details or have more research to do. Maybe there is no action required. The failure is to proceed without identifying the risk of the missing information. Whether an expert or not, there are always going to be missing details. When working in security, the missed detail could be the difference between high and abysmal security. In other domains, the risks may be much different.&lt;/p&gt;
&lt;p&gt;Knowing the risks of missing information allows us to choose whether to accept those risks. &lt;/p&gt;
&lt;h2 id="how-do-i-apply-this"&gt;&lt;a class="zola-anchor" href="#how-do-i-apply-this"&gt;How do I apply this?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I think it's as simple as stating, &amp;quot;We don't know what we don't know&amp;quot; in a conversation, or typing WDKWWDK into a document or chat session. And ensuring our teams and leaders don't allow a stigma to exist around not knowing some details.&lt;/p&gt;
&lt;p&gt;I'm not the &lt;a href="https://shaker.com/questions-your-company-needs-to-be-asking-itself-and-acting-on-now/"&gt;first&lt;/a&gt; to use this acronym, but I also don't believe we use it enough.&lt;/p&gt;
&lt;p&gt;This statement of fact, acts as a reminder, that we should step back and consider how our biases may impact a particular decision or design and to identify what information may be missing.&lt;/p&gt;
&lt;p&gt;We can then consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What we know&lt;/li&gt;
&lt;li&gt;What we know we don't know&lt;/li&gt;
&lt;li&gt;If there is anything we don't know what we don't know that needs exploration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And decide on the risks of proceeding with missing information, cognizant that there will always be missing information.&lt;/p&gt;
&lt;h2 id="summary"&gt;&lt;a class="zola-anchor" href="#summary"&gt;Summary&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before committing to an approach to an engineering problem, remind yourself or the team that there are likely missing details that may affect the outcome. How to proceed largely depends on the risks involved, topics like security have different risks than the CI/CD pipeline. &lt;/p&gt;
&lt;p&gt;And we need to remind ourselves and our peers to avoid the stigmas and biases introduced by admitting we don't know things. Being an expert in a domain like security, doesn't mean memorization of every algorithm, every protocol, or approach.&lt;/p&gt;</description><author/><pubDate>Thu, 16 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://wdkwwdk.com/posts/we-dont-know/</guid></item><item><title>Reinventing School</title><link>https://one.mikro2nd.net/pages/reinventing-school/</link><description>There is no such thing as a problem without a gift for you in its hands. Richard Bach, &amp;ldquo;Illusions&amp;rdquo;
We&amp;rsquo;ve had a hard lockdown, and everyone is tired of it. I understand. We&amp;rsquo;ve got to get people back to work, get The Economy working again. I understand. So that means we&amp;rsquo;ve got to get the kids Back To School. And out of the way. Anyway, not all of the children forced to try and School At Home have good access to the internet for taking classes online.</description><author>one mikro2nd</author><pubDate>Thu, 16 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/reinventing-school/</guid></item><item><title>Upgrade to Ubuntu 20.04 from 19.10</title><link>https://rd.nz/2020/07/upgrade-to-ubuntu-2004-from-1910.html</link><description>Fixing things when they break partway</description><author>Rich Dougherty</author><pubDate>Wed, 15 Jul 2020 22:11:00 GMT</pubDate><guid isPermaLink="true">https://rd.nz/2020/07/upgrade-to-ubuntu-2004-from-1910.html</guid></item><item><title>Screwed by Lufthansa and the German Government, Saved by PayPal</title><link>https://svedic.org/travel/screwed-by-lufthansa-german-government-saved-by-paypal</link><description>The travel and tourism sectors are suffering because of the COVID-19 pandemic, and governments are scrambling to offer subsidies to affected businesses. But, there is little talk on how companies are transferring their costs to citizens, with government approval. In &amp;#8230; &lt;a href="https://svedic.org/travel/screwed-by-lufthansa-german-government-saved-by-paypal"&gt;Continue reading &lt;span class="meta-nav"&gt;&amp;#8594;&lt;/span&gt;&lt;/a&gt;</description><author>Svedic.org</author><pubDate>Wed, 15 Jul 2020 20:33:22 GMT</pubDate><guid isPermaLink="true">https://svedic.org/travel/screwed-by-lufthansa-german-government-saved-by-paypal</guid></item><item><title>ALIFE 2020 - Robot Cancer</title><link>https://liza.io/alife-2020-robot-cancer/</link><description>&lt;p&gt;These are my hastily taken and edited notes on the first ALIFE 2020 conference keynote, presented by Mike Levin.&lt;/p&gt;
&lt;h2 id="robot-cancer---why-dont-todays-robots-get-cancer"&gt;Robot Cancer - why don&amp;rsquo;t (today&amp;rsquo;s) robots get cancer?&lt;/h2&gt;
&lt;p&gt;By Michael Levin, director of the Allen Discovery Center at Tufts and the Tufts Center for Regenerative and Developmental Biology.&lt;/p&gt;</description><author>Liza Shulyayeva</author><pubDate>Wed, 15 Jul 2020 14:40:00 GMT</pubDate><guid isPermaLink="true">https://liza.io/alife-2020-robot-cancer/</guid></item><item><title>The hardship of SaaS in the video games industry</title><link>https://philippzentner.com/hardship-saas-video-games-industry.html</link><description>&lt;img alt="" src="https://philippzentner.com/media/posts/21/alexey-savchenko-k4Akpt5-Sfk-unsplash.jpg" /&gt;
                    At STOMT we've been focusing on the video games industry. And let me tell you, it's been a ride. When we started out, we tried to approach the industry from the bottom-up. We got feedback and love from independent developers first and then started to&amp;hellip;</description><author>Philipp Zentner</author><pubDate>Wed, 15 Jul 2020 13:04:40 GMT</pubDate><guid isPermaLink="true">https://philippzentner.com/hardship-saas-video-games-industry.html</guid></item><item><title>Laravel Localization Case Tips</title><link>https://james.brooks.page/blog/laravel-localization-case-tips</link><description>Here is a little tip for Laravel’s Localization that I discovered today whilst looking through the open Laravel Nova issues. Although it’s documented it’s not well known - at least, I didn’t know about it before today!</description><author>James Brooks</author><pubDate>Wed, 15 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://james.brooks.page/blog/laravel-localization-case-tips</guid></item><item><title>Clearing Mac Storage Space</title><link>https://www.dannyguo.com/blog/clearing-mac-storage-space</link><author>Danny Guo</author><pubDate>Wed, 15 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.dannyguo.com/blog/clearing-mac-storage-space</guid></item><item><title>📋get_HN_favorites.py</title><link>https://www.jskherman.com/gists/get_hn_favorites.py/</link><description>A Python script to get HN favorites for a user.</description><author>jskherman</author><pubDate>Wed, 15 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.jskherman.com/gists/get_hn_favorites.py/</guid></item><item><title>What's new in Lua 5.4</title><link>https://lwn.net/Articles/826134/</link><description>An overview of the new features in Lua 5.4 (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Wed, 15 Jul 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/826134/</guid></item><item><title>Six Trends Shaping Developer Productivity</title><link>https://whoisnnamdi.com/developer-productivity-trends/</link><description>We interviewed developer productivity leaders. Here's what they said.</description><author>Who is Nnamdi?</author><pubDate>Tue, 14 Jul 2020 22:20:44 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/developer-productivity-trends/</guid></item><item><title>ALIFE 2020 - Soft alife with SPLAT and Ulam</title><link>https://liza.io/alife-2020-soft-alife-with-splat-and-ulam/</link><description>&lt;p&gt;Below are some rough notes from a tutorial session called Soft alife with SPLAT and Ulam by David Ackley. These notes are very hastily taken and I am editing them between sessions mostly for my own benefit, so expect to see typos and maybe even mis-wordings.&lt;/p&gt;</description><author>Liza Shulyayeva</author><pubDate>Tue, 14 Jul 2020 14:40:00 GMT</pubDate><guid isPermaLink="true">https://liza.io/alife-2020-soft-alife-with-splat-and-ulam/</guid></item><item><title>The National Broadband Network (NBN) A Massive Dissapointment</title><link>https://boyter.org/posts/national-broadband-network-a-massive-dissapointment/</link><description>&lt;p&gt;I write this mostly so I can move on. The NBN has been a source of constant frustration and anger for me. While I will never forgive those who caused the current shambles I can perhaps redirect my anger elsewhere will keeping it in the back of my mind.&lt;/p&gt;
&lt;p&gt;So here is my brief time-line of NBN.&lt;/p&gt;
&lt;p&gt;I moved to area that was due to get NBN FTTP in ~2014. The fact that it was due to get such a connection influenced the decision. With the change in government that ended up going away. I was then promised by Senator Fifield (who replaced Malcolm Turnbull as communications Minister) while on the campaign trail for the 2016 election that NBN would start construction in the area in 2016. This however was pushed back to 2017. What followed was it being pushed out roughty every 3 months. Finally told it will be done in June 2018.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Tue, 14 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/national-broadband-network-a-massive-dissapointment/</guid></item><item><title>A "super ping" command to run while diagnosing network issues</title><link>https://allanrbo.blogspot.com/2020/07/a-super-ping-command-to-run-while.html</link><description>&lt;p&gt;Here's a bash function for your bash profile that continuously prints some basic checks I usually do while diagnosing network issues:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Show my LAN IPs&lt;/li&gt;
  &lt;li&gt;Show the default gateway IP&lt;/li&gt;
  &lt;li&gt;Ping the default gateway IP&lt;/li&gt;
  &lt;li&gt;Ping 8.8.8.8 (Google's public DNS servers)&lt;/li&gt;
  &lt;li&gt;DNS resolve amazon.com&lt;/li&gt;
  &lt;li&gt;Ping amazon.com&lt;/li&gt;
  &lt;li&gt;Get my WAN IP by curl'ing ifconfig.me&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tested on Ubuntu 20.04 and MacOS Catalina&lt;/p&gt;

&lt;pre class="code"&gt;
function pingg() {
    while true; do
        printf &amp;quot;%s  &amp;quot; $(TZ=UTC date &amp;quot;+%Y-%m-%dT%H:%M:%S&amp;quot;)

        if [[ &amp;quot;$OSTYPE&amp;quot; == &amp;quot;darwin&amp;quot;* ]]; then
            lanIps=$(ifconfig | grep &amp;quot;inet &amp;quot; | grep -v 127.0.0.1 | awk '{print $2}' | paste -d, -s -)
            gw=$(netstat -rn -f inet | grep default | awk '{print $2}')
        else
            lanIps=$(ip addr | grep &amp;quot;inet &amp;quot; | grep -v 127.0.0.1 | awk '{print $2}' | paste -d, -s -)
            gw=$(ip route | grep default | awk '{print $3}')
        fi
        printf &amp;quot;lanIp=%-15s &amp;quot; $lanIps
        printf &amp;quot;gw=%-15s &amp;quot; $gw

        pingGw=&amp;quot;-------&amp;quot;
        if [ &amp;quot;$gw&amp;quot; != &amp;quot;&amp;quot; ]; then
            pingGw=$(ping -W1 -c1 $gw 2&amp;gt;/dev/null | tail -1 | grep -v &amp;quot;0 packets received&amp;quot; | cut -d '=' -f 2 | cut -d '/' -f 2)
            if [ &amp;quot;$pingGw&amp;quot; == &amp;quot;&amp;quot; ]; then
                pingGw=&amp;quot;-------&amp;quot;
            fi
        fi
        printf &amp;quot;pGw=%-7s &amp;quot; $pingGw

        ping8888=$(ping -W1 -c1 8.8.8.8 2&amp;gt;/dev/null | tail -1 | grep -v &amp;quot;0 packets received&amp;quot; | cut -d '=' -f 2 | cut -d '/' -f 2)
        if [ &amp;quot;$ping8888&amp;quot; == &amp;quot;&amp;quot; ]; then
            ping8888=&amp;quot;-------&amp;quot;
        fi
        printf &amp;quot;p8=%-7s &amp;quot; $ping8888

        dnsAmzn=$(host -4 -W 1 -t a amazon.com | head -n1 | grep &amp;quot;has address&amp;quot; | awk '{print $4}')
        if [ &amp;quot;$dnsAmzn&amp;quot; == &amp;quot;&amp;quot; ]; then
            dnsAmzn=&amp;quot;-------&amp;quot;
        fi
        printf &amp;quot;dnsAmz=%-15s &amp;quot; $dnsAmzn

        pingAmzn=&amp;quot;-------&amp;quot;
        if [ &amp;quot;$dnsAmzn&amp;quot; != &amp;quot;-------&amp;quot; ]; then
            pingAmzn=$(ping -W1 -c1 $dnsAmzn 2&amp;gt;/dev/null | tail -1 | grep -v &amp;quot;0 packets received&amp;quot; | cut -d '=' -f 2 | cut -d '/' -f 2)
            if [ &amp;quot;$pingAmzn&amp;quot; == &amp;quot;&amp;quot; ]; then
                pingAmzn=&amp;quot;-------&amp;quot;
            fi
        fi
        printf &amp;quot;pAmz=%-7s &amp;quot; $pingAmzn

        wanIp=&amp;quot;-------&amp;quot;
        dnsIfconfigMe=$(host -4 -W 1 -t a ifconfig.me | head -n1 | grep &amp;quot;has address&amp;quot; | awk '{print $4}')
        if [ &amp;quot;$dnsIfconfigMe&amp;quot; != &amp;quot;&amp;quot; ]; then
            wanIp=$(curl -s --max-time 2 --connect-timeout 2 -H &amp;quot;Host: ifconfig.me&amp;quot; $dnsIfconfigMe | head -n 1 | awk '{print $1'})
            if [ &amp;quot;$wanIp&amp;quot; == &amp;quot;&amp;quot; ]; then
                wanIp=&amp;quot;-------&amp;quot;
            fi
        fi
        printf &amp;quot;wanIp=%-15s &amp;quot; $wanIp

        printf &amp;quot;\n&amp;quot;

        sleep 0.7
    done
}
&lt;/pre&gt;

&lt;p&gt;Example output:&lt;/p&gt;
&lt;pre class="code"&gt;
2020-07-13T23:43:59  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.264   p8=53.338  dnsAmz=176.32.98.166   pAmz=127.532 wanIp=1.2.3.4
2020-07-13T23:44:01  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.190   p8=47.107  dnsAmz=176.32.103.205  pAmz=111.309 wanIp=1.2.3.4
2020-07-13T23:44:02  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.290   p8=------- dnsAmz=176.32.103.205  pAmz=118.834 wanIp=1.2.3.4
2020-07-13T23:44:04  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.328   p8=143.387 dnsAmz=176.32.103.205  pAmz=135.333 wanIp=1.2.3.4
2020-07-13T23:44:06  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.313   p8=17.944  dnsAmz=176.32.103.205  pAmz=105.977 wanIp=1.2.3.4
2020-07-13T23:44:07  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.223   p8=22.505  dnsAmz=176.32.103.205  pAmz=97.623  wanIp=1.2.3.4
2020-07-13T23:44:08  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.250   p8=23.917  dnsAmz=176.32.103.205  pAmz=98.403  wanIp=1.2.3.4
2020-07-13T23:44:09  lanIp=192.168.1.6/24 gw=192.168.1.1    pGw=0.220   p8=41.262  dnsAmz=176.32.103.205  pAmz=100.828 wanIp=1.2.3.4
&lt;/pre&gt;</description><author>Allan's Blog</author><pubDate>Tue, 14 Jul 2020 02:46:39 GMT</pubDate><guid isPermaLink="true">https://allanrbo.blogspot.com/2020/07/a-super-ping-command-to-run-while.html</guid></item><item><title>How to: add Twitter and Instagram Embeds on an Eleventy website using Sanity</title><link>https://phacks.dev/articles/how-to-add-twitter-and-instagram-embeds-on-an-eleventy-website-using-sanity</link><description>At Orbit, we recently rebuilt our website from the ground up using a Jamstack approach and more specifically using Eleventy as our Static Site Generator and Sanity as our CMS.</description><author>Nicolas Goutay</author><pubDate>Mon, 13 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://phacks.dev/articles/how-to-add-twitter-and-instagram-embeds-on-an-eleventy-website-using-sanity</guid></item><item><title>Building Android: BTS</title><link>https://wantguns.dev/blog/build-android/</link><description>&lt;p&gt;So you've successfully compiled AOSP. But you are still not entertained
and rather inquisitive about how things worked under the hood after you
hit &lt;code&gt;make bacon&lt;/code&gt; or &lt;code&gt;brunch&lt;/code&gt; on your Lineage tree.&lt;/p&gt;
&lt;p&gt;I am too and so I decided to take a look under the myriad that AOSP is.
In this blog, I would share what I have learned so far, also being
relevent to my GSoC obligations and therefore prepping hand by hand for a native aarch64 build.&lt;/p&gt;
&lt;p&gt;So just setup your build environment and follow along.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="toolchains"&gt;Toolchains&lt;/h2&gt;
&lt;p&gt;Android has decided to phase out of using a GCC toolchain to the
LLVM/Clang based solution since Android 8.0. People usually see a
performance boost after the switch.&lt;/p&gt;
&lt;p&gt;The actual Toolchain AOSP uses is already prebuilt and bundled with the
entire AOSP source. But since AOSP only supports a Linux/Darwin x86 host
enviroment for building, we will have to build our own toolchain
supporting aarch64 hosts.&lt;/p&gt;
&lt;p&gt;In order to do that we shall dive deep first and study &lt;a href="https://android.googlesource.com/toolchain/llvm_android/" rel="external"&gt;llvm_android&lt;/a&gt;,
the source of the prebuilt toolchain.&lt;/p&gt;
&lt;h3 id="llvm-android"&gt;LLVM_android&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;I should mention that we could have used vanilla LLVM, but Google pushes some &lt;a href="https://android.googlesource.com/toolchain/llvm_android/+/refs/heads/master/patches/" rel="external"&gt;patches&lt;/a&gt; along with its LLVM fork which is required by AOSP. So it is better if we stick to the way Google handles it. These patches are applied to the toolchain in between its compilation.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After setting that toolchain up and doing a build test on x86, we
realise that LLVM_android ships with prebuilt GCC and Clang toolchains.
It uses Clang as its compiler and GCC's libs and binaries to build the
stage 1 of the LLVM_android compiler.&lt;/p&gt;
&lt;p&gt;LLVM_android also ships with the Bionic (Android's libc) sources. Though we notice while building the toolchain that only Bionic's headers are copied to the building toolchain. Bionic is not compiled at this stage.&lt;/p&gt;
&lt;p&gt;After building &lt;code&gt;swig&lt;/code&gt; and &lt;code&gt;libedit&lt;/code&gt; we finally reach the start of stage
2.
As expected the script now calls CMake again but with debug flags
referring to the newly built Clang/++ and its libraries. It also calls
the prebuilt libraries like it did earlier.&lt;/p&gt;
&lt;p&gt;Briefly put these are all the building parts, in order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For Linux:
&lt;ul&gt;
&lt;li&gt;Stage 1:  builds the crude Clang&lt;/li&gt;
&lt;li&gt;swig:     required for Stage 2&lt;/li&gt;
&lt;li&gt;libedit:  required for Stage 2&lt;/li&gt;
&lt;li&gt;Stage 2:  builds the final Clang&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;For Android { arm, aarch64, x86, i386 }:
&lt;ul&gt;
&lt;li&gt;sysroots&lt;/li&gt;
&lt;li&gt;compiler-rt&lt;/li&gt;
&lt;li&gt;compiler-rt-i386-host (only for linux)&lt;/li&gt;
&lt;li&gt;libomp&lt;/li&gt;
&lt;li&gt;lldb-server&lt;/li&gt;
&lt;li&gt;asan-mapfile&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will have to patch &lt;a href="https://android.googlesource.com/toolchain/llvm_android/+/refs/heads/master/paths.py" rel="external"&gt;paths.py&lt;/a&gt; and replace the paths where the script calls its tools with the host's to compensate for the aarch64 host.
Additionally, we should only &lt;code&gt;sync&lt;/code&gt; the repositories which are necessary by editing the &lt;code&gt;.repo/manifest.xml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But enough of that, let's move on to building Android now.&lt;/p&gt;
&lt;h2 id="building-android-using-the-toolchain-we-just-made"&gt;Building Android using the toolchain we just made&lt;/h2&gt;
&lt;p&gt;If not done already, sync Lineage's Android Manifest.
Put the newly made toolchain at &lt;code&gt;prebuilts/clang/host/linux-x86/&lt;/code&gt;
and change the Clang version to that of the one we just built at
&lt;code&gt;build/soong/cmd/cc/config/global.go&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now setup the environment and brunch your device.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;source&lt;/span&gt;&lt;span class="z-string"&gt; build/envsetup.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;brunch&lt;/span&gt;&lt;span class="z-string"&gt; _TARGET_NAME_&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You'll notice that Building would give errors due to warnings.
We come to yet another realisation that AOSP uses an older version of Clang (9.0.3 currently).
The toolchain we just built is at bleeding edge, and is throwing errors at the old code as it
finds vulnerabilities in it.
We should recall that the lineage tree we synced is stable and so all
the warnings generated by the newer compiler can actually be avoided. We
could approach this in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Disable certain flags which throws those errors.&lt;/li&gt;
&lt;li&gt;compile the current supported version of clang and use it instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Approach 1 would be time intensive and not scalable in any way, since we
don't control the main tree and upstream could make our forks fatal.
So we should follow the second approach.&lt;/p&gt;
&lt;p&gt;And so once we get a hold of the correct toolchain version, the builds
should not be throwing errors.&lt;/p&gt;
&lt;p&gt;Let me explain the build process now. Once you &lt;code&gt;make bacon&lt;/code&gt; or &lt;code&gt;brunch&lt;/code&gt;,
the soong build system is called and is compiled.
The very first program built is &lt;code&gt;soong_ui&lt;/code&gt; which is the build
system used to iniate the build process. The target you lunch will be
passed to the newly built &lt;code&gt;soong_ui&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Go is used to build all of &lt;code&gt;soong&lt;/code&gt;, and AOSP ships its prebuilt version of Go.
We will have to change the location of GOROOT to use host's tools.
GOROOT is called at &lt;code&gt;build/blueprint/microfactory/microfactory.bash&lt;/code&gt;
so we will edit it there.&lt;/p&gt;
&lt;p&gt;Eventually it parses all the blueprint files (.bp extensions), and kati parses all
the makefiles. Once the &lt;code&gt;build.ninja&lt;/code&gt; file is created, the Android build
is ready to start.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;build.ninja&lt;/code&gt; is called and it starts building certain intermediates
first which would be used later in assistance to build Android. One of
these intermediates which is of concern to us is &lt;strong&gt;&lt;code&gt;Bionic&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="compiling-bionic"&gt;Compiling Bionic&lt;/h3&gt;
&lt;p&gt;Like we discussed earlier, Bionic's header files are already included in
the llvm_android toolchain. But the &lt;code&gt;libc&lt;/code&gt; sources are not compiled then.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;libc&lt;/code&gt; and friends are actually compiled within the build as
intermediates and then copied to some different folder under &lt;code&gt;/out&lt;/code&gt;, from where it
gets called later in the build process.&lt;/p&gt;
&lt;p&gt;So, as I believe, once we have the toolchain ready, we should be good to
go for building Android using aarch64 host. I will be setting up an
ARM based VPS for the same, since I only have 32 gig of storage on my
phone.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We need to build llvm_android on aarch64 host, by patching the build scripts provided by Google.
Also we need to build the &lt;a href="https://android.googlesource.com/platform/prebuilts/clang/host/linux-x86/+/master/README.md#llvm-users" rel="external"&gt;latest supported version&lt;/a&gt; of Clang/LLVM.
Once that is done, we will have to edit the paths of various tools called in the AOSP tree with our host's. And then finally, test a build.&lt;/p&gt;
&lt;p&gt;Achieving this should mark my task of building Android on aarch64 Host,
which is incomplete in the sense that I don't have a separatable
toolchain. But once we are through with this process, Separating Bionic
and implementing crossdev for the toolchain would be easier.&lt;/p&gt;</description><author>Gunwant Jain - @wantguns</author><pubDate>Mon, 13 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://wantguns.dev/blog/build-android/</guid></item><item><title>Real-time data streaming using FastAPI and WebSockets</title><link>https://stribny.name/posts/real-time-data-streaming-using-fastapi-and-websockets/</link><author>Posts by Petr Stribny</author><pubDate>Sun, 12 Jul 2020 23:17:43 GMT</pubDate><guid isPermaLink="true">https://stribny.name/posts/real-time-data-streaming-using-fastapi-and-websockets/</guid></item><item><title>The meddling middlemen of academia</title><link>https://bastian.rieck.me/blog/2020/middlemen/</link><description>&lt;p&gt;One of the strangest phenomena in academia is the reliance on publishing
companies. In this article, I want to outline some of the issues that
arise when working with publishers. I shall also endeavour to provide
some solutions to improve this collaboration.&lt;/p&gt;
&lt;p&gt;Before we start, a brief &lt;strong&gt;disclaimer&lt;/strong&gt;: this article will use an
amalgamation of different incidents that involved either myself, my
colleagues, or my friends.  Names (of the publishing companies)
have been withheld because I do not think it fair to use my &amp;lsquo;soapbox&amp;rsquo;
without giving the &lt;em&gt;other&lt;/em&gt; side a chance to respond. Moreover,
everything I write here pertains to publishing your research in
a journal. Conference publishing&amp;mdash;at least in machine learning&amp;mdash;is
a joy&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Plus, there &lt;em&gt;are&lt;/em&gt; good examples of journals for machine
learning papers, foremost of them the &lt;a href="http://www.jmlr.org"&gt;Journal of Machine Learning
Research&lt;/a&gt;. The &amp;lsquo;adversaries&amp;rsquo; in this article are
rather the &amp;lsquo;big&amp;rsquo; publishing companies and their practices. With that out
of the way, let us take a look at the state of the art!&lt;/p&gt;
&lt;h1 id="the-journal-publishing-process-in-academia"&gt;The journal publishing process in academia&lt;/h1&gt;
&lt;p&gt;If you are new to science, at some point, you will probably have to deal
with an established publishing company to get your article published.
The deal usually works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You look for a journal you want to publish in and submit your article
to the journal. This already often involves jumping through some
hoops. Without knowing the eventual fate of your article, you often
already have to abide by certain arbitrary formatting guidelines or
completely &amp;lsquo;butcher&amp;rsquo; your article for the submission&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt; by shifting
content around. However, this can be all accepted and endured because
of course, you want something from &lt;em&gt;them&lt;/em&gt;, i.e. a published,
citable publication!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The journal then receives your submission&amp;mdash;often through a web
interface that was developed with all the UX/UI knowledge of the
1980s&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; and has &lt;em&gt;never&lt;/em&gt; been updated since&amp;mdash;and this is where it gets
slightly &lt;em&gt;murky&lt;/em&gt;. Another person&amp;mdash;typically the editor of the
journal&amp;mdash;now decides whether to accept the paper for reviewing, or
whether to provide you with a desk reject. A desk reject usually cannot
be appealed. It just shows you the door and leaves you to try again
with another journal (more murkiness here). For early-career
researchers like Ph.D. students submitting their first paper,
this can be highly discouraging. I see the reason for reducing the
workload on reviewers, of course, but I also heard of academic feuds
that were carried out on the backs of Ph.D. students and their
publications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Assuming your paper &amp;lsquo;survived&amp;rsquo; the desk reject, it will now be sent
to reviewers or referees. Their job is to review your paper
thoroughly, provide feedback, and in general give this whole business
a formal veneer. Setting aside problems in the reviewing
process&amp;mdash;which I discussed &lt;a href="https://bastian.rieck.me/blog/2019/reviewing/"&gt;in another blog post&lt;/a&gt;&amp;mdash;this again opens up a portal into
a strange dimension: working as a reviewer for a journal is usually
a job that is provided for free (same goes for editorial
duties). Notice that this is &lt;em&gt;despite&lt;/em&gt; the fact that those journals
are charging money to readers and universities. ETH Zurich, my
current employer, describes their experiences of the &lt;a href="https://www.library.ethz.ch/en/Services/Using-ordering-resources/National-negotiations-with-publishers-Read-publish-reorganised"&gt;negotiations
with
publishers&lt;/a&gt;
and mentions an expenditure of 6.4 million EUR (roughly 7.25
million USD) per year for being allowed to access journal articles.
That is a lot of money.&lt;/p&gt;
&lt;p&gt;Setting aside the actual numbers here, let me just point out how
strange it is that companies are relying on &lt;em&gt;unpaid labour&lt;/em&gt;, and this
reliance is &lt;em&gt;crucial&lt;/em&gt; to their business model. They often do not
employ people that are qualified to judge the content that they want
to publish! But of course, reviewers and editors get the benefit of
&lt;em&gt;exposure&lt;/em&gt;&amp;mdash;that wonderful currency that is supposed to help your
career along! Even stranger: journals often charge hefty sums for
accessing your own research articles. To me, it is super weird that
research that is often &lt;em&gt;funded&lt;/em&gt; by the taxpayer cannot be &lt;em&gt;accessed&lt;/em&gt;
by the taxpayer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supposing your article got sufficiently good reviews to be published,
the next stage of the process starts. This is where the &lt;em&gt;meddling&lt;/em&gt;
begins in earnest. After a little back and forth, you article will be
changed according to some arbitrary rules: the last period of every
sentence in an image caption will be removed, footnotes will be put
into the text&amp;mdash;because for some reason, footnotes are permitted in
virtually every template and publishing medium, but deemed somewhat
uncouth by certain publishers&amp;mdash;and you might have to redo certain
parts of your paper because of subtle font changes or what have you.&lt;/p&gt;
&lt;p&gt;Again, lest you think of me as a particularly cranky person prone to
grumbling and finding faults, you are getting the wrong idea here.
I do not object to these changes, but I &lt;em&gt;do&lt;/em&gt; object to the fact that
these meddlesome changes often decrease the quality of your paper.
Here are some irksome changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Footnotes will be inserted willy-nilly into the text, regardless of
whether they make sense or not. That might break the flow of your
paper, but that is &lt;em&gt;your&lt;/em&gt; problem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some &amp;lsquo;publisher house rules&amp;rsquo; conflict with proper nomenclature in
a field. For example, the journal might have the &amp;lsquo;rule&amp;rsquo; that all
fields in a table have to be capitalised. If this clashes with
nomenclature in your field, it is&amp;mdash;you guessed it&amp;mdash;&lt;em&gt;your&lt;/em&gt; problem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your equations will typically be typeset yet
another time for you&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;, which might introduce subtle changes: symbols
will change and you have to be go through your own paper once again
line-by-line to see whether anything untoward happened. Again, I am
primarily objecting to the substandard quality of this meddling:
the work that you put into writing your equations is completely
ignored, and now you have to chase&amp;mdash;often very subtle&amp;mdash;changes in
your own text. For mathematical typesetting, precision is crucial,
and it is unbecoming when people who do not &lt;em&gt;care&lt;/em&gt; about this
precision create more work for you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As a last example, your figures might be meddled with: you might be
forced to convert them into obsolete file formats (because
apparently, EPS is still the best format available), or, more
appallingly, vector graphics might be converted to raster
images (judging from the experiences of my friends and myself,
this is unfortunately relatively common!). This might sound like a tiny
problem again, but it decreases readability and accessibility for
some readers, and, more to the point of this post, it is somewhat
unnecessary meddling.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let me re-iterate my main point: I do not object to changing my
paper, I merely object to meddlesome changes that are just generating
useless work. For example, there is no need whatsoever to typeset
your equations again&amp;mdash;this is quite literally the definition of
negative work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you survived this ordeal intact, you now must &lt;em&gt;pay&lt;/em&gt;. To be fair,
not all journals charge you for normal articles, but &lt;em&gt;most&lt;/em&gt; of them
charge you for open access publishing. In other words: if I want my
research, which is generously funded&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="#fn:5"&gt;5&lt;/a&gt;&lt;/sup&gt; by the Swiss taxpayers, to
be available to those selfsame taxpayers, I have to pay. The amounts
vary a little bit, of course, but we are talking upwards of a few
hundred USD at least. Luckily, this is &lt;em&gt;not&lt;/em&gt; a problem for my
research group; my postdoctoral adviser, &lt;a href="https://bsse.ethz.ch/mlcb/karsten.html"&gt;Prof. Karsten
Borgwardt&lt;/a&gt; ensures that
sufficient funds for open access publications are available.&lt;/p&gt;
&lt;p&gt;Interestingly, sometimes the cost is fielded by a conference; this
happens when the conference has a contract that ensures that its
publications will be available as special issue of some journal.
This might seem nice because it &lt;em&gt;shifts&lt;/em&gt; the costs away from authors,
but it is also somewhat non-transparent; conference costs being high
already, I find it strange that some of the money goes into the
pockets of another party.&lt;/p&gt;
&lt;p&gt;After all this negativity, it is time for a &lt;em&gt;positive example&lt;/em&gt;:
NeurIPS, one of the flagship machine learning conferences, is
partnered with a publisher and makes &lt;em&gt;all&lt;/em&gt; papers available for free
online. I &lt;em&gt;gladly&lt;/em&gt; pay the conference fee for this!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="a-better-model"&gt;A better model&lt;/h1&gt;
&lt;p&gt;How can this process be improved? I have a few suggestions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transparency&lt;/strong&gt;: publishers should make it clear &lt;em&gt;where&lt;/em&gt; the funds are
going. Are we increasing shareholder value by working for free? How
are profits split and used?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Giving back&lt;/strong&gt;: it is generally understood that everyone needs to eat
and no one should have to work for free. Why is then that this
completely different in publishing? Almost all the profits are
essentially generated because editors and reviewers work for free.
I know that being remunerated for your reviewing work might raise
some questions about impartiality etc., so I think &lt;em&gt;paying&lt;/em&gt; people to
write reviews might be somewhat problematic.&lt;/p&gt;
&lt;p&gt;However, closely related to my point about transparency, publishers
could be more upfront about how they user their funds and &lt;em&gt;give back&lt;/em&gt;
to the community. For example, publishers could sponsor students so
that they can visit a conference for free, or publishers could
sponsor the conferences themselves.&lt;/p&gt;
&lt;p&gt;If you, as a publisher, engage the community and give back a little,
the community will be all the more happy to work with you. We need
you, but you also need us. Without the scientists, you cannot be
a scientific publisher.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commitment to excellence&lt;/strong&gt;: publishers should commit to the highest
quality and the highest standards. Employ people that are capable of
working &lt;em&gt;with&lt;/em&gt; the scientists, not &lt;em&gt;for&lt;/em&gt; the scientists. Train your
employees to be experts in typography, typesetting, and pair them
with domain experts so that they do not create more work for the
authors by inadvertently destroying equations, figures, and so on.&lt;/p&gt;
&lt;p&gt;This goal is not necessarily orthogonal to maximising your profits,
by the way: if you lower your standards, your reputation as
a publisher will suffer, meaning that scientists in the long
run (!) might not be willing to publish with you any more. If
you commit to excellence, by contrast, we will flock to you.&lt;/p&gt;
&lt;p&gt;I know that working with a publisher that &lt;em&gt;cares&lt;/em&gt; about the end
product as much as I do is a heavenly match! So we should endeavour
to make such experiences the norm, not the exception.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If publishers work on these three suggestions, they will start to really
provide added value to the publishing process by working &lt;em&gt;with&lt;/em&gt; the
authors in order to find the best way of showcasing good research.&lt;/p&gt;
&lt;p&gt;Note that despite my misgivings about some things in the publishing
process, I am confident and optimistic that we can build a better way
together. The machine learning community, for example, already created
their own journal to provide a high-quality, low-friction publishing
experience.  Let us strive to improve this for other domains as well.&lt;/p&gt;
&lt;p&gt;Until next time, good luck with your proofs!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;My biggest problem here is merely that some of the larger conferences
offer a template with pre-defined LaTeX commands to create a list of
authors, their affiliations, and their contributions, whereas for
other conferences, you have to typeset them yourself. This is quite
literally the &lt;em&gt;only&lt;/em&gt; issue I have with the logistics of the conference
publishing process, and it pales in comparison to anything else in
this article.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Some journals, for example, think that reviewers of your article
get confused when you mix figures and text. You know, in the way that
&lt;em&gt;every other paper&lt;/em&gt; does. So, they force you to reformat the paper
such that all figures and tables are situated in an appendix.
Reviewing such a paper is appalling from a reviewer&amp;rsquo;s perspective.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;This might seem like a low blow, but I have trouble reading some
text in some of the interface because my normal browser-based zoom
function does not work. Clearly, accessibility is not a top priority
here, and I am slightly underwhelmed by my technical support
experiences here&amp;mdash;but this should be a topic for another post.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;Never mind the fact that they could just as well be &lt;em&gt;copied&lt;/em&gt; from
your original source file. If you are using LaTeX, this would actually
be a breeze.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;I am sincerely grateful for the way academia is treated in
Switzerland.&amp;#160;&lt;a class="footnote-backref" href="#fnref:5"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Sun, 12 Jul 2020 13:00:00 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/middlemen/</guid></item><item><title>Type-Safe Hypermedia Controls</title><link>https://daniellittle.dev/type-safe-hypermedia-controls</link><description>Hypermedia Controls in REST provide links and actions with each response pointing to related resources. This concept is a powerful tool that…</description><author>Daniel Little Dev</author><pubDate>Sun, 12 Jul 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://daniellittle.dev/type-safe-hypermedia-controls</guid></item><item><title>Fixing the blower motor in my central air system</title><link>https://porkrind.org/missives/fixing-the-blower-motor-in-my-central-air-system/</link><description>On Wednesday as I was going to bed I noticed it was quite hot in my house. I checked my central air blower unit and there was frost on the coils and the blower wasn&amp;#8217;t moving. It kept trying to start but not being able to start. The 7 segment led was showing &amp;#8220;b5&amp;#8221; which &amp;#8230; &lt;a class="more-link" href="https://porkrind.org/missives/fixing-the-blower-motor-in-my-central-air-system/"&gt;Continue reading &lt;span class="screen-reader-text"&gt;Fixing the blower motor in my central air system&lt;/span&gt;&lt;/a&gt;</description><author>Missives</author><pubDate>Sun, 12 Jul 2020 09:59:04 GMT</pubDate><guid isPermaLink="true">https://porkrind.org/missives/fixing-the-blower-motor-in-my-central-air-system/</guid></item><item><title>Believing in Blue - An Introduction</title><link>http://spirals.blog/articles/blue-introduction/</link><description>&lt;div class="toc"&gt;
&lt;p&gt;Blue represents the “fourth stage” of human existence. If you’re new to Spiral, please first read:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/what-is-spiral-dynamics/"&gt;What is Spiral Dynamics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/beige-introduction/"&gt;Beginning in Beige&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/purple-introduction/"&gt;Progressing to Purple&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/red-introduction/"&gt;Rising to Red&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These articles will provide the necessary context for some of the concepts here.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Dear Sir/Madam. Spirals.blog would thank you for reading this chapter. We hope you find this text informative and instructional. Once you are done, if you could please fill out the form below for further updates on the matter of perspective. It’s titled “Spiral Sundays”. Please queue to the left. Thank you.&lt;/p&gt;
&lt;p&gt;Yes, next in line, please!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;And lo! The Truth has been told! The word of &amp;lt;insert a god/“ism”/“ideology”&amp;gt; has spoken, and all who listen SHALL BE SAVED! Those who do NOT heed the Truth shall be condemned. They will be imprisoned and suffer horrendous guilt for all eternity. Ye be warned.&lt;/p&gt;
&lt;p&gt;And oh! Yes! How our Truth is &lt;em&gt;&lt;strong&gt;true&lt;/strong&gt;&lt;/em&gt;! We are the mighty, the chosen, and we have the ONE TRUE WAY to live life. All other beliefs are FALSE BELIEFS! They can go fuc–&lt;/p&gt;
&lt;p&gt;Excuse me. We shouldn’t be so crude. We’ll have none of that unhealthy Red/Blue here now, will we? Remember how our &lt;a href="https://spirals.blog/articles/red-introduction"&gt;last article turned out?&lt;/a&gt; We will, from now on, make a solemn promise to you, reader, that we will remain proper and courteous. We shan’t digress into any more obscene vanity or profanity. Let us start this article again. The polite way. The correct way.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;s&gt;The 10 commandments of Blue&lt;/s&gt;&lt;/h2&gt;
&lt;h2&gt;Table of Contents&lt;/h2&gt;
&lt;p&gt;The (in)formal Definition of Blue&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Guilt&lt;/li&gt;
&lt;li&gt;Fairness&lt;/li&gt;
&lt;li&gt;Justice and the Bigger Picture&lt;/li&gt;
&lt;li&gt;Order &amp;amp; Hierarchy&lt;/li&gt;
&lt;li&gt;Time&lt;/li&gt;
&lt;li&gt;Sacrifice now for the future&lt;/li&gt;
&lt;li&gt;Truth &amp;amp; Absolutism&lt;/li&gt;
&lt;li&gt;Religion&lt;/li&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;Beyond Blue&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The (in)formal Definition of Blue&lt;/h2&gt;
&lt;p&gt;Blue is the fourth level of human existentialism, as defined by the theory of Spiral Dynamics. To understand Blue, one must let go of everything else they know and embrace its elegant, organized, fair nature. It’s what makes our world “tick”.&lt;/p&gt;
&lt;p&gt;What is Blue? We’re delighted you asked. We know that colors are not “one thing” or behavior, or a single opinion or idea. They’re a living, breathing collection of all of these things put together. They’re a way of “solving life”.&lt;/p&gt;
&lt;p&gt;Blue is essential as it’s the perfect tool to deal with the cacophony of chaos that emerges from Red. Red seeks to express itself, do whatever it can to promote itself, and doesn’t think about the future AT ALL. Hmph. Blue steps in to clean up the mess, make everyone take a little more responsibility, and think about the bigger picture.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Unhappy Steve" src="http://spirals.blog/articles/blue-introduction/unhappy.png" /&gt;&lt;/p&gt;
&lt;p&gt;A sense of obedience drives much of Blue. It is obeying the rules, order, and harmony that is created by those who have the truth. This could be our government, a religion, an “ism”, a company’s policies, and so on. In many ways, it’s the direct opposite of Red, in that it seeks to serve rather than express. &lt;a href="https://spirals.blog/articles/i-vs-we"&gt;The pendulum swings yet again.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Blue is a stalwart, dependable, color, and is where most of the world is operating from today. One only needs to step into an airport, courthouse, police station, or accounting firm to observe Blue’s astute nature. Everyone has a role, a place in society, meaning and purpose, and a narrative by which to live. Blue gives us predictability and schedules and time. Blue is whom you call when you’re in trouble. Blue is who saves you when you’re sick. Blue is the protector against the evil and unjust in the world.&lt;/p&gt;
&lt;p&gt;Blue is your friend.&lt;/p&gt;
&lt;h2&gt;1. Guilt&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;When the person lives successfully this way [Red] and in living successfully begins to create problems for himself. Namely in living successfully [in Red], the person begins to get other people angry at him for his entrapment, for his using the others to gain one’s own satisfaction, for his ensnaring and trapping others. Then, this person has created a new problem for himself or herself, and if he or she is going to stay alive here, she has got to begin to shut down a little bit on this egocentric behavior that is shown, and &lt;strong&gt;begin to think a little bit about other human beings&lt;/strong&gt;.&lt;br /&gt;
– Clare Graves - &lt;a href="https://youtu.be/tt3Uk1f3y_U?t=1647"&gt;In Conversation with Clare W. Graves. (Youtube)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Guilt. A powerful, &lt;em&gt;necessary&lt;/em&gt;, and useful tool in Blue’s arsenal of understanding the world and creating order.&lt;/p&gt;
&lt;p&gt;When Red gets too Red, there’s a problem (like any color really), and if we continue living this way, we create disharmony for ourselves. &lt;strong&gt;To stay in Purple, we must think about others.&lt;/strong&gt; There are only so many times you can steal your housemates’ toothpaste or butter before they start to notice. If you do something frequently, or to a severe degree, people &lt;em&gt;will&lt;/em&gt; get angry, and they &lt;em&gt;will&lt;/em&gt; confront you. You know you’re in the “wrong”. You’re behaving in a way that’s hurting others. That feeling is guilt.&lt;/p&gt;
&lt;p&gt;Guilt, in some beautiful fashion, instills enough fear and negativity towards something BEFORE we’ve even done it. That’s its power. It prevents you from taking action on something you know will affect others, critical for controlling that unhealthy Red. It is NOT ok for you to kill someone so you can claim their partner for your own. That’s what it used to be, but we’re a little further along than that now. You &lt;strong&gt;should&lt;/strong&gt; feel guilty if you steal, taking from someone’s hard labor to add to your “self”. Jibing an unjustly nasty remark to someone and feeling bad after is a &lt;strong&gt;useful emotion&lt;/strong&gt; to ensure you don’t behave that way again. Going to jail for a life sentence is an appropriate societal response to murder. Embrace guilt. It saves you from hurting others before you do.&lt;/p&gt;
&lt;p&gt;Guilt, of course (like anything), can be taken too far. What does this look like? Limiting of &lt;em&gt;healthy&lt;/em&gt; self-expression, telling young children that “God will blind you if you masturbate” (yes, this actually happens), overly strict parents making their children feel bad for not coming home at the time they want, and so on. “Bad guilt” is all around us too.&lt;/p&gt;
&lt;p&gt;How do we tell the difference between “good guilt” and “bad guilt? Perhaps we might ask, “Is the intention to protect and help, or is it coming from inflexible rules and insecurities?” We can use guilt where necessary to prevent things that should not happen, but not too much…&lt;/p&gt;
&lt;p&gt;In later articles, we’ll discuss how we can raise or lower the “Guilt Line” to accommodate varying types of expressions from other “I” colors (Red, Orange, etc.).&lt;/p&gt;
&lt;h2&gt;2. Fairness&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Fairness" src="http://spirals.blog/articles/blue-introduction/fairness.jpg" /&gt;
&lt;em&gt;Photo by Tom Parsons @tomzzlee&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With Red’s now “waking up” to this feeling of guilt, some begin to wonder if there is a better way. Can we possibly reconcile, or “integrate” both living in Purple AND expressing in Red? For the Red’s now “entering Blue”, the concept of fairness begins to emerge out of the guilt.&lt;/p&gt;
&lt;p&gt;To maintain the balance, these new ideals propagate out to the rest of the Purple group. At an individual level, one realizes their actions and, stemming from the guilt associated with their past Red activities, resolve to treat everyone fairly.&lt;/p&gt;
&lt;p&gt;Fairness is “valued” as a way of protecting people against unhealthy Red. It stands in defense for those who might not necessarily be able to stand up for themselves. They are sheltered by the value Blue shares in &lt;em&gt;how&lt;/em&gt; we should lead a &lt;strong&gt;good&lt;/strong&gt; life. Thanks, Blue.&lt;/p&gt;
&lt;p&gt;This is a &lt;strong&gt;massive&lt;/strong&gt; part of Blue’s motivation; the protection of the innocent. Fairness for all that “accept blue”. But what about those that don’t “accept” this way of life? The obstinate, the “closed Reds”, the sinners, and barbarians, and criminals, and hooligans? What about them?&lt;/p&gt;
&lt;h2&gt;3. Justice and the Bigger Picture&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Justice" src="http://spirals.blog/articles/blue-introduction/justice.jpg" /&gt;
&lt;em&gt;Photo by Tingey Injury Law Firm @tingeyinjurylawfirm&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There are some that don’t see it as the “Blue” way. The Reds and Purples? They’ve got their own way of seeing things, and it certainly doesn’t match Blue 100% of the time. That’s for sure.&lt;/p&gt;
&lt;p&gt;So what are we to do about this? We started convincing people and showing them the pain that was being caused by the Reds. We started groups, holding town-halls, and market place Khutbahs (Islamic sermons). We worked together to come up with a system of rules and ways of living that we ALL had to abide by, lest there be a punishment (guilt).&lt;/p&gt;
&lt;p&gt;And so legal systems around the world were born and often tied very intensely to a religion. A set of rules, ideas, stories, and values that helped us all to live healthier lives, without violence or hurting each other. In theory.&lt;/p&gt;
&lt;p&gt;Blue that has moved through Red (can step into Red and enforce it) spread across the globe. It was far more capable than it’s &lt;em&gt;pure&lt;/em&gt; Red predecessors, and it conquered everything. If one has studied history to any degree, we may draw from the countless of Blue applying it’s justice and truth wherever it goes. Blue’s trained armies are no match courageous Purple/Red warriors. Movies like Braveheart depict this perfectly, with the British playing a significant aggressor in “Blue”-ifying the world at the time. The Roman Empire is another example.&lt;/p&gt;
&lt;p&gt;And so, justice served. It served us all as we served it. God’s justice, the judge’s justice, the justice of the law, the justice found in the Truth. This is the biggest motivator behind how most of society’s across the world operate today. We go to work, we pay our taxes, we follow the law, and we listen to the experts who have studied things we haven’t. We speak the same language. More importantly, we agree (mostly) on &lt;em&gt;how&lt;/em&gt; we should live, and are comfortable letting society determine these rules.&lt;/p&gt;
&lt;p&gt;Something magical happens in Blue. As we become more aware of how our actions affect others, we grow to appreciate the “collective” idea that binds us together. This could be the law, a god, or a companies mission. &lt;strong&gt;It is more significant than any one of us&lt;/strong&gt;, and when everyone follows this, we have peace. Unless there are other versions of the Truth.&lt;/p&gt;
&lt;h2&gt;4. Order &amp;amp; Hierarchy&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Hierarchy" src="http://spirals.blog/articles/blue-introduction/hierarchy.jpg" /&gt;
&lt;em&gt;Photo by Jeffrey F Lin @jeffreyflin&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As you can imagine, things start to get pretty complicated once we start leaving Red. There are laws to right, borders to protect, fields to plow, institutions to uphold, and the King to serve. In Purple, there’s next to no hierarchy (asides from the odd Shaman or two). In Red, we see a little more of this but driven by a desire to dominate. Red respects the biggest Red.&lt;/p&gt;
&lt;p&gt;In Blue, this changes &lt;em&gt;&lt;strong&gt;dramatically&lt;/strong&gt;&lt;/em&gt;. For order to ensue, we must put people in charge to make sure everyone’s doing the right thing and following the rules we’ve agreed to. Very quickly, we develop a “pyramid” like structure, with someone at the top who “calls the shots”, and trickles down through middle managers, sergeants, priests, and eventually finds it’s way down to the workers.&lt;/p&gt;
&lt;p&gt;If someone “above” you in this structure asks you to do something, it’s expected (per Blue) that you do it without question. It’s assumed that someone higher than you has access to more of the bigger picture, has served longer than you have, and is closer to the Truth. Thus, we treat our “superiors” with respect, obedience, and give them the authority that they “deserve”.&lt;/p&gt;
&lt;p&gt;This structure (the worst nightmare for a Red) is what gives Blue the discipline, security, and predictability it relies on upon to carry out it’s behemoth missions. Organizing society is no small task.&lt;/p&gt;
&lt;p&gt;Should you decide NOT to follow this order, you are promptly spoken to, and if it continues, removed. If there is a soldier in-sighting a rebellion against the General, this could mean the difference between winning the war or falling succumb to the enemy. A rogue employee who vehemently disagrees with the CEO can be a danger to the companies vision and must be dealt with accordingly.&lt;/p&gt;
&lt;h3&gt;A side order of stagnation&lt;/h3&gt;
&lt;p&gt;Interesting, Blue’s rigid structure is also it’s downfall. As we will see in Orange (and how it transcends these limitations), too much hierarchy, combined with inflexibility, creates problems for Blue. Over-reliance on these hierarchies and processes can stagnate a country/organization and grind everything to a snail pace. In some cases, it can create a complete deadlock.&lt;/p&gt;
&lt;p&gt;“Why don’t we try this new way?”&lt;/p&gt;
&lt;p&gt;“Because THIS is the way we’ve always done it. Get back to work”&lt;/p&gt;
&lt;h2&gt;5. Time&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Time" src="http://spirals.blog/articles/blue-introduction/time.jpg" /&gt;
&lt;em&gt;Photo by Jeffrey F Lin @jeffreyflin&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Have you ever noticed, in particularly Purple/Red interactions (chilling on the couch, picnicking in the park with friends, going for a hike, etc.) that you &lt;em&gt;entirely&lt;/em&gt; lose track of time? You look at the clock, and what feels like 10 mins were 4 hours. Purple/Red is brilliant for connecting, relating, and building closer relationships. It’s not so great at showing up to work on time.&lt;/p&gt;
&lt;p&gt;In the perfect Blue world, nobody is late. Those Reds and Purples don’t exactly “own a watch” so to speak. It is in Blue that &lt;em&gt;&lt;strong&gt;time&lt;/strong&gt;&lt;/em&gt; becomes observed, and we are better for it. Isn’t it pleasant when everyone shows up to our compulsory daily meeting on time, well-groomed, considerate, and there to serve?&lt;/p&gt;
&lt;p&gt;Time, like guilt, is one of Blue’s greatest strengths. The ability to observe things over a period, recognize patterns, and respond accordingly. Blues gain foresight from their unique ability to perceive time. It invents devices to track it, systems to follow it (astronomy, seasons, etc.), and language to communicate it. It becomes the lead actor on Blue’s societal stage.&lt;/p&gt;
&lt;p&gt;Without time, how could we organize ourselves into large groups, coordinate projects, and keep the world running? We’d have trouble even doing the simplest of activities. To compare, take a trip to a Purple/Red country. The meaning of time is different there.&lt;/p&gt;
&lt;p&gt;“Hey, I thought we had an 11’oclock?” Says the businessman to the contractor.&lt;/p&gt;
&lt;p&gt;“Yeah we do! I said I’d come in the morning, right? It’s only 11:30. I’ll be there soon.”&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;It’s an entirely different way of seeing reality. It can be incredibly frustrating for a Blue when other colors (and even other cognitive functions) perceive time differently.&lt;/p&gt;
&lt;p&gt;In time (pun intended), and as we observe ourselves moving through it, we develop a key realization that forms another critical aspect of Blue.&lt;/p&gt;
&lt;h2&gt;6. Sacrifice self now, for the future benefit&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Sacrifice" src="http://spirals.blog/articles/blue-introduction/sacrifice.jpg" /&gt;
&lt;em&gt;Photo by Jonathan Borba @jonathanborba&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“How about we DON’T eat all our grain, let’s save some” exclaims the Blue to the Purple/Red, “You remember what happened last winter right? We had to eat Annie.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Poor Annie.&lt;/p&gt;
&lt;p&gt;What a fantastic idea. Truly. &lt;em&gt;&lt;strong&gt;The idea of forgoing temporary pleasure for something greater in the future.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Have you ever practiced a musical instrument? Trained in a sport? Studied for a test? Worked hard at a job to retire?&lt;/p&gt;
&lt;p&gt;Our ability in Blue to sacrifice “now” for the “future” (born from our newfound relationship to time) is what set’s the foundation for all other colors in the Spiral. Good luck trying to build a successful “Orange business” if all you’re looking for is immediate short term again. It’s sad that many of our cherished industries have become this.&lt;/p&gt;
&lt;p&gt;By saying to ourselves, “Gee, I’d really love to party tonight guys, but I gotta study for my mid-terms” we pass university. We &lt;strong&gt;get&lt;/strong&gt; the degree to become a doctor. We &lt;strong&gt;save&lt;/strong&gt; those thousands and thousands of lives.  &lt;strong&gt;That’s&lt;/strong&gt; what this idea brings to society.&lt;/p&gt;
&lt;p&gt;How can you expect to save up for your own life and retirement without it? Red spends it all, and Purple has no idea what to do with it! Blue gives you the &lt;em&gt;&lt;strong&gt;discipline&lt;/strong&gt;&lt;/em&gt; to not buy the new motorbike or trip to Hawaii and put it towards a house deposit. It might feel crap at the time, but boy oh boy, do you thank your past self. Again, thanks Blue.&lt;/p&gt;
&lt;p&gt;In many ways, Red is the complete opposite. “Sacrifice the future for NOW dude! 🤘😎”&lt;/p&gt;
&lt;h2&gt;7. Truth &amp;amp; Absolutism&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Truth" src="http://spirals.blog/articles/blue-introduction/truth.jpg" /&gt;
&lt;em&gt;Photo by Bruno van der Kraan @brunovdkraan&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Blue works. That’s a fact.&lt;/p&gt;
&lt;p&gt;Compared to Purple, Red, and Purple/Red, Blue wins in building large societies. In a similar fashion to it’s Armies of Justice, Blue methods of living spread. Because compared to everything before, they work.&lt;/p&gt;
&lt;p&gt;Are they perfect? Blue likes to think so, because what other things have worked this well? They have the one way to live that solves the problems. This is where things can get a little unhealthy. &lt;em&gt;&lt;strong&gt;A Healthy Blue is an Open Blue.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Depending on what you believe, the truth is either relative or it is the Truth. I don’t want to get into a relativity discussion here, so I will just say that Blue &lt;em&gt;tends&lt;/em&gt; to think in absolutes.&lt;/p&gt;
&lt;p&gt;Most people would generally agree (hopefully) that murder is a bad thing. Many would say that’s an objective truth. That good and evil are objective truths. Things that actually exist. That our reality, the world, and all in it operate in such a fashion. A fathomless philosophical conundrum non-the-less.&lt;/p&gt;
&lt;p&gt;What about when this extends to things on a more day to day example? You must do this thing that I believe, or you’re a terrible person. I’m sure we all have something like that in one way or another. Interesting isn’t it?&lt;/p&gt;
&lt;p&gt;We all hold some of these absolutisms. These “truths”. Are they really true? Now is not the time or place to discuss such things.&lt;/p&gt;
&lt;p&gt;But, oh, how they get in conflicts don’t they? Sometimes we even find these conflicts in ourselves—a dichotomy. And we fight over them—a lot.&lt;/p&gt;
&lt;p&gt;This truth is more accurate than this truth. Because it’s the truth.
&lt;strong&gt;Circular arguments are all around us.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Perhaps, to make the world a kinder place, we should start by saying, this is “MY” truth, but you hold your own. Let’s not worry about other people’s versions of the truth. Unless they use it for evil, of course.&lt;/p&gt;
&lt;h2&gt;8. Religion&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Religion" src="http://spirals.blog/articles/blue-introduction/religion.jpg" /&gt;
&lt;em&gt;Photo by Artem Beliaikin @belart84&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;With your permission, I’d like to discuss a touchy subject for many people. I myself have nothing against &lt;em&gt;&lt;strong&gt;HEALTHY EXPRESSION&lt;/strong&gt;&lt;/em&gt; of religion, none what we’re about to cover will ever attempt to say it’s “bad”. Done right, religion is a truly incredible and beautiful force in the world. What we will discuss is how and why Blue often expresses itself through religion, and the forms this can take.&lt;/p&gt;
&lt;p&gt;What is at the core of every major religion? Being kind to others so we can all get along. Blue. Here are some rules for it. Blue. If you don’t follow these rules, there will be consequences. Blue.&lt;/p&gt;
&lt;p&gt;For a Red, hearing a powerful Blue narrate this to us will wake a few of us up. “You mean I can find peace from all this war shit?”&lt;/p&gt;
&lt;p&gt;Yes.&lt;/p&gt;
&lt;p&gt;Sadly, unhealthy expression of religion has killed more people than pretty much anything else humans have done to each other. But that’s not necessarily what religion was designed for…&lt;/p&gt;
&lt;p&gt;The healthiest religious people I know hold their own truth, yes, and are open to others holding theirs. There’s no need to compare, to fight over which is better or more true, or disturb the peace.&lt;/p&gt;
&lt;p&gt;Other Blues, unusually the unhealthy kind, tend to disagree. A lot. This is unfortunate, but the nature of the reality we live in, and we mustn’t ignore it. It’s a dominant force in this world, and left unchecked creates much pain and disharmony. It is the author’s hope that spreading tools like Spiral will enable us all to be more emphatic about such things.&lt;/p&gt;
&lt;p&gt;Done right, religion expressed in Blue provides the “blue”-print (ok, I’ll stop the dad jokes) for how to live a good life. For billions, this is precisely what they need in order to live a good, healthy, meaningful life. You take that away from them, and they’re left with an existential hole so deep it would send most into chaos.&lt;/p&gt;
&lt;p&gt;It provides us answers (truth) to ideas and questions we can’t conceive. Most importantly, it unites us.&lt;/p&gt;
&lt;h2&gt;9. Service&lt;/h2&gt;
&lt;p&gt;&lt;img alt="service" src="http://spirals.blog/articles/blue-introduction/service.jpg" /&gt;
&lt;em&gt;Photo by Daniel Tausis @greatmalinco&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;When one discovers the cool, air-conditioned breeze that Blue offers from the maddening sands of the Red Desert, one is grateful. Put simply, we feel indebted to what Blue provides us and saves us from.&lt;/p&gt;
&lt;p&gt;If this gratitude is strong enough, it expresses itself in servitude. To serve one’s country, god, or company is the life of a true Blue.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I will give myself to the collective, that which is more significant than me. “&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A remarkably pure intention. We would not be where we all are today without it. There would be no nurses, or lawyers, or rubbish men to take your 23 smelly beer bottles away from your home. No police to come RUSHING to your house as soon as you make a phone call. No books. Or written word for that matter.&lt;/p&gt;
&lt;p&gt;We give ourselves to make the world around us better. Purple serves the tribe, but Blue serves something more powerful. Blue can serve ideas. These ideas, if enough people believe in them, can change the course of entire nations. They empower us, inspire us, and in return, serve US.&lt;/p&gt;
&lt;p&gt;Think about the idea of the law for a minute. What would the world be like if there were not sensible rules we all abided by? Many are grateful enough for this and believe it so much that they become an officer or a lawyer.&lt;/p&gt;
&lt;p&gt;Do you go to work? Do you believe in the idea of money enough to work for someone else? You serve society because, in return, you hope it will serve you. This is the deepest truth behind Blue. Let go of the chaos and serve your truth. This service is the foundation that gives many people meaning and purpose in their lives. Without it, the world stops.&lt;/p&gt;
&lt;h2&gt;10. Beyond Blue&lt;/h2&gt;
&lt;p&gt;&lt;img alt="orange" src="http://spirals.blog/articles/blue-introduction/orange.jpg" /&gt;
&lt;em&gt;Photo by lucas clarysse @lucky_photography&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For many reading, this is where much of our own perception is based. In some combination of Purple, Red, and Blue – we live our lives.&lt;/p&gt;
&lt;p&gt;We have &lt;a href="http://localhost:8080/articles/wholearchy/"&gt;spoken at great length&lt;/a&gt; on the topic of “objectifying” the “higher colors”. Simply put, it’s dangerous, we’re often out of perspective, and it can fuck us up (profanity intended) more than we’d ever realize.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is especially true with leaving Blue.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In so many ways, Blue is a gigantic safety blanket. It covers us all, allowing us to live our lives without having to worry about anything more complex.&lt;/p&gt;
&lt;p&gt;Very few of us truly know what it feels like to come “this close” to winning an Olympic gold medal. Nobody remembers second place.&lt;/p&gt;
&lt;p&gt;Not many among us have faced the challenges of maintaining an international conglomerate, with 100,000 employees in 12 different timezones.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Some successfully solve Blue’s challenges in life, only to find that it doesn’t provide what it said it would. By living the narrative they were told, they still encountered problems in life. The government didn’t provide for them. The lawyer cheated them out of a deal. They lost the company job that was offering “life-time job security”.&lt;/p&gt;
&lt;p&gt;Blue doesn’t always work. Like every, single, other color, it’s just &lt;em&gt;&lt;strong&gt;one&lt;/strong&gt;&lt;/em&gt; perspective. It can’t solve every type of problem that exists in the world (Even though it tries to. Ever read a tax law book?) At some point, the system breaks. The bureaucracy, old laws, and “Great American Dream” create more problems than they solve. This is the case with every color.&lt;/p&gt;
&lt;p&gt;Orange is the shiniest color of them all. Don’t be tempted by the snake-oil-trader’s promises of grandeur. 99.999% of the time, he’s full of shit. It’s not really a get rich quick scheme. And no, standing on a machine that makes you jiggle &lt;strong&gt;WON’T&lt;/strong&gt; make you lose weight (and neither will pills).&lt;/p&gt;
&lt;p&gt;There are those who seek to trick us. Those who know we’re weary of &lt;strong&gt;the 20 years it takes to be successful in Blue&lt;/strong&gt;. So they play at our weaknesses. They know we’re buying.&lt;/p&gt;
&lt;p&gt;SIGNIFICANT care, environment, and perspective must be taken when transitioning into Orange. Please consult your local Spiral expert. Leaving the comforts of Blue to pursue what you &lt;em&gt;“think”&lt;/em&gt; is “Orange” (which the majority of the time is not even close) is risky business. Now read this whole paragraph, out loud, another three times. &lt;strong&gt;&lt;em&gt;Please&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That said, there are legitimate cases where Blue is the bottleneck, and new skills are required. We will discuss this in our next article.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;In closing&lt;/h2&gt;
&lt;p&gt;It is my hope that you see the beauty in Blue. For the I’s among us, yes, Blue is a pain in the ass a lot of the time, but it’s there to keep us safe. To keep it all flowing.&lt;/p&gt;
&lt;p&gt;Healthy Blue enables you to do all the other things in life. It provides the stability of a steady paycheck, the assurance of emergency services, running water, and proper healthcare. We probably wouldn’t be alive without it.&lt;/p&gt;
&lt;p&gt;We’re at a point now in this series of colors where things are becoming &lt;strong&gt;very complex.&lt;/strong&gt; This is our most extended article to date, and yet we’ve only scratched the surface on all things Blue.&lt;/p&gt;
&lt;p&gt;How does Blue show up in your life?&lt;/p&gt;
&lt;p&gt;What do you hold as truth?&lt;/p&gt;
&lt;p&gt;How do you serve?&lt;/p&gt;
&lt;p&gt;Blue and all it’s values can be embraced and combined with other colors and perspectives to produce insanely powerful results. For those operating in “higher colors”, look towards Blue for the platform on which all your habits, techniques, and principles are built on.&lt;/p&gt;
&lt;p&gt;For those living the good Purple/Red life, Blue can be an intense journey to set out on. It can feel long and arduous. But always remember, we’re doing it together.&lt;/p&gt;
&lt;p&gt;So hop to it. Clean up your room, do your budget, &lt;a href="https://www.youtube.com/watch?v=PbAoXw_DqvM"&gt;get a haircut and a real job&lt;/a&gt;. Save that bonus. Floss your teeth. Pay the overdue fine. Serve those around you.&lt;/p&gt;
&lt;p&gt;And find &lt;em&gt;&lt;strong&gt;your&lt;/strong&gt;&lt;/em&gt; truth.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 12 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/blue-introduction/</guid></item><item><title>As Cold As A Witches Tit</title><link>https://one.mikro2nd.net/pages/cold-as-a-witches-tit/</link><description>It&amp;rsquo;s cold out, today. And rainy. And howling winds. I have donned double legs and warm belly-binder, and still the cold is getting to parts I&amp;rsquo;d prefer it not to. It&amp;rsquo;s colder than a witches tit.
I am immediately led to ask: Why should witches breasts be colder than anyone else&amp;rsquo;s?
I can only think that the reason witches have colder breasts than other women is all that dancing about naked beneath the light of the moon.</description><author>one mikro2nd</author><pubDate>Sat, 11 Jul 2020 16:23:01 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/cold-as-a-witches-tit/</guid></item><item><title>Against guaranteed services, and jobs</title><link>https://stop.zona-m.net/2020/07/against-guaranteed-services-and-jobs/</link><description>&lt;p&gt;(just a collage of things already said&amp;hellip;)&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 11 Jul 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/against-guaranteed-services-and-jobs/</guid></item><item><title>Hello World</title><link>https://bartlomiejmika.com/posts/2020/hello-world/</link><description>&lt;p&gt;Welcome to my first blog post, I&amp;rsquo;ll explain the purpose of this site, why I started it, and what I hope to accomplish.&lt;/p&gt;</description><author>Bartlomiej Mika</author><pubDate>Sat, 11 Jul 2020 07:02:30 GMT</pubDate><guid isPermaLink="true">https://bartlomiejmika.com/posts/2020/hello-world/</guid></item><item><title>Why aren't developers paid more?</title><link>https://jonpauluritis.com/articles/why-arent-developers-paid-more/</link><description>&lt;p&gt;Over the last few years I've randomly run into articles and/or posts (&lt;a href="https://danluu.com/bimodal-compensation/"&gt;example&lt;/a&gt;, &lt;a href="https://news.ycombinator.com/item?id=21177617"&gt;example&lt;/a&gt;, &lt;a href="https://techcrunch.com/2012/10/27/write-code-get-paid/"&gt;example&lt;/a&gt;, &lt;a href="https://www.reddit.com/r/cscareerquestions/comments/4yy8mm/does_anyone_else_feel_guilty_that_youre_overpaid/"&gt;example&lt;/a&gt;, &lt;a href="https://www.jefftk.com/p/programmers-should-plan-for-lower-pay"&gt;and others&lt;/a&gt;) that assert definitively that software developers/ engineers are paid too much for the work that they do. The &amp;quot;TLDR;&amp;quot; is that the jobs are considerably easier than many technical jobs (Doctor, Electrical Engineer, Lawyer, etc), and often so is the training, so it seems almost unfair that software engineers are paid the way they are. &lt;em&gt;Especially&lt;/em&gt; considering that many software jobs are working on seemingly trivial details such as optimizing buttons or forms.&lt;/p&gt;
&lt;p&gt;In general, I've held conflicting opinions about this thesis. On the one hand if you're getting paid $250K/year to update the css for a button yeah maybe the pay is a little high (seriously though who leverages their people that way?)... but on the other hand some software engineers are up there with the greatest minds on the planet right now and they probably aren't capturing a fair amount of the value they are generating for the businesses that they are working for.&lt;/p&gt;
&lt;p&gt;The latter point of the two made me wonder:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What if developers are actually underpaid?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;While it may seem a little odd to question if individuals making 2X-8X the average US salary are being underpaid I think there's actually a reasonable argument to be made. For starters, there tend to be lots of theories around developer pay that focus on labor market efficiency (danluu identifies a number of theories in &lt;a href="https://danluu.com/bimodal-compensation/"&gt;&amp;quot;Is dev compensation bimodal&amp;quot;&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Aspects such as: the limited supply of developers or increased demand as the technology sector continues to grow (i.e. &lt;a href="https://a16z.com/2011/08/20/why-software-is-eating-the-world/"&gt;&amp;quot;software is eating the world&amp;quot;&lt;/a&gt;). Another theory is that software engineering salaries can be high because certain individuals are actually just more productive (i.e. &lt;em&gt;the mythical &amp;quot;10X developer&amp;quot;&lt;/em&gt;).  This situation creates an &amp;quot;anchoring&amp;quot; effect to these over-productive individuals which raises salaries as companies fight for talent ( dev salaries are bimodal comes from). There is yet another theory that Software Companies are just worth more and so the people that know how to build them are therefore worth more.&lt;/p&gt;
&lt;p&gt;Personally, I find many of these theories can provide some explanation, but I think the macro economic environment is a better explanation.&lt;/p&gt;
&lt;h2&gt;The US loves Venture Capital&lt;/h2&gt;
&lt;p&gt;Over the last 30 years the number and size of US Venture Capital investments has increased dramatically. In 1991 $3.4 billion in venture capital was invested by US venture funds (ref: SBA Trends in Venture Capital Funding ~1997)... in 2019 there was $136.5 Billion invested. Put another way: &amp;quot;there's a shit load of money in the system&amp;quot;&lt;/p&gt;
&lt;p&gt;[Note: I am very aware that not all companies are Venture Capital backed. I am focusing on Venture Capital backed companies because they are the &amp;quot;rising tide that lifts all boats&amp;quot;... meaning other companies have to compete with VC backed companies for the same employee talent pool. If you want a pretty solid explanation on how Venture Capital works read &lt;a href="http://reactionwheel.net/2019/01/why-do-vcs-insist-on-only-investing-in-high-risk-high-return-companies.html"&gt;this article&lt;/a&gt;]&lt;/p&gt;
&lt;p&gt;The reason that there is a shit load of money in the system is because technology companies, and more specifically, software companies have had great return on investment for the last 30 years. Sorry did I say great? I meant mind-blowing returns (&lt;a href="https://www.sequoiafund.com/Performance"&gt;example&lt;/a&gt;). How do they get returns like that?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Simple. They only invest in high-growth, high-return businesses (like software).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To restate- there's more venture money than ever being invested in (software) companies, with the sole condition that they grow like crazy or die (e.g. the Gumroad story is &lt;a href="https://sahillavingia.com/reflecting"&gt;very illuminating&lt;/a&gt;). This state of affairs has influenced the developer labor market by raising developer salaries for those with experience and consequently making it more difficult to break into the industry which furthers the developer &amp;quot;shortage&amp;quot;.&lt;/p&gt;
&lt;p&gt;... but is there method to the madness?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Let's say you're a founder (software) and per your deal with the VC you have to grow fast. To do that you have to build your product fast, which means you need experienced people to build it (because you don't have time to train new people). You go out and recruit looking for talented engineers, but everyone already has a job. Not just that, but they all have good jobs because this VC cash has been flying around for 30 years already. So you finally find someone, and they say they're only willing to come over to a high-risk startup for an extra $30K above market comp for their skill level. Well you look at your situation, you have tons of money but no time... your answer is almost certainly: &amp;quot;fuck it... hire them.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;...And this is the state of the industry.&lt;/p&gt;
&lt;p&gt;Hell, only ~25% of US STEM graduates even work in STEM jobs (&lt;a href="https://www.vox.com/2014/7/11/5888407/even-if-you-have-a-stem-degree-you-probably-dont-have-a-stem-job"&gt;link&lt;/a&gt;) - no doubt at least a few of them would be smart enough to be retrained to do software engineering.&lt;/p&gt;
&lt;p&gt;Here's the thing though, we don't need more STEM people or more programmers... we need more EXPERIENCED programmers because our industry doesn't have time to train new people. So long as there are enough over-sized returns going back to venture capitalists, software developer salaries should continue to go up.&lt;/p&gt;
&lt;p&gt;To some extent developer salaries are influenced by the fact that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We don't have enough &lt;em&gt;experienced&lt;/em&gt; people building software to meet the demand&lt;/li&gt;
&lt;li&gt;Software is eating the world and/or more software is still needed to be built&lt;/li&gt;
&lt;li&gt;Experienced engineers are actually more productive than people manually doing it or multiple junior engineers&lt;/li&gt;
&lt;li&gt;Software companies are worth more (and they return more)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;... but as true as these points are, $140 billion is being spent basically telling founders to ignore the &amp;quot;rounding error&amp;quot; on compensation when hiring an engineer and get building your business.&lt;/p&gt;
&lt;h2&gt;Which brings me back to my main point...&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Assuming you don't completely disagree with the aforementioned state of the industry (I totally get it if you don't agree).&lt;/em&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Venture Capitalists&lt;/strong&gt; need &lt;strong&gt;software companies&lt;/strong&gt; to get their returns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Software companies&lt;/strong&gt; aren't software companies without &lt;strong&gt;software&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;You can't have &lt;strong&gt;software&lt;/strong&gt; with out &lt;strong&gt;software engineers&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;So are software engineers being underpaid?&lt;/h3&gt;
&lt;p&gt;Yes, or maybe.&lt;/p&gt;
&lt;p&gt;Venture capitalist returns have been fairly consistent and Software Company founders have enjoyed an asymmetric risk/reward payout when they succeed... it feels like labor is missing out on their chunk of the pie when considering their leverage and the actual work being performed.&lt;/p&gt;
&lt;p&gt;Now, I totally get that there is a labor market and that the returns for an individual startup could be hard to predict... but I think we also need to be realistic that many of these businesses are simple conversions of analog businesses into digital businesses. It is reasonable to believe that the market could actually bare higher developer salaries as a whole if employers thought that they were receiving adequate value for their money. And if the market can tolerate it why then wouldn't we expect the labor market to react in turn?&lt;/p&gt;
&lt;p&gt;I'll start by saying &lt;strong&gt;I don't know the answer&lt;/strong&gt; (&lt;em&gt;not to mention that would be a whole other article on its own&lt;/em&gt;), but my guess is that the labor market is just inefficient - which is something that software engineers could possibly take advantage of. I think we all know (anecdotally) the industry is really bad at evaluating developer productivity (the way project estimation is conducted should be all the evidence that you need).  The industry is also really (&lt;em&gt;really&lt;/em&gt;) bad at interviewing and evaluating talent opportunities. Things could be confounded further because engineering culture doesn't value soft skills (such as negotiation) nearly as much as technical skills. This arguably causes engineers to &amp;quot;leave money on the table&amp;quot;... by not maximizing their compensation opportunity.&lt;/p&gt;
&lt;h2&gt;Larger Trends&lt;/h2&gt;
&lt;p&gt;The last thing I want to add is that VC related macro economic trends probably aren't the only thing making us &lt;em&gt;&lt;strong&gt;FEEL&lt;/strong&gt;&lt;/em&gt; like engineering compensation is a bit high. A missing asterisk with all these discussions is that US hasn't seen any noticeable wage growth for what, 4 decades? Compare that to a 75% increase in entry level wages at the larger tech firms over the last ten years (~$80K in 2010 to ~$140K in 2020)... yea things are going to feel a little off. If wages across the country were up 40% like we experienced between 1947 and 1960 I feel like the narrative would be different. Other historical periods that compare well to the &amp;quot;information age&amp;quot; saw wages grow considerably (&lt;a href="https://www.investopedia.com/ask/answers/032715/what-impact-does-industrialization-have-wages.asp"&gt;the industrial revolution&lt;/a&gt;, &lt;a href="https://ideas.repec.org/p/tor/tecipa/munro-04-04.html"&gt;post-plague Europe&lt;/a&gt;, post-WW2, etc.), so why is this transformational period different? I don't know but we certainly are feeling it more.&lt;/p&gt;
&lt;h2&gt;Closing&lt;/h2&gt;
&lt;p&gt;Obviously this is an essay not a research study, but if you are going to take anything from this:&lt;/p&gt;
&lt;p&gt;I think it's reasonable to assert software engineers are actually commanding reasonable wages that probably seem inflated more than they actually are inflated. Similarly, I would guess that the industry could benefit from building a better understanding of developer productivity/ how to train engineers rather than just throwing money at the problem... which would probably benefit a lot of engineers too. Chances are they are probably worth more money than they are currently being paid but have no way to know it.&lt;/p&gt;</description><author>JonPaulUritis.com</author><pubDate>Sat, 11 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jonpauluritis.com/articles/why-arent-developers-paid-more/</guid></item><item><title>PS2 RPI4 Part III: Underway</title><link>https://thomashunter.name/posts/2020-07-11-ps2-rpi4-underway</link><author>Thomas Hunter II</author><pubDate>Sat, 11 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thomashunter.name/posts/2020-07-11-ps2-rpi4-underway</guid></item><item><title>Black Holes • Art</title><link>https://muffinman.io/art/black-holes/</link><description>&lt;div class="container"&gt;&lt;div class="art-page__content"&gt;&lt;p&gt;Plotted in two takes on a single paper. White could be a little stronger, I still regret not doing two passes for each layer.&lt;/p&gt;&lt;/div&gt;&lt;table class="text-sm art-page__info"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Created: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;July 2020&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Size: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;70x40cm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Paper: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;200gsm&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Pens: &lt;/b&gt;&lt;/td&gt;&lt;td&gt;Uni-ball Signo UM-153&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;div class="art-gallery photoswipe-gallery art-gallery--wide"&gt;&lt;div class="art-gallery__cover"&gt;&lt;a class="gallery__link outline" href="./0.jpg"&gt;&lt;img alt="" class="gallery__image" height="1381" src="./0.jpg" width="2439" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="art-gallery__items"&gt;&lt;a class="gallery__link outline" href="./1.jpg"&gt;&lt;img alt="" class="gallery__image" height="1294" src="./w_500-h_500--1.jpg" width="1698" /&gt;&lt;/a&gt;&lt;a class="gallery__link outline" href="./2.jpg"&gt;&lt;img alt="" class="gallery__image" height="858" src="./w_500-h_500--2.jpg" width="1357" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;</description><author>Muffin Man</author><pubDate>Sat, 11 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/art/black-holes/</guid></item><item><title>Obstacles to Open Data in and out of Public Administrations</title><link>https://stop.zona-m.net/2020/07/obstacles-to-open-data-in-and-out-of-public-administrations/</link><description>&lt;p&gt;Nothing new (sadly), but well said.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 10 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/obstacles-to-open-data-in-and-out-of-public-administrations/</guid></item><item><title>7 Tips for Wiser Twitter</title><link>https://one.mikro2nd.net/pages/guidelines-for-wiser-twittering/</link><description>Update Nov 2022
In the wake of Elon Musk&amp;rsquo;s takeover of Twitter and the shitshow that has ensued, this post is looking dated and obsolete. To be honest, it&amp;rsquo;s by no means obvious to me that Mastodon is the clear way forward for most people. I&amp;rsquo;m much minded of the Great WhatsApp Exodus, when Facebook changed the WhatsApp Ts&amp;amp;Cs: Much noise, not much light, Signal was supposed to replace it, but most people are still using WhatsApp.</description><author>one mikro2nd</author><pubDate>Fri, 10 Jul 2020 16:53:44 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/guidelines-for-wiser-twittering/</guid></item><item><title>Personal Development</title><link>https://zacs.site/blog/personal-development.html</link><description>&lt;p&gt;A smart person knows everything about a single topic. An intelligent person knows as much as possible about more than one topic. Both have great value, and depending on the industry, some organizations value &lt;a href="Smart versus intelligent.html"&gt;one more than the other&lt;/a&gt;. In general, though, smart people fill entry-level jobs, who then become intelligent people to move up the ladder&lt;sup id="fnref1"&gt;&lt;a href="#fn1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;. A robust personal development strategy will help you go from the former to the latter.&lt;/p&gt;
                &lt;p&gt;&lt;a href="https://zacs.site/blog/personal-development.html"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Fri, 10 Jul 2020 15:54:06 GMT</pubDate><guid isPermaLink="true">https://zacs.site/blog/personal-development.html</guid></item><item><title>Infrequent Roundup, part N</title><link>https://rjp.is/blogging/posts/2020/07/10-links/</link><description>Various things, links, and excitement.</description><author>infrequent oscillations</author><pubDate>Fri, 10 Jul 2020 15:44:49 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/07/10-links/</guid></item><item><title>Devlog #2: game engine architecture</title><link>https://domwillia.ms/devlog2</link><description>A deep dive into my game engine architecture, looking at how the simulation is entirely separate from its visual representation.</description><author>Dom Williams</author><pubDate>Fri, 10 Jul 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://domwillia.ms/devlog2</guid></item><item><title>What do you take home?</title><link>https://blog.harterrt.com/notebook/2020-07-10.html</link><description>&lt;p&gt;Every other week,
I go through my todo list and decide where I should focus my attention.
I review a list of prompts that help me choose important work.
One of the oldest prompts on my list is:
"&lt;strong&gt;What will you take home at the end of the week?&lt;/strong&gt;".&lt;/p&gt;
&lt;p&gt;I …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Fri, 10 Jul 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/notebook/2020-07-10.html</guid></item><item><title>Deep Work: Rules for Focused Success in a Distracted World</title><link>https://olshansky.info/book/deep_work/</link><description>Olshansky's review of Deep Work: Rules for Focused Success in a Distracted World by Cal Newport</description><author>🦉 olshansky 🦁</author><pubDate>Fri, 10 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/deep_work/</guid></item><item><title>Vulnerable API writeup</title><link>https://badshah.io/writeup/vulnerable-api/</link><description>&lt;p&gt;Most of the applications I see these days heavily depend on APIs. Pentesting them is a bit different than that of web applications. In this writeup I will show you how I discovered the vulnerabilities in the &amp;ldquo;&lt;a href="https://github.com/mattvaldes/vulnerable-api"&gt;Vulnerable API&lt;/a&gt;&amp;rdquo; project.&lt;/p&gt;</description><author>Chandrapal Badshah | Security Engineer on Chandrapal Badshah</author><pubDate>Thu, 09 Jul 2020 21:30:00 GMT</pubDate><guid isPermaLink="true">https://badshah.io/writeup/vulnerable-api/</guid></item><item><title>What is heterarchy, and why you want it</title><link>https://stop.zona-m.net/2020/07/what-is-heterarchy-and-why-you-want-it/</link><description>&lt;p&gt;Not alone, of course. But you want heterarchy. Trust me.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 09 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/what-is-heterarchy-and-why-you-want-it/</guid></item><item><title>Outcomes Over Outputs</title><link>http://evantravers.com/articles/2020/07/09/outcomes-over-outputs/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/07/outcomes_over_outputs.png" /&gt;&lt;/p&gt;&lt;p&gt;After reading Lean UX&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; I became convinced of the immense power of describing work to be done in terms of &amp;quot;outcomes over outputs.&amp;quot; It seemed a crystal clear distinction when I was sitting in the classroom discussing it with others who had just finished the book as well… but I've found it a challenging concept to convey to someone who has not been seriously studying it.&lt;/p&gt;
&lt;p&gt;Imagine with me that you are in your kitchen with someone who is waiting for your direction. There are a couple ways you could give direction to your little team… and hopefully I'll be able to persuade you why you may want to consider leading with &lt;em&gt;outcomes&lt;/em&gt; over &lt;em&gt;outputs&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Make a peanut-butter and jelly sandwich.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img alt="sandwich making instructions" src="https://images.evantravers.com/articles/2020/07/sandwich.png" /&gt;&lt;/p&gt;
&lt;p&gt;This is a description of a straightforward &lt;em&gt;output&lt;/em&gt;. You just told the person what to do. No creativity or initiative required of your team.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Take two pieces of bread.&lt;/li&gt;
&lt;li&gt;Cover one with peanut butter.&lt;/li&gt;
&lt;li&gt;Cover the second with jelly.&lt;/li&gt;
&lt;li&gt;Place the two halves together.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The final outcome of these actions is a peanut butter sandwich.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you were shooting for giving your team an outcome… this is short of the mark. An output prescribes the way the goal is accomplished. Here you are describing what to do, and how to do it. A true outcome is a measurable set of goal criteria… that &lt;em&gt;doesn't&lt;/em&gt; specify the output.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'm hungry for two pieces of bread, with peanut butter and jelly in the middle. I, a user, would be pleased if you combined these somehow.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Closer… we are getting further towards describing a desired user outcome, but you are still cheating and prescribing an &lt;em&gt;output&lt;/em&gt;. Try again.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I'm hungry, and I need to eat sometime in the next hour before my next meeting. I'm allergic to shellfish, but otherwise have no dietary requirements. Here's what is in the pantry, and here's a history of what I've liked and disliked for lunch in the past.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally… this is describing a user &lt;em&gt;outcome&lt;/em&gt;: a set of measurable success criteria with some optional boundary conditions. When the user is no longer hungry and enjoys their meal… then the mission is accomplished. There is not a specified thing to make or task to be done, instead you describe a measurable set of success criteria, leaving your team free to creatively solve within those boundaries.&lt;/p&gt;
&lt;p&gt;Why is this important?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It depends on who is standing in the kitchen with you.&lt;/strong&gt; Is it a 5-year old, or a Michelin-rated chef?&lt;/p&gt;
&lt;p&gt;&lt;img alt="sandwich making instructions" src="https://images.evantravers.com/articles/2020/07/cordon_bleu.png" /&gt;&lt;/p&gt;
&lt;p&gt;Carefully detailing the steps for making a peanut butter sandwich makes &lt;em&gt;perfect&lt;/em&gt; sense if you are working with a 5-year old… but if you are working with a talented chef you are preventing yourself from getting the best possible output by restricting the output's description up front.&lt;/p&gt;
&lt;p&gt;If you are leading your product team by prescribing outputs, you are currently asking for a PB&amp;amp;J when &lt;em&gt;you could be having the best meal of your life&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It makes &lt;em&gt;no&lt;/em&gt; sense to specify a restricted output if you trust the people around you to provide creative value and diverse perspectives. If you specify an output instead of an outcome, you rob yourself of the opportunity of a better result than you could imagine alone. Worse, you insinuate that you don't trust your team's ability to solve problems.&lt;/p&gt;
&lt;p&gt;Next time you are cooking something up in your product reflect what you are telling your team by what you are prescribing, and seriously consider experimenting with describing work to be done as an outcome instead of an output.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;Jeff Gothelf, Josh Seiden. &lt;em&gt;Lean UX&lt;/em&gt;. &amp;quot;O'Reilly Media, Inc.&amp;quot;, 2013. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Thu, 09 Jul 2020 14:51:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/07/09/outcomes-over-outputs/</guid></item><item><title>Estimating Pi with a Monte Carlo Simulation</title><link>https://blog.lukesalamone.com/posts/monte-carlo/</link><description>&lt;p&gt;A Monte Carlo simulation is a method of estimating events or quantities which are difficult or computationally infeasible to derive a closed-form solution to. The value of the mathematical constant Pi is a good example of this: although it is possible to calculate the exact value of Pi, a good estimate is easily demonstrated with just a few lines of code.&lt;/p&gt;</description><author>Luke Salamone's Blog</author><pubDate>Thu, 09 Jul 2020 10:40:14 GMT</pubDate><guid isPermaLink="true">https://blog.lukesalamone.com/posts/monte-carlo/</guid></item><item><title>A trip down memory lane: FidoNet and Usenet</title><link>https://nicolaiarocci.com/a-trip-down-memory-lane-fidonet-and-usenet/</link><description>&lt;p&gt;&lt;a href="https://technicshistory.com/"&gt;Creatures of Thought&lt;/a&gt; is a project I discovered just recently. It is about the
history of science and technology, and it revolves around two primary tracks:
The Switch and The Backbone. The former covers the digital switch; the latter
is the story of how the world got online. Both sections are well written,
researched, and curated. The latest installment of The Backbone covers Usenet&amp;rsquo;s
invention, then FidoNet, and well, it sent me on a mesmerizing trip down
memory lane.&lt;/p&gt;</description><author>Nicola Iarocci</author><pubDate>Thu, 09 Jul 2020 08:05:25 GMT</pubDate><guid isPermaLink="true">https://nicolaiarocci.com/a-trip-down-memory-lane-fidonet-and-usenet/</guid></item><item><title>Links - July 9, 2020</title><link>https://faingezicht.com/links/2020/07/09/links/</link><description/><author>Avy Faingezicht</author><pubDate>Thu, 09 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/links/2020/07/09/links/</guid></item><item><title>The rocky road to implementing link prefetching in Rails</title><link>https://phacks.dev/articles/the-rocky-road-to-implementing-link-prefetching-in-rails</link><description>I set up to implement link prefetching in our Ruby on Rails application, and boy was it a wild ride. Buckle up!</description><author>Nicolas Goutay</author><pubDate>Thu, 09 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://phacks.dev/articles/the-rocky-road-to-implementing-link-prefetching-in-rails</guid></item><item><title>Jamulus and Temporally Hyper-Near Servers</title><link>https://andrewferguson.net/2020/07/08/jamulus-and-temporally-hyper-near-servers/</link><description>Temporally Hyper-Near Servers As we&amp;#8217;ve been doing more video and audio conferencing lately, I&amp;#8217;ve been experimenting with temporally hyper-near servers to see if it results in a better experience. TL;DR…not really for most purposes. Temporally hyper-near servers differ from geographically near servers in that it doesn&amp;#8217;t matter how close the server is physically in miles,&amp;#8230;&amp;#160;&lt;a class="" href="https://andrewferguson.net/2020/07/08/jamulus-and-temporally-hyper-near-servers/" rel="bookmark"&gt;Read More &amp;#187;&lt;span class="screen-reader-text"&gt;Jamulus and Temporally Hyper-Near Servers&lt;/span&gt;&lt;/a&gt;</description><author>Andrew Ferguson dot NET</author><pubDate>Wed, 08 Jul 2020 22:12:54 GMT</pubDate><guid isPermaLink="true">https://andrewferguson.net/2020/07/08/jamulus-and-temporally-hyper-near-servers/</guid></item><item><title>From Irrigation Canals to Linux...</title><link>https://stop.zona-m.net/2020/07/from-irrigation-canals-to-linux.../</link><description>&lt;p&gt;What is missing here?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 08 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/from-irrigation-canals-to-linux.../</guid></item><item><title>Introducing PerfBeacon - Continuously Measure Site Speed via API or Schedule</title><link>https://maxrozen.com/introducing-perfbeacon</link><description>PerfBeacon was a wrapper around Google Lighthouse that lets you continuously measure your site's performance via API, or a schedule</description><author>Max Rozen</author><pubDate>Wed, 08 Jul 2020 18:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/introducing-perfbeacon</guid></item><item><title>I don't want toast</title><link>https://zefram.xyz/2020/07/i-dont-want-toast.html</link><description>&lt;p&gt;Recently, I have realized that all the mistakes I&amp;rsquo;ve made in the past, and is still making, have been caused by a single type of error: mistaking expedience for desire, for a call to action.&lt;/p&gt;
&lt;p&gt;When I am looking to make a purchase, say a toaster, I look for a &amp;ldquo;good deal&amp;rdquo;. The toaster can&amp;rsquo;t have a significant number of bad reviews. The price can&amp;rsquo;t be too low, such that the toaster is bound to break down in a month; but it also can&amp;rsquo;t be too expensive, such that the purchase becomes exorbitant. It should have many features: a timer, different modes, bagel compatibility; but it&amp;rsquo;s okay if it&amp;rsquo;s missing a few as long as the price is lower. Might seem reasonable to try and find a &amp;ldquo;good deal&amp;rdquo; like this, but if one thought it through, one would find that it&amp;rsquo;s a recipe for mediocrity.&lt;/p&gt;</description><author>Zefram's Blog</author><pubDate>Wed, 08 Jul 2020 10:14:00 GMT</pubDate><guid isPermaLink="true">https://zefram.xyz/2020/07/i-dont-want-toast.html</guid></item><item><title>Keeping a Journal</title><link>https://blog.harterrt.com/notebook/2020-07-08.html</link><description>&lt;p&gt;There was a discussion of
&lt;a href="https://hbr.org/2017/07/the-more-senior-your-job-title-the-more-you-need-to-keep-a-journal"&gt;this HBR article&lt;/a&gt;
("The More Senior Your Job Title, the More You Need to Keep a Journal")
&lt;a href="https://news.ycombinator.com/item?id=23768624"&gt;on HN&lt;/a&gt; today.&lt;/p&gt;
&lt;p&gt;This is great advice.
I've kept a journal for almost a decade now
and it's definitely improved my career
especially as I've become more senior …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Wed, 08 Jul 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/notebook/2020-07-08.html</guid></item><item><title>What is Jamstack and why should you use it?</title><link>https://rajeevnaruka.com/blog/What-is-Jamstack-and-why-should-you-use-it</link><description>Learn what Jamstack really means and what are the benefits of Jamstack over traditional solutions like running your own server for back-end using the likes of NodeJS or Ruby on Rails.(updated 2020).</description><author>Rajeev Singh Naruka</author><pubDate>Wed, 08 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://rajeevnaruka.com/blog/What-is-Jamstack-and-why-should-you-use-it</guid></item><item><title>Hugo: a static-site generator</title><link>https://lwn.net/Articles/825507/</link><description>An overview of Hugo, a flexible static website generator written in Go and optimized for speed (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Wed, 08 Jul 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/825507/</guid></item><item><title>Italian public schools surrender email to Microsoft</title><link>https://stop.zona-m.net/2020/07/italian-public-schools-surrender-email-to-microsoft/</link><description>&lt;p&gt;Because it costs less, of course. But&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 07 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/italian-public-schools-surrender-email-to-microsoft/</guid></item><item><title>Restoring (Some) Integrity in Politics</title><link>https://one.mikro2nd.net/pages/reining-in-the-political-classes/</link><description>Politics as the overwhelming mass of us experience it — worldwide to a very great degree — is deeply and fundamentally broken. We, the people, get to express a vote once every N years, after which politicians lie, cheat and steal, do and say pretty much anything they want in the service of party and getting said party re-elected, with an appalling lack of consequence or accountability. This is fundamentally a systems problem.</description><author>one mikro2nd</author><pubDate>Tue, 07 Jul 2020 17:18:54 GMT</pubDate><guid isPermaLink="true">https://one.mikro2nd.net/pages/reining-in-the-political-classes/</guid></item><item><title>When your WPF menu alignment is wrong</title><link>https://ilearnt.com/blog/menualignment/</link><description>&lt;p&gt;I had a very weird problem where my menus on a WPF application were dropping down to the left instead of the normal to the right.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Tue, 07 Jul 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/menualignment/</guid></item><item><title>Practical Hypermedia Controls</title><link>https://daniellittle.dev/practical-hypermedia-controls</link><description>A lot has been written about REST but less so when it comes to Hypermedia Controls. I haven't seen too many Hypermedia based APIs out in the…</description><author>Daniel Little Dev</author><pubDate>Tue, 07 Jul 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://daniellittle.dev/practical-hypermedia-controls</guid></item><item><title>Like of https://ohhelloana.blog/overthinking-likes/</title><link>https://qubyte.codes/likes/1594107603722</link><description>&lt;p&gt;Like of &lt;a href="https://ohhelloana.blog/overthinking-likes/"&gt;https://ohhelloana.blog/overthinking-likes/&lt;/a&gt;&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Tue, 07 Jul 2020 10:40:03 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/likes/1594107603722</guid></item><item><title>Placeholdifier</title><link>https://github.com/pomber/placeholdifier</link><description>Turn any website into a live wireframe</description><author>Rodrigo Pombo</author><pubDate>Tue, 07 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://github.com/pomber/placeholdifier</guid></item><item><title>Song practice app concept</title><link>https://ciesie.com/post/song_practice_app/</link><description>&lt;p&gt;If you&amp;rsquo;ve ever tried to get better at playing a particular song you want to learn, you might want
to first learn it in chunks. After you feel good with those chunks you start putting it all
together. Then you realize, you still suck at some of those chunks, so you practice them.&lt;/p&gt;
&lt;p&gt;It would be nice to have a tool that works well for that process. I didn&amp;rsquo;t feel like coding today
but I needed to export this idea out of my mind so here is a quick concept I&amp;rsquo;ve put together.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Tue, 07 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/song_practice_app/</guid></item><item><title>How to use NextJS API routes?</title><link>https://rajeevnaruka.com/blog/how-to-use-nextjs-api-routes</link><description>This is a complete guide to understand how API routes work in NextJS and how you can use them easily in your next project. We will also cover examples to fully understand it (updated 2020).</description><author>Rajeev Singh Naruka</author><pubDate>Tue, 07 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://rajeevnaruka.com/blog/how-to-use-nextjs-api-routes</guid></item><item><title>How to Keep Your JS Libraries Up to Date</title><link>https://www.dannyguo.com/blog/how-to-keep-your-js-libraries-up-to-date</link><author>Danny Guo</author><pubDate>Tue, 07 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.dannyguo.com/blog/how-to-keep-your-js-libraries-up-to-date</guid></item><item><title>Implementing a Blog Series in Middleman</title><link>http://evantravers.com/articles/2020/07/06/implementing-a-blog-series-in-middleman/</link><description>&lt;p&gt;While working on my &lt;a href="/articles/series/hammerspoon-headspace"&gt;hammerspoon series&lt;/a&gt;, I decided it was a good time to refactor how I related a series of blog posts. Over the past year or two, I've found myself doing a series of shorter posts rather than one long &lt;em&gt;monster post&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I first implemented this for my series on Git Gud at Vim. I simply used a markdown comment that I copy pasted at the top of every post, and a tag &lt;code&gt;git-gud-vim&lt;/code&gt; that I used to link them all together. It worked just fine, and I did the same for the World of Textfiles posts.&lt;/p&gt;
&lt;p&gt;While working on the Hammerspoon Headspace series, I wanted to do a little more styling, and realized quickly that I probably could do something a little more comprehensive. Still using tags, I just wrote some custom logic conditional on a tag that started with &lt;code&gt;series-&lt;/code&gt;. If a post had a tag prefixed with &lt;code&gt;series-&lt;/code&gt;, it'd look in a folder for a partial named the same way and include it.&lt;/p&gt;
&lt;p&gt;This was of course a dreadful kluge, but it got me a single partial I could use in several places… so every post could be updated all at the same time.&lt;/p&gt;
&lt;p&gt;Eventually I dug further into middleman's docs and found their &lt;a href="https://middlemanapp.com/basics/blogging/#custom-article-collections"&gt;custom collections feature&lt;/a&gt;. This meant that I could create  custom YAML attribute and fire off some logic &lt;em&gt;much&lt;/em&gt; more simply.&lt;/p&gt;
&lt;p&gt;First initialize the custom collection…&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;activate&lt;/span&gt; &lt;span&gt;:blog&lt;/span&gt; &lt;span&gt;do&lt;/span&gt; &lt;span&gt;|&lt;/span&gt;&lt;span&gt;blog&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;blog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tag_template&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;tag.html&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;blog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;calendar_template&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;calendar.html&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;blog&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;custom_collections&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;series&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;link&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;/series/&amp;amp;lbraceseries&amp;amp;rbrace.html&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;template&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;'&lt;/span&gt;&lt;span&gt;/articles/series/show.html&lt;/span&gt;&lt;span&gt;'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I just built a quick helper in config.rb to grab the content from the partial. There may be a better way to do this… but this worked.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-ruby" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;def&lt;/span&gt; &lt;span&gt;series_header&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;is_index&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;false&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;header&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;is_index&lt;/span&gt; &lt;span&gt;?&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt; &lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;%&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;header&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &amp;lt;div class=&amp;quot;article__series&amp;quot;&amp;gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;partial&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;articles/series/&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;slugify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &amp;lt;div class=&amp;quot;blog__tags&amp;quot;&amp;gt;
&lt;/div&gt;&lt;div class="line"&gt;        &amp;lt;span class=&amp;quot;emoji&amp;quot;&amp;gt;🗂&amp;lt;/span&amp;gt;
&lt;/div&gt;&lt;div class="line"&gt;        &amp;lt;a href=&amp;quot;/articles/series/&lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;slugify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;&amp;quot;&amp;gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;/span&gt;&lt;span&gt;#&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;series&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &amp;lt;/a&amp;gt;
&lt;/div&gt;&lt;div class="line"&gt;      &amp;lt;/div&amp;gt;
&lt;/div&gt;&lt;div class="line"&gt;    &amp;lt;/div&amp;gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I can use this on the &lt;a href="/articles/series/git-gud-at-vim"&gt;series show page&lt;/a&gt;, the &lt;a href="/articles/series/"&gt;series listing page&lt;/a&gt;, or any &lt;a href="http://evantravers.com/articles/2020/06/19/hammerspoon-headspace/"&gt;single page in a series&lt;/a&gt;… I can update the series display, or the content, and it updates &lt;em&gt;everywhere&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I love being able to build my website into &lt;em&gt;whatever&lt;/em&gt; I want… hopefully even if I leave &lt;a href="http://middlemanapp.com/"&gt;middleman&lt;/a&gt; I can take the content I wrote for the series headers with me.&lt;/p&gt;</description><author>trv.rs</author><pubDate>Tue, 07 Jul 2020 00:29:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/07/06/implementing-a-blog-series-in-middleman/</guid></item><item><title>Innovation in Clean Tech is still needed</title><link>https://stop.zona-m.net/2020/07/innovation-in-clean-tech-is-still-needed/</link><description>&lt;p&gt;SORELY needed&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 06 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/innovation-in-clean-tech-is-still-needed/</guid></item><item><title>Voronants</title><link>https://rjp.is/blogging/posts/2020/07/voronants/</link><description>In which we explore a fractal landscape with ants.</description><author>infrequent oscillations</author><pubDate>Mon, 06 Jul 2020 11:19:43 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/07/voronants/</guid></item><item><title>Notes on gravity as a gauge theory</title><link>https://diffxweyl.wordpress.com/2020/07/05/notes-on-gravity-as-a-gauge-theory/</link><description>Gravity has often been called a gauge theory of the Poincaré or Lorentz group. Here, I develop general relativity in direct analogy to Yang-Mills theory, avoiding geometry entirely1. None of this is original, but I have tried to simplify the presentation compared to the literature, where the similarities and differences between the two theories are &amp;#8230; &lt;a class="more-link" href="https://diffxweyl.wordpress.com/2020/07/05/notes-on-gravity-as-a-gauge-theory/"&gt;Continue reading&lt;span class="screen-reader-text"&gt; "Notes on gravity as a gauge&amp;#160;theory"&lt;/span&gt;&lt;/a&gt;</description><author>diff × weyl</author><pubDate>Mon, 06 Jul 2020 08:51:48 GMT</pubDate><guid isPermaLink="true">https://diffxweyl.wordpress.com/2020/07/05/notes-on-gravity-as-a-gauge-theory/</guid></item><item><title>Interactive SVG Outline Map in React</title><link>https://www.tderflinger.com/en/interactive-svg-map-munich</link><description>Interactive maps on the web are a great way to visualize information.
How to create an interactive outline map with React of the city of Munich, I want to show in this article.</description><author>Thoughts by Thomas Derflinger</author><pubDate>Mon, 06 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.tderflinger.com/en/interactive-svg-map-munich</guid></item><item><title>Disconnected, Hood Mountain</title><link>https://faingezicht.com/photos/2020/07/06/hoodmtn/</link><description>For 4th of July weekend Hannah and I took a last minute backpacking trip to Hood Mountain, right on the border of Napa and Sonoma Counties. We had been looking for campsite permits in a bunch of different parks during the weeks leading up to the long weekend, but nothing seemed to open up. Luckily, Sonoma regional parks had had their reservation system closed due to COVID, and they opened it the morning of the 2nd. After a stressful morning trying to book something, we found this site.

This was our first time leaving SF since the shelter-in-place order started, and it was great to disconnect almost completely. Except for a couple of _let's check Alltrails_ moments, and a short call to my dad to wish him happy birthday, my phone was on airplane mode the whole time.</description><author>Avy Faingezicht</author><pubDate>Mon, 06 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/photos/2020/07/06/hoodmtn/</guid></item><item><title>Update for July, year of total chaos 2020</title><link>https://ciesie.com/post/update_06072020/</link><description>&lt;p&gt;I&amp;rsquo;m trying something new. I&amp;rsquo;d like to regularly write some sort of an update which explains what
I&amp;rsquo;m working on. Since this website doesn&amp;rsquo;t generate any meaningful traffic, I&amp;rsquo;m doing this for
myself. I&amp;rsquo;m not imposing any strict time frame on this. I don&amp;rsquo;t want to do this too often, since
I don&amp;rsquo;t want my blog to be full of posts like this one. I want the blog section to be useful for
weary travellers who look for answers, in this world full of questions! Anyway, lets get to it.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Mon, 06 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/update_06072020/</guid></item><item><title>So, you think online conferencing is new?</title><link>https://jasoneckert.github.io/myblog/so-you-think-online-conferencing-is-new/</link><description>&lt;p&gt;&lt;img alt="Olde Hespeler" src="hespeler.png#center" title="Olde Hespeler" /&gt;&lt;/p&gt;
&lt;p&gt;The city that I live in (Cambridge, Ontario) was formed as an amalgamation of three smaller towns (Hespeler, Preston and Galt) in 1973. Hespeler gets its name from Jacob Hespeler, who built an impressive industrial empire in the town in 1845. Through his widespread influence, he secured railway access, as well as attracted engineering talent from as far away as Europe. By the start of World War I, Hespeler housed the largest textile mill in the British Empire, and had an electric passenger railway (Grand River Railway) that allowed easy transit to the rest of the region.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Mon, 06 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/so-you-think-online-conferencing-is-new/</guid></item><item><title>Rendering drawings with tuhirender</title><link>https://blog.gnoack.org/post/tuhirender</link><description>&lt;p&gt;Recently, almost all my digital drawings were made with a &lt;a href="https://www.amazon.de/Wacom-Bamboo-Slate-Smartpad-Digitalisierungs-Funktion/dp/B01L1V61MC"&gt;Bamboo
Slate&lt;/a&gt;
tablet and &lt;a href="https://github.com/tuhiproject/tuhi"&gt;Tuhi&lt;/a&gt;. It was good
fun to take Tuhi&amp;rsquo;s drawing data and create my own renderer
&lt;a href="https://github.com/gnoack/tuhirender"&gt;tuhirender&lt;/a&gt;, which can be used
from the command line to produce some more advanced effects and tune
more of the rendering knobs.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tuhirender&lt;/code&gt; replaces Tuhi&amp;rsquo;s own renderer by building on Tuhi&amp;rsquo;s
JSON-based output format for line coordinates and pen pressure data.&lt;/p&gt;
&lt;h2 id="basic-invocation"&gt;Basic invocation&lt;/h2&gt;
&lt;p&gt;The basic invocation is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tuhirender -width 200 -fit -o out.png &amp;lt; in/1593622352.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All parameters are in principle optional, but this invocation shows
the most commonly used options. &lt;code&gt;-width&lt;/code&gt; specifies the desired output
width in pixels.&lt;/p&gt;
&lt;h2 id="animate-a-drawing"&gt;Animate a drawing&lt;/h2&gt;
&lt;p&gt;To animate the drawing progress, use the &lt;code&gt;gif&lt;/code&gt; output format by passing the flag &lt;code&gt;--format gif&lt;/code&gt; and specifying a matching filename with &lt;code&gt;-o out.gif&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="" src="/images/drawing.gif" /&gt;
&lt;figcaption&gt;&lt;p&gt;An animated drawing&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="simplify-line-segments"&gt;Simplify line segments.&lt;/h2&gt;
&lt;p&gt;With the &lt;code&gt;--simplify&lt;/code&gt; flag, &lt;code&gt;tuhirender&lt;/code&gt; simplifies all lines. See my
previuos post on the topic: &lt;a href="https://blog.gnoack.org/post/path-simplification-lib/"&gt;Go: Path simplification
library&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="An original and a path-simplified picture side-by-side" src="/images/hippie.png" /&gt;
&lt;figcaption&gt;&lt;p&gt;Original and simplified version side-by-side&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This picture is a bit of an extreme example to demonstrate the
simplification. When tweaking the parameters a bit, the simplification
is less visible. At some point, I might be able to use this for
outputting vector graphics at reduced file size and acceptable quality
loss.&lt;/p&gt;
&lt;h2 id="some-sample-pictures"&gt;Some sample pictures&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="" src="/images/winged-victory-of-samothrace.png" /&gt;
&lt;figcaption&gt;&lt;p&gt;A bigger picture: Winged Victory of Samothrace&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is the biggest picture I&amp;rsquo;ve drawn so far with the tablet; I&amp;rsquo;m
happy with how it turned out. The hatching renders nicely and produces
the desired shades.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="" src="/images/sausage.png" /&gt;
&lt;figcaption&gt;&lt;p&gt;A cartoon drawing: A man, a dog and a sausage&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This cartoon drawing is simpler and has a bigger zoom, so it&amp;rsquo;s easier
to see how the change in pen pressure is rendered.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="" src="/images/gopher.png" /&gt;
&lt;figcaption&gt;&lt;p&gt;A gopher&lt;/p&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The gopher picture has a lot of nuanced Pen pressure, and arguably it
looked slightly better on paper. At the moment, &lt;code&gt;tuhirender&lt;/code&gt; renders
pen pressure by modifying the line width on the go. I suspect that
changing the line opacity might be better, but I&amp;rsquo;m still looking for
an elegant algorithm to fix up the artifacts between line segments
when doing that.&lt;/p&gt;</description><author>Blog on blog.gnoack.org</author><pubDate>Mon, 06 Jul 2020 01:04:10 GMT</pubDate><guid isPermaLink="true">https://blog.gnoack.org/post/tuhirender</guid></item><item><title>How to Install Custom Firmware on Your Xiaomi M365 E-Scooter</title><link>https://www.mikekasberg.com/blog/2020/07/05/how-to-install-custom-firmware-on-your-xiaomi-m365.html</link><description>&lt;p&gt;The &lt;a href="https://www.mi.com/global/mi-electric-scooter"&gt;Xiaomi m365&lt;/a&gt; (also known as
the Xiaomi Mi) is one of the most highly-rated electric scooters available. If
you’ve ever rented a Lyft or a Bird scooter, the design will look very familiar.
This electric scooter is fun to ride and great for commuting! But one of the
best things about the m365 scooter is that you can modify the firmware to suit
your own preferences! It’s easy to do and should only take 20 or 30 minutes.
Let’s get started!&lt;/p&gt;

&lt;div class="warning"&gt;
&lt;p&gt;&lt;b&gt;Modify your firmware at your own risk!&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;These instructions worked for me, but I can't guarantee they'll work for you.
There are inherent risks associated with this procedure and I'm not responsible
for anything that goes wrong.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id="part-1-ensure-your-scooter-is-compatible-with-modified-firmware"&gt;Part 1: Ensure your scooter is compatible with modified firmware&lt;/h2&gt;

&lt;p&gt;This firmware mod will work on any Xiaomi m365 e-scooter with 2 fuses. Most m365
scooters manufactured after March 2017 do have 2 fuses. To verify that your
scooter has 2 fuses:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Find the serial number of your scooter. It’s located on a sticker on the
side of the base and will look like the one in the picture below. There are two
parts separated by a &lt;code class="language-plaintext highlighter-rouge"&gt;/&lt;/code&gt;. The first part describes the country
and the color. The second part is a unique serial number.&lt;/p&gt;

    &lt;p&gt;&lt;img alt="m365 serial number sticker" src="https://www.mikekasberg.com/images/m365-custom-firmware/serial-number.jpg" /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Use the first part of the number to find some info about your scooter in
the chart below:&lt;/p&gt;

    &lt;table&gt;
      &lt;thead&gt;
        &lt;tr&gt;
          &lt;th&gt;Serial No.&lt;/th&gt;
          &lt;th&gt;Country&lt;/th&gt;
          &lt;th&gt;Color&lt;/th&gt;
          &lt;th&gt;2 Fuses?&lt;/th&gt;
        &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
        &lt;tr&gt;
          &lt;td&gt;13678&lt;/td&gt;
          &lt;td&gt;China&lt;/td&gt;
          &lt;td&gt;White&lt;/td&gt;
          &lt;td&gt;Check Battery Date&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;13679&lt;/td&gt;
          &lt;td&gt;China&lt;/td&gt;
          &lt;td&gt;Black&lt;/td&gt;
          &lt;td&gt;Check Serial&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;16132&lt;/td&gt;
          &lt;td&gt;Europe&lt;/td&gt;
          &lt;td&gt;White&lt;/td&gt;
          &lt;td&gt;Check Battery Date&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;16133&lt;/td&gt;
          &lt;td&gt;Europe&lt;/td&gt;
          &lt;td&gt;Black&lt;/td&gt;
          &lt;td&gt;Yes&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
          &lt;td&gt;16349&lt;/td&gt;
          &lt;td&gt;US&lt;/td&gt;
          &lt;td&gt;Black&lt;/td&gt;
          &lt;td&gt;&lt;a href="https://www.amazon.com/ask/questions/Tx2RGKDYX0X9WRD/ref=ask_ql_ql_al_hza"&gt;Yes&lt;/a&gt;&lt;/td&gt;
        &lt;/tr&gt;
      &lt;/tbody&gt;
    &lt;/table&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you have the European black version or the US version, you should have 2
fuses. Skip ahead to part 2. If you have the Chinese black version, and the
second part of your serial number is greater than &lt;code class="language-plaintext highlighter-rouge"&gt;00035000&lt;/code&gt;, you should have 2
fuses – skip ahead to part 2. If you have a white model continue here to check
the battery date.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;To check the battery date of manufacture, you need to connect your scooter
to the Mi Home app
(&lt;a href="https://apps.apple.com/us/app/mi-home-xiaomi-smarthome/id957323480"&gt;iOS&lt;/a&gt;/&lt;a href="https://play.google.com/store/apps/details?id=com.xiaomi.smarthome"&gt;Android&lt;/a&gt;).
After connecting your scooter to the app, look at &lt;strong&gt;Battery Info&lt;/strong&gt; and check the
&lt;strong&gt;Production Date&lt;/strong&gt;. If the battery production date is later than March 2017,
you should have 2 fuses, and can continue with the mod.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your scooter has 2 fuses, it should be safe to modify the firmware. If the
scooter is an older model with a single fuse, it is risky to continue because
the firmware mod is likely to destroy the fuse.&lt;/p&gt;

&lt;h2 id="part-2-build-your-custom-firmware"&gt;Part 2: Build your custom firmware&lt;/h2&gt;

&lt;p&gt;GitHub user BotoX has developed a tool to patch custom parameters into the m365
scooter firmware. The tool is open source, developed in Python, and you can see
the source code &lt;a href="https://github.com/BotoX/xiaomi-m365-firmware-patcher"&gt;on
GitHub&lt;/a&gt; if you’re
interested. Really though, the source code isn’t what we’re interested in. We’re
simply going to use the software on his website to patch a custom firmware.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open &lt;a href="https://m365.botox.bz"&gt;https://m365.botox.bz&lt;/a&gt; on your phone.&lt;/li&gt;
  &lt;li&gt;Select the options for your own custom firmware. You can get started with
some defaults using the buttons at the top. The website explains most of the
settings well, but I’ll add some detail for a few important settings below.&lt;/li&gt;
  &lt;li&gt;When you’re done, click &lt;code class="language-plaintext highlighter-rouge"&gt;Patch!&lt;/code&gt; and save the zip to your phone.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id="my-settings"&gt;My Settings&lt;/h3&gt;

&lt;p&gt;I’ll share the settings I prefer below. Use these as suggestions if you’re not
sure what to customize.&lt;/p&gt;

&lt;h4 id="base-version"&gt;Base Version&lt;/h4&gt;

&lt;p&gt;There’s a strong consensus that &lt;code class="language-plaintext highlighter-rouge"&gt;1.3.8&lt;/code&gt; is the best version to use, so I used
that as my &lt;strong&gt;base version&lt;/strong&gt;.&lt;/p&gt;

&lt;h4 id="kers-min-speed"&gt;KERS min speed&lt;/h4&gt;

&lt;p&gt;I didn’t change the &lt;strong&gt;KERS min speed&lt;/strong&gt; because I actually like the automatic
braking, and I’ve come to expect it.&lt;/p&gt;

&lt;h4 id="maximum-speed-in-normal-mode"&gt;Maximum speed in normal mode&lt;/h4&gt;

&lt;p&gt;I bumped the &lt;strong&gt;maximum speed in normal mode&lt;/strong&gt; up to &lt;code class="language-plaintext highlighter-rouge"&gt;30&lt;/code&gt;. This is in km/h, so
that’s roughly 18.5 mph. I would have set it faster, but other components
prevent the scooter from going much faster, so I’ve found &lt;code class="language-plaintext highlighter-rouge"&gt;30&lt;/code&gt; to be the highest
you can go here to keep a smooth ride. I didn’t patch the eco mode speed (which
I rarely use anyway).&lt;/p&gt;

&lt;h4 id="motor-start-speed"&gt;Motor start speed&lt;/h4&gt;

&lt;p&gt;I set the &lt;strong&gt;motor start speed&lt;/strong&gt; to &lt;code class="language-plaintext highlighter-rouge"&gt;3&lt;/code&gt; instead of &lt;code class="language-plaintext highlighter-rouge"&gt;5&lt;/code&gt;. This prevents those
situations where you need to kick more to get the motor to start.&lt;/p&gt;

&lt;h4 id="motor-power-constant"&gt;Motor power constant&lt;/h4&gt;

&lt;p&gt;I also bumped the &lt;strong&gt;motor power constant&lt;/strong&gt; down to the DYoC setting of &lt;code class="language-plaintext highlighter-rouge"&gt;40165&lt;/code&gt;
(remember lower is more power). This seemed like a good compromise to get a
little extra power (i.e. acceleration) but not put too much extra wear on the
motor. (I don’t want it to break too quickly!)&lt;/p&gt;

&lt;p&gt;I left the rest of the settings alone – most of them are unnecessary to change
or only needed for advanced/unusual customization. But feel free to experiment
more if you want!  Here’s another blogger’s
&lt;a href="http://nelsonware.com/blog/2018/09/24/my-xiaomi-mijia-m365-dyoc-settings.html"&gt;thoughts&lt;/a&gt;.
This tool lets you customize the firmware that’s right &lt;em&gt;for you&lt;/em&gt;, so you don’t
have to use my settings if you don’t want to.&lt;/p&gt;

&lt;h2 id="part-3-install-the-firmware-to-the-scooter"&gt;Part 3: Install the firmware to the scooter&lt;/h2&gt;

&lt;p&gt;Finally, we’re ready to install our firmware. The best way is to use the &lt;a href="https://play.google.com/store/apps/details?id=com.m365downgrade"&gt;m365
DownG&lt;/a&gt; Android
app. First, connect the app to the scooter. After you’re connected, choose &lt;code class="language-plaintext highlighter-rouge"&gt;Open
Bin&lt;/code&gt; to open the zipped firmware you downloaded from the BotoX website. Finally,
hit &lt;code class="language-plaintext highlighter-rouge"&gt;Flash Bin&lt;/code&gt; to send the firmware to the scooter. If you don’t have an
Android device, see if you can find a friend who will let you use theirs.
Apparently there’s a new, similar app on iOS, but I’m not sure how well it
works.&lt;/p&gt;

&lt;p&gt;&lt;img alt="m365 DownG app screenshot" src="https://www.mikekasberg.com/images/m365-custom-firmware/downg.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;Now you’re done! Take that scooter out for a test ride! And let me know what
you think &lt;a href="https://twitter.com/mike_kasberg"&gt;@mike_kasberg&lt;/a&gt;. Of course, credit
is also due to &lt;a href="https://github.com/botox"&gt;BotoX&lt;/a&gt;, who developed the firmware
tool, and &lt;a href="https://github.com/CamiAlfa"&gt;CamiAlfa&lt;/a&gt;, who developed the flashing
app. Thanks for reading, have fun, and stay safe!&lt;/p&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Mon, 06 Jul 2020 00:30:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/07/05/how-to-install-custom-firmware-on-your-xiaomi-m365.html</guid></item><item><title>D-Bus and Polkit, No More Mysticism and Confusion</title><link>https://venam.net/blog/unix/2020/07/06/dbus-polkit.html</link><description>Dbus and Polkit are two technologies that emanate an aura of confusion. While their names are omnipresent in discussions, and the internet has its share of criticism and rants about them, not many have a grasp of what they actually do. In this article I'll give an overview of these technologies.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Mon, 06 Jul 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/unix/2020/07/06/dbus-polkit.html</guid></item><item><title>Simplified Hardware Arx</title><link>https://truthindustri.es/hardware/2020/07/05/simplified-hardware-arx.html</link><description>I’m taking an online workshop on building electronic musical instruments. So last week I put together a sketch, in blog post form, of what it might look like to make a hardware Arx — which is to say, a hardware version of my Ruby breakbeat improviser Archaeopteryx (renamed for simplicity).</description><author>truth industri.es</author><pubDate>Sun, 05 Jul 2020 19:58:10 GMT</pubDate><guid isPermaLink="true">https://truthindustri.es/hardware/2020/07/05/simplified-hardware-arx.html</guid></item><item><title>Automating My Weekly Review in Things.app</title><link>http://evantravers.com/articles/2020/07/05/automating-my-weekly-review-in-things-app/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/07/example_weekly_review.png" /&gt;&lt;/p&gt;&lt;div class="admonition update"&gt;
&lt;p&gt;If you want a crossplatform version of this I've built &lt;a href="https://evantravers.com/articles/2023/01/27/weekly-reviews-in-things-app-using-shortcuts/"&gt;a version using Shortcuts&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;For the past couple of months, I've adopted a weekly review ritual to help me stay in tune with my work and not be overwhelmed. I structured the original format from Peter Akkies's comprehensive review template for Things, but I have since modified it for my purposes.&lt;/p&gt;
&lt;p&gt;The crux of Peter's review template is a helpful series of questions that you ask yourself for each Project in your Things.app account.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="" src="https://images.evantravers.com/articles/2020/07/former_weekly_review.png" /&gt;
  &lt;figcaption&gt;
    This is what my Weekly Review repeating to-do used to look like. Pretty overwhelming, right?
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The first iteration of this involved a repeating task with a giant text note with all the steps. For each Project in Things.app, I had to jump over to the Project, answer each question, then go to the next Project and repeat. To shorten the loop, I would open the repeated task in one window, and have another window to do the actual review.&lt;/p&gt;
&lt;p&gt;Things does not really want you to use more than one window, and it's a little difficult to set it up, so I wrote some Hammerspoon lua code that sets up my favorite window setup. (Pictured at the top of the article.)&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launchOrFocusByBundleID&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.culturedcode.ThingsMac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;things&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.culturedcode.ThingsMac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Hide Sidebar&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fnutils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;imap&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;allWindows&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;v&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;close&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;New Things Window&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Today&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;New Things Window&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;if&lt;/span&gt; &lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;findMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Show Sidebar&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Show Sidebar&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;selectMenuItem&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Anytime&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;quot;Things&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;Anytime&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;primaryScreen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;left70&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;quot;Things&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;Today&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;primaryScreen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;right30&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/4a743367871e56a6971566621ac635c09fb32ea7/spaces/review.lua#L11-L34"&gt;review.lua&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;This was a &lt;strong&gt;huge&lt;/strong&gt; time-saver, but there still were problems. I had trouble &amp;quot;resetting&amp;quot; my brain to address each Project with the same questions. Without a checklist I found I was easily distractable and the whole process easily took an hour or two.&lt;/p&gt;
&lt;p&gt;Finally, enough was enough. I rolled up my sleeves, pulled up &lt;a href="https://culturedcode.com/things/support/articles/2803573/"&gt;@culturedcode's documentation&lt;/a&gt;, and spent some quality hours in Apple's Script Editor to write the following. (It's long, so I'll break it up into sections.)&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-javascript" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;let&lt;/span&gt; &lt;span&gt;datestamp&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;new&lt;/span&gt; &lt;span&gt;Date&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toLocaleDateString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;en-US&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;let&lt;/span&gt; &lt;span&gt;review_proj&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;project&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;operation&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;create&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;attributes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;`Weekly Review: $&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;datestamp&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;`&lt;/span&gt; &lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;tags&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;Rituals&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;when&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;today&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I want to build a Things project for the Weekly Review ritual. All my &amp;quot;ritual&amp;quot; type projects/to-dos have the &amp;quot;Rituals&amp;quot; tag, so I add that tag and assign it to &amp;quot;Today&amp;quot;. I start to build the Weekly Review Project as a JSON object… and soon I'll add some &lt;code&gt;items&lt;/code&gt; to it for the to-do actions.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-javascript" tabindex="0"&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;items&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;lbrace&lt;/span&gt; &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;heading&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;attributes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt; &lt;span&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;Prep&amp;quot;&lt;/span&gt; &lt;span&gt;&amp;amp;rbrace&lt;/span&gt; &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I &lt;em&gt;love&lt;/em&gt; Things.app's headings feature, and I make quite a bit of use of it in this automation. Here's one for the &amp;quot;Prep&amp;quot; part, then the following to-dos.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-javascript" tabindex="0"&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;to-do&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;attributes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;📓: Review journal.&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;to-do&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;attributes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;✅: What did you accomplish?&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;notes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;things:///show?id=logbook&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;[&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;to-do&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;attributes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;Process your Things inbox. Assign each task to an area or to a project. Tag appropriately. (:estimate, $focus, !categorize, priority)&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;to-do&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;quot;attributes&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;Go through each of your projects. Use the checklists below.&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first things added to the Weekly Review project are the initial setup actions… reminders to gather all the sources of to-dos, review and prepare.&lt;/p&gt;
&lt;p&gt;Now it's time to gather all the projects to review! I wanted to build Peter's checklist as a to-do for all the Projects currently active in my Things.app, something like the following:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="" src="https://images.evantravers.com/articles/2020/07/single_project.png" /&gt;
  &lt;figcaption&gt;
    With this system, I at least have a checklist to go through for each project!
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Let's build it!&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;let&lt;/span&gt; &lt;span&gt;Things&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;Application&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Things&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;Things&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  for &lt;span&gt;(&lt;/span&gt;&lt;span&gt;area&lt;/span&gt; &lt;span&gt;of&lt;/span&gt; &lt;span&gt;Things&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;areas&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;review_proj&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&amp;quot;&lt;span&gt;attributes&lt;/span&gt;&amp;quot;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&amp;quot;&lt;span&gt;items&lt;/span&gt;&amp;quot;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;lbrace&lt;/span&gt; &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;heading&lt;/span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Projects&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot; + area.name() &amp;amp;rbrace &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;    )
&lt;/div&gt;&lt;div class="line"&gt;    for (proj of Things.projects().filter(p =&amp;gt; p.area() != null &amp;amp;&amp;amp; p.area().id() === area.id())) &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;      if (proj.status() == &amp;quot;&lt;/span&gt;&lt;span&gt;open&lt;/span&gt;&lt;span&gt;&amp;quot; ) &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;        review_proj[&amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;][&amp;quot;&lt;/span&gt;&lt;span&gt;items&lt;/span&gt;&lt;span&gt;&amp;quot;].push(
&lt;/div&gt;&lt;div class="line"&gt;        &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;          &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;          &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;            &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Review&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot; + proj.name(),
&lt;/div&gt;&lt;div class="line"&gt;            &amp;quot;&lt;/span&gt;&lt;span&gt;notes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;//&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;show?id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&amp;quot; + proj.id(),
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I'm using Things.app's JXA/Applescript dictionary to loop through Things.app internal database. First I loop through the &lt;code&gt;Things.areas()&lt;/code&gt; so that I can split up the Projects by area, then for each Project in &lt;code&gt;Things.projects()&lt;/code&gt; I add the checklist of questions from Peter Akkie's worksheet (with some modifications for my purposes, shortened for this post.):&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;            &lt;span&gt;&amp;quot;checklist-items&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;[&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;            &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;              &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;checklist&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;              &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;                &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Is&lt;/span&gt; &lt;span&gt;this&lt;/span&gt; &lt;span&gt;project&lt;/span&gt; &lt;span&gt;still&lt;/span&gt; &lt;span&gt;relevant?&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;              &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;            &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;            &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;              &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;checklist&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;              &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;                &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Can&lt;/span&gt; &lt;span&gt;I&lt;/span&gt; &lt;span&gt;delegate&lt;/span&gt; &lt;span&gt;this&lt;/span&gt; &lt;span&gt;project?&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;              &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;            &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;            &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;              &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;checklist&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;              &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;                &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Should&lt;/span&gt; &lt;span&gt;I&lt;/span&gt; &lt;span&gt;move&lt;/span&gt; &lt;span&gt;this&lt;/span&gt; &lt;span&gt;project&lt;/span&gt; &lt;span&gt;to&lt;/span&gt; &lt;span&gt;Someday?&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;              &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;            &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;            [...]
&lt;/div&gt;&lt;div class="line"&gt;            &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;              &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;checklist&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;item&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;              &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;                &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Is&lt;/span&gt; &lt;span&gt;there&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span&gt;clear&lt;/span&gt; &lt;span&gt;'next action'&lt;/span&gt; for &lt;span&gt;this&lt;/span&gt; &lt;span&gt;project?&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;If&lt;/span&gt; &lt;span&gt;not&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;break&lt;/span&gt; &lt;span&gt;down&lt;/span&gt; &lt;span&gt;your&lt;/span&gt; &lt;span&gt;projects&lt;/span&gt; &lt;span&gt;or&lt;/span&gt; &lt;span&gt;tasks&lt;/span&gt; &lt;span&gt;into&lt;/span&gt; &lt;span&gt;smaller&lt;/span&gt; &lt;span&gt;tasks&lt;/span&gt; until &lt;span&gt;there&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;a&lt;/span&gt; &lt;span&gt;clear&lt;/span&gt; &lt;span&gt;next&lt;/span&gt; &lt;span&gt;action&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;              &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;            &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;            ]
&lt;/div&gt;&lt;div class="line"&gt;          &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;        &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;        )
&lt;/div&gt;&lt;div class="line"&gt;      &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;    &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;rbrace
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that I'm done looping through the Projects, it's time to add the last actions related to the &amp;quot;Planning&amp;quot; time of the Weekly Review.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;  &lt;span&gt;review_proj&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;attributes&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;items&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;push&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;lbrace&lt;/span&gt; &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;heading&lt;/span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Plan&lt;/span&gt;&amp;quot; &amp;amp;rbrace &amp;amp;rbrace,
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I add another heading to the &lt;code&gt;items&lt;/code&gt;, and then the remaining to-dos.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &amp;quot;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;      &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Identify&lt;/span&gt; &lt;span&gt;what’s&lt;/span&gt; &lt;span&gt;due&lt;/span&gt; &lt;span&gt;soon&lt;/span&gt;&lt;span&gt;.&lt;/span&gt; &lt;span&gt;Use&lt;/span&gt; &lt;span&gt;the&lt;/span&gt; &lt;span&gt;Upcoming&lt;/span&gt; &lt;span&gt;view&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;    &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;      &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Identify&lt;/span&gt; &lt;span&gt;which&lt;/span&gt; &lt;span&gt;tasks&lt;/span&gt; &lt;span&gt;are&lt;/span&gt; &lt;span&gt;available&lt;/span&gt; &lt;span&gt;for&lt;/span&gt; &lt;span&gt;you&lt;/span&gt; &lt;span&gt;to&lt;/span&gt; &lt;span&gt;work&lt;/span&gt; &lt;span&gt;on&lt;/span&gt;&lt;span&gt;.&lt;/span&gt; &lt;span&gt;Use&lt;/span&gt; &lt;span&gt;the&lt;/span&gt; &lt;span&gt;Anytime&lt;/span&gt; &lt;span&gt;view&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;    &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;      &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;Plan&lt;/span&gt; &lt;span&gt;what&lt;/span&gt; &lt;span&gt;to&lt;/span&gt; &lt;span&gt;work&lt;/span&gt; &lt;span&gt;on&lt;/span&gt; &lt;span&gt;next&lt;/span&gt;&lt;span&gt;.&lt;/span&gt; &lt;span&gt;Assign&lt;/span&gt; &lt;span&gt;“when”&lt;/span&gt; &lt;span&gt;dates&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;as&lt;/span&gt; &lt;span&gt;you&lt;/span&gt; &lt;span&gt;learned&lt;/span&gt; &lt;span&gt;in&lt;/span&gt; &lt;span&gt;the&lt;/span&gt; &lt;span&gt;section&lt;/span&gt; &lt;span&gt;on&lt;/span&gt; &lt;span&gt;planning&lt;/span&gt; &lt;span&gt;your&lt;/span&gt; &lt;span&gt;days&lt;/span&gt; &lt;span&gt;and&lt;/span&gt; &lt;span&gt;weeks&lt;/span&gt;&lt;span&gt;.&lt;/span&gt; &lt;span&gt;Choose&lt;/span&gt; &lt;span&gt;important&lt;/span&gt; &lt;span&gt;tasks&lt;/span&gt; &lt;span&gt;as&lt;/span&gt; &lt;span&gt;well&lt;/span&gt; &lt;span&gt;as&lt;/span&gt; &lt;span&gt;urgent&lt;/span&gt; &lt;span&gt;ones&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;    &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;      &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;🖊&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;Build&lt;/span&gt; &lt;span&gt;spread&lt;/span&gt; for &lt;span&gt;next&lt;/span&gt; &lt;span&gt;week&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;    &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;rbrace,
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;do&lt;/span&gt;&lt;span&gt;&amp;quot;,
&lt;/div&gt;&lt;div class="line"&gt;    &amp;quot;&lt;/span&gt;&lt;span&gt;attributes&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;      &amp;quot;&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;/span&gt;&lt;span&gt;⭐️&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;What&lt;/span&gt; &lt;span&gt;is&lt;/span&gt; &lt;span&gt;essential&lt;/span&gt; &lt;span&gt;for&lt;/span&gt; &lt;span&gt;next&lt;/span&gt; &lt;span&gt;week?&lt;/span&gt;&lt;span&gt;&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;    &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;  &amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;  )
&lt;/div&gt;&lt;div class="line"&gt;  let url = &amp;quot;&lt;/span&gt;&lt;span&gt;things&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;//&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;json?data&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&amp;quot; + encodeURIComponent(JSON.stringify([review_proj]));
&lt;/div&gt;&lt;div class="line"&gt;  return url;
&lt;/div&gt;&lt;div class="line"&gt;&amp;amp;rbrace)();
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/2456c5efbdb06e6261eacbc7f8d7b1e4c90e97d7/spaces/weekly_review.lua#L11-L218"&gt;weekly_review.lua&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;That's it! You can take the &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/2456c5efbdb06e6261eacbc7f8d7b1e4c90e97d7/spaces/weekly_review.lua#L11-L218"&gt;whole JXA script&lt;/a&gt;) from me and deploy it however you want, but I use it as part of my &lt;a href="http://evantravers.com/articles/series/hammerspoon-headspace"&gt;Hammerspoon Headspace&lt;/a&gt; script:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;buildThingsProjectUrl&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;osascript&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;javascript&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;[[
&lt;/div&gt;&lt;div class="line"&gt;        (function() &amp;amp;lbrace
&lt;/div&gt;&lt;div class="line"&gt;           … (the JXA code above) …
&lt;/div&gt;&lt;div class="line"&gt;        &amp;amp;rbrace)()
&lt;/div&gt;&lt;div class="line"&gt;    ]]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;ok&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;url&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;buildThingsProjectUrl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;if&lt;/span&gt; &lt;span&gt;ok&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;something wrong with the jxa to build a review project.&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When I enter the Headspace, the JXA is run and the result is set to &lt;code&gt;url&lt;/code&gt;, which I then open using &lt;code&gt;hs.urlevent.openURL()&lt;/code&gt;. While I was troubleshooting the script, I made heavy use of Apple's Script Editor to debug because Hammerspoon kind of eats the JXA errors. If you want to see the whole thing in context, you can look &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/4a743367871e56a6971566621ac635c09fb32ea7/spaces/weekly_review.lua"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="" src="https://images.evantravers.com/articles/2020/07/weekly_review_overview.png" /&gt;
  &lt;figcaption&gt;The finished review: Prep, Projects, Planning, all separated by Headers and with appropriate checklists.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This fulfills a lot of my goals: the last few weekly reviews that I've timed have decreased from two hours to around 30 minutes, mostly because I don't lose my place. 😛 I also have started taking notes on the week in the notes of the individually created Projects, so that I can actually go look at last week's lessons in the Logbook by searching for &amp;quot;Weekly Review.&amp;quot; It &lt;em&gt;is&lt;/em&gt; dependent on being on my desktop, I don't believe there is anyway for the JXA to work on iOS.&lt;/p&gt;
&lt;p&gt;Not having a structured review was one of the main reasons that I have been tempted by the siren-call of Omnifocus. While this is a hack, and certainly one that is a little programmer-specific, it's enough to make me stay with Things.app for a while longer.&lt;/p&gt;
&lt;figure&gt;
	&lt;img src="https://images.evantravers.com/articles/2020/07/services.png" /&gt;
	&lt;figcaption&gt;You can use the script without any coding thanks to Automator!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you would like to use this script, and you aren't much of a coder, I've wrapped it in an Automator Service. You just &lt;a href="https://images.evantravers.com/articles/2020/07/Weekly%20Review.zip"&gt;download the Service&lt;/a&gt;, run it and it'll install in the Services menu of your Things.app.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-urls" id="fnref-urls"&gt;1&lt;/a&gt;&lt;/sup&gt; 👍&lt;/p&gt;
&lt;p&gt;&lt;a href="/contact"&gt;Let me know&lt;/a&gt; if you find this useful, or if you have something that you want changed for your particular use case. 🙏&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-urls"&gt;
&lt;p&gt;You may also have to set Enable Things URLs in the Settings.
&lt;img alt="things pref pane" src="https://images.evantravers.com/articles/2020/07/things_url.png" /&gt; &lt;a class="footnote-backref" href="#fnref-urls"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Sun, 05 Jul 2020 14:44:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/07/05/automating-my-weekly-review-in-things-app/</guid></item><item><title>PS2 RPI4 Part II: Internals</title><link>https://thomashunter.name/posts/2020-07-05-ps2-rpi4-internals</link><author>Thomas Hunter II</author><pubDate>Sun, 05 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thomashunter.name/posts/2020-07-05-ps2-rpi4-internals</guid></item><item><title>Use broot and meld to diff before commit</title><link>https://dystroy.org/blog/gg/</link><description>&lt;p&gt;Before every commit, I do a short review of what I wrote.
And usually there are a few last things to fix.&lt;/p&gt;</description><author>dystroy|Canop / blog</author><pubDate>Sun, 05 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dystroy.org/blog/gg/</guid></item><item><title>Create Dynamic meta-tags for your posts in NextJS</title><link>https://rajeevnaruka.com/blog/create-dynamic-meta-tags-for-your-posts-in-nextjs</link><description>Create dynamic meta-tags in your NextJS project using dynamic routing. Meta tags are specific HTML snippets of text and image content that provide a summary for your webpage to web-crawlers like Google-bot. These meta-tags affect how your webpages appear on Google search results or when someone shares a link on social media or in messaging.</description><author>Rajeev Singh Naruka</author><pubDate>Sun, 05 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://rajeevnaruka.com/blog/create-dynamic-meta-tags-for-your-posts-in-nextjs</guid></item><item><title>Recovering a Corrupted Crostini Image</title><link>https://reticulated.net/posts/crostinirecovery/</link><description>How to reecover from a corrupted Crostini Image in Chrome OS</description><author>Reticulated</author><pubDate>Sun, 05 Jul 2020 00:08:28 GMT</pubDate><guid isPermaLink="true">https://reticulated.net/posts/crostinirecovery/</guid></item><item><title>A simple primer on Modern Monetary Theory</title><link>https://stop.zona-m.net/2020/07/a-simple-primer-on-modern-monetary-theory/</link><description>&lt;p&gt;&amp;hellip; and my own main objection to it.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 04 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/a-simple-primer-on-modern-monetary-theory/</guid></item><item><title>How to easily implement successful remote team retrospectives</title><link>https://ilearnt.com/blog/fullyremoteretrospectives/</link><description>&lt;p&gt;As part of our processes we regularly hold retrospectives. We used to do this all in a room with post-it notes - a fairly traditional approach. We would set up 4 areas: Liked, Longed, Learned and Lacked and proceed to plaster post-it notes over the different sections. Once everyone had finished we would organise each section into themes and then discuss and agree actions.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Sat, 04 Jul 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/fullyremoteretrospectives/</guid></item><item><title>PostcardPop</title><link>https://briansunter.com/projects/postcardpop</link><description>Create and share beautiful digital postcards with custom images, messages, map stamps, and a copyable link.</description><author>Brian Sunter</author><pubDate>Sat, 04 Jul 2020 08:42:56 GMT</pubDate><guid isPermaLink="true">https://briansunter.com/projects/postcardpop</guid></item><item><title>PS2 RPI4 Part I: Restoration</title><link>https://thomashunter.name/posts/2020-07-04-playstation-2-raspberry-pi-restoration</link><author>Thomas Hunter II</author><pubDate>Sat, 04 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://thomashunter.name/posts/2020-07-04-playstation-2-raspberry-pi-restoration</guid></item><item><title>whoami</title><link>https://dystroy.org/blog/whoami/</link><description>&lt;p&gt;Here's a short map of my main identities (the ones which are related to software making, at least):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dystroy.org"&gt;dystroy&lt;/a&gt; is the umbrella covering all the me, and the brand of my freelance activity&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Canop"&gt;Canop&lt;/a&gt; is an open-source software writer&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dystroy.org/cv"&gt;Denys Séguret&lt;/a&gt; writes Rust for fun and profit, mainly on the backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You'll get news from me and my software on Mastodon (&lt;a href="https://mastodon.dystroy.org/@dystroy"&gt;@dystroy@mastodon.dystroy.org&lt;/a&gt;) and the best place to contact me is my &lt;a href="https://miaou.dystroy.org/3"&gt;Miaou chat&lt;/a&gt; during West European day.&lt;/p&gt;</description><author>dystroy|Canop / blog</author><pubDate>Sat, 04 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dystroy.org/blog/whoami/</guid></item><item><title>Love Is</title><link>http://spirals.blog/articles/love-is/</link><description>&lt;!--
&lt;p class='no-cap'&gt;
  “&lt;span class='color purple'&gt;Love&lt;/span&gt; is family; when we’re all together”
&lt;/p&gt;

&lt;p&gt;
  “&lt;span class='color red'&gt;Love&lt;/span&gt; is the strength to stand up for that which is beautiful.”
&lt;/p&gt;

&lt;p&gt;
  “&lt;span class='color blue'&gt;Love&lt;/span&gt; is the sacrifice for purity and the truth”
&lt;/p&gt;

&lt;p&gt;
  “&lt;span class='color orange'&gt;Love&lt;/span&gt; is boundless freedom to enjoy all that is here.”
&lt;/p&gt;

&lt;p&gt;
  “&lt;span class='color green'&gt;Love&lt;/span&gt; is the path to finding peace in your heart”
&lt;/p&gt;

&lt;p&gt;
  “&lt;span class='color yellow'&gt;Love&lt;/span&gt; is the knowledge that all things are one.”
&lt;/p&gt;

&lt;p&gt;
  “&lt;span class='color turquoise'&gt;Love&lt;/span&gt; is.”
&lt;/p&gt; --&gt;
&lt;p style="text-align: center;"&gt;
Love is family; when we’re all together.&lt;br /&gt;
Love is the strength to stand up for that which is beautiful.&lt;br /&gt;
Love is the sacrifice for purity and the truth.&lt;br /&gt;
Love is boundless freedom to enjoy all that is here.&lt;br /&gt;
Love is the path to finding peace in your heart.&lt;br /&gt;
Love is the knowledge that all things are one.&lt;br /&gt;
Love is.
&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sat, 04 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/love-is/</guid></item><item><title>Reversing Lyft's ride history API to analyze 6 years worth of rides</title><link>https://jonlu.ca/posts/reversing-lyft</link><description>Reverse-engineering Lyft's ride-history APIs to analyze six years of personal trips.</description><author>JonLuca's Blog</author><pubDate>Sat, 04 Jul 2020 02:20:34 GMT</pubDate><guid isPermaLink="true">https://jonlu.ca/posts/reversing-lyft</guid></item><item><title>Review: Orange Pi Zero</title><link>https://www.mikekasberg.com/blog/2020/07/03/review-orange-pi-zero.html</link><description>&lt;p&gt;&lt;a href="http://www.orangepi.org"&gt;Orange Pi&lt;/a&gt; is a relatively unknown competitor to
&lt;a href="https://www.raspberrypi.org/"&gt;Raspberry Pi&lt;/a&gt;. I recently learned about Orange Pi
while doing some research about a Raspberry Pi project I wanted to start, and I
actually ended up buying the &lt;a href="http://www.orangepi.org/orangepizero/"&gt;Orange Pi
Zero&lt;/a&gt;. Orange Pi is a Chinese company
that is focused on producing small PC boards – similar to Raspberry Pi – as
cheaply as possible. And Orange Pi produces a wider variety of boards than
Raspberry Pi, so perhaps one of their boards will fit your project better than a
Raspberry Pi would.&lt;/p&gt;

&lt;p&gt;To get a sense for what Orange Pi is, let’s start with a side-by-side comparison
of the &lt;a href="https://www.raspberrypi.org/products/raspberry-pi-zero-w/"&gt;Raspberry Pi Zero
W&lt;/a&gt; and the &lt;a href="http://www.orangepi.org/orangepizero/"&gt;Orange Pi
Zero&lt;/a&gt;.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;Raspberry Pi Zero W&lt;/th&gt;
      &lt;th&gt;Orange Pi Zero&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Price&lt;/td&gt;
      &lt;td&gt;$9.99&lt;/td&gt;
      &lt;td&gt;$11.49&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Power In&lt;/td&gt;
      &lt;td&gt;Micro USB&lt;/td&gt;
      &lt;td&gt;Micro USB&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Storage&lt;/td&gt;
      &lt;td&gt;Micro SD&lt;/td&gt;
      &lt;td&gt;Micro SD&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;CPU&lt;/td&gt;
      &lt;td&gt;1GHz BCM2835&lt;/td&gt;
      &lt;td&gt;1.2GHz Allwinner H2+&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;RAM&lt;/td&gt;
      &lt;td&gt;512MB&lt;/td&gt;
      &lt;td&gt;512MB&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Display Out&lt;/td&gt;
      &lt;td&gt;Mini HDMI&lt;/td&gt;
      &lt;td&gt;None/External Board&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Wifi&lt;/td&gt;
      &lt;td&gt;802.11 b/g/n 2.4GHz&lt;/td&gt;
      &lt;td&gt;802.11 b/g/n, but don’t use it&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Bluetooth&lt;/td&gt;
      &lt;td&gt;4.1&lt;/td&gt;
      &lt;td&gt;None&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Ethernet&lt;/td&gt;
      &lt;td&gt;None&lt;/td&gt;
      &lt;td&gt;10/100M RJ-45&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Micro USB&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;USB 2.0&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;As you can see, the boards are &lt;em&gt;very&lt;/em&gt; similar. The Raspberry Pi has a few
advantages – micro HDMI support, Bluetooth support, micro USB support, and it’s
$1.49 cheaper. But the Orange Pi &lt;em&gt;also&lt;/em&gt; has a few advantages – an Ethernet
port, standard USB port, and a slightly faster processor. As such, there’s no
clear winner. It depends on the project you want to use it for.&lt;/p&gt;

&lt;p&gt;Now, I see a lot of people using the Pi Zero W for a wide variety of projects
where it’s essentially functioning as an always-on LAN server. This might be a
file server, web server, &lt;a href="https://pi-hole.net/"&gt;Pi-Hole&lt;/a&gt;, internet camera, or
a similar LAN application. For many of these types of projects, I think the
&lt;strong&gt;Orange Pi Zero is actually a better choice.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You don’t need a display, so the micro HDMI is somewhat useless. Also, who
owns a micro HDMI cable?&lt;/li&gt;
  &lt;li&gt;For an always-on server, wired networking is a lot more reliable than
wireless. So the RJ-45 port is a major plus.&lt;/li&gt;
  &lt;li&gt;The Pi Zero W doesn’t even support 5Ghz wireless! Again, relying on Ethernet
is probably better here.&lt;/li&gt;
  &lt;li&gt;I think the standard USB port is a small plus - you’re less likely to need an
adapter.&lt;/li&gt;
  &lt;li&gt;The slightly faster CPU on the Orange Pi is nice.&lt;/li&gt;
  &lt;li&gt;As long as you’re not doing a Bluetooth-specific project, there’s no loss
there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For only $1.49 more, you get a lot of advantages with the Orange Pi for
a project like an always-on LAN server. I’ve been running an Orange Pi Zero as
an always-on LAN server for a couple months now, and it’s performed great! I had
problems with the wifi dropping out on the Raspberry Pi, and the Orange Pi
didn’t have the same problem because it’s wired to the LAN.&lt;/p&gt;

&lt;p&gt;Of course, the Orange Pi isn’t better across the board. In particular, if you’re
doing a project where you need Bluetooth or micro HDMI, the Raspberry Pi is the
obvious choice.&lt;/p&gt;

&lt;p&gt;Documentation for the Raspberry Pi is great, and you’ll find that it’s a little
bit harder to figure out the Orange Pi. But if you’re comfortable with computer
basics it’s not bad at all. You’ll want to use
&lt;a href="https://www.armbian.com/"&gt;Armbian&lt;/a&gt; – which is a lot like Raspbian but for a
broader range of devices. Once that’s set up, follow the “Linux” or “Debian”
installation instructions for whatever additional software you need.&lt;/p&gt;

&lt;p&gt;Should you use an Orange Pi your next project? At only $11.49 for the Orange Pi
Zero, I think it’s worth considering. If you do want to buy one, the best place
to do so is on
&lt;a href="https://www.aliexpress.com/item/1005001688034180.html"&gt;AliExpress&lt;/a&gt; or
&lt;a href="https://www.amazon.com/dp/B07ZYJGPF8"&gt;Amazon&lt;/a&gt;. You might find them in other
places as well, but the prices will probably be higher.&lt;/p&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Sat, 04 Jul 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/07/03/review-orange-pi-zero.html</guid></item><item><title>How I wrote 214 pages for a web development book with 19 pull requests in 3 months</title><link>https://www.mootoday.com/blog/how-i-wrote-214-pages-for-a-web-development-book-with-19-pull-requests-in-3-months</link><description>An in-depth journey report of the last three months when I wrote the Cloud Native Web Development book. Why did I write it? How did I develop the source code? Why do I self-publish? What has the post-publication experience been like?</description><author>www.mootoday.com - RSS Feed</author><pubDate>Fri, 03 Jul 2020 23:26:33 GMT</pubDate><guid isPermaLink="true">https://www.mootoday.com/blog/how-i-wrote-214-pages-for-a-web-development-book-with-19-pull-requests-in-3-months</guid></item><item><title>Why complete abolition of cash is BAD</title><link>https://stop.zona-m.net/2020/07/why-complete-abolition-of-cash-is-bad/</link><description>&lt;p&gt;(because it can forbid you spending YOUR money)&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 03 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/why-complete-abolition-of-cash-is-bad/</guid></item><item><title>Why Don't VCs Index Invest?</title><link>https://whoisnnamdi.com/vcs-index-invest/</link><description>VCs are picky, not because they have so many options but because they have so few.</description><author>Who is Nnamdi?</author><pubDate>Fri, 03 Jul 2020 19:54:02 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/vcs-index-invest/</guid></item><item><title>It's not about keyboards</title><link>https://dorotac.eu/posts/not_keyboard/</link><description>&lt;h1&gt;It's not about keyboards&lt;/h1&gt;
&lt;p&gt;My work on &lt;a href="https://source.puri.sm/Librem5/squeekboard/"&gt;Squeekboard&lt;/a&gt; and the corresponding Wayland protocols is open and public. That lets people come and contribute, and give feedback. Those people come with different expectations about the result of my work, and there's one that looks enticing but doesn't really correspond with what my work is about. It causes lots of confusion, so I would like to dispel it.&lt;/p&gt;
&lt;p&gt;Squeekboard's goal is not to be a &lt;em&gt;keyboard&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Instead, I designed Squeekboard and the pieces around it to support &lt;em&gt;text composition&lt;/em&gt; first and foremost. While a &lt;em&gt;keyboard&lt;/em&gt; is one method of composing text, it usually does other things as well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;playing musical notes&lt;/li&gt;
&lt;li&gt;turning things on and off&lt;/li&gt;
&lt;li&gt;shooting virtual monsters&lt;/li&gt;
&lt;li&gt;moving within virtual space&lt;/li&gt;
&lt;li&gt;instructing the computer to do arbitrary actions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Squeekboard doesn't want to do any of those things, unless they help composing text. To understand why, let's look at the basic properties of keyboards and Squeekboard. Keyboards&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;have labels which don't change&lt;/li&gt;
&lt;li&gt;have keys which stay in place and retain their shape forever&lt;/li&gt;
&lt;li&gt;have keys which sense force&lt;/li&gt;
&lt;li&gt;have keys which provide precise tactile feedback.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Meanwhile, Squeekboard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;occupies a changeable area of the screen&lt;/li&gt;
&lt;li&gt;has pixels which change color but not shape&lt;/li&gt;
&lt;li&gt;has touch points which overlap the display&lt;/li&gt;
&lt;li&gt;has touch points that capture "pressure".&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, they are very different beasts, with different constraints and abilities&lt;/p&gt;
&lt;h2&gt;It's just an app!&lt;/h2&gt;
&lt;p&gt;Squeekboard has some ability to emulate the keyboard buttons and register touches, so in principle it could share the goals of a keyboard. The key to understanding why this is not a useful useful goal is to realize that all of Squeekboard's unique abilities are the same as of any other graphical program.&lt;/p&gt;
&lt;p&gt;That gives us a new constraint: Squeekboard should not duplicate the functionality of the application it controls.&lt;/p&gt;
&lt;p&gt;A physical keyboard has it easy: touch feedback and less hand movement always adds value. But what can an on-screen one offer? Let's think about the interactions the user has with an application.&lt;/p&gt;
&lt;p&gt;The user might want to close or resize the application. That's easy, the compositor takes care of that. The user might want to issue an application-specific action, like rendering a scene, or moving the camera. Arguably, this is best handled by the application, which can present the relevant information. Commonly encountered actions like saving the file, copying or opening preferences are usually supported in a built-in way too. What does that leave us?&lt;/p&gt;
&lt;p&gt;Text input.&lt;/p&gt;
&lt;p&gt;Few applications give user an interface to enter text directly, making it the obvious responsibility of Squeekboard as an input method.&lt;/p&gt;
&lt;h2&gt;Extra powers&lt;/h2&gt;
&lt;p&gt;Dropping the preconception that an on-screen input method is a keyboard opens new possibilities for text input. Changing button shapes and numbers, presenting useful information in labels, offering corrections and suggestions, gestures, handwriting recognition, embedded input methods, and sending text directly to the application (not as button presses) are not things that can be done with just a matrix of buttons.&lt;/p&gt;
&lt;p&gt;While Squeekboard doesn't support many of those features, the groundwork for most of them is included in the Wayland protocols developed alongside it.&lt;/p&gt;
&lt;p&gt;Looking past the historically proven idea of a keyboard opens a different view on how touch-based human-computer interfaces should work, and Squeekboard is there to make best use of the new possibilities.&lt;/p&gt;</description><author>dcz's posts</author><pubDate>Fri, 03 Jul 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/not_keyboard/</guid></item><item><title>Lessons and Regrets from My $25000 Book Launch</title><link>https://www.swyx.io/coding-career-launch</link><description>Reflections on the Coding Career book launch</description><author>swyx's site RSS Feed</author><pubDate>Fri, 03 Jul 2020 07:06:47 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/coding-career-launch</guid></item><item><title>Modernized JavaScript 90’s Cursor Effects, that we all know and love</title><link>https://tholman.com/post/cursor-effects/</link><description>Bringing those beloved cursor effects into the modern age.</description><author>The Curious Creations of Tim Holman</author><pubDate>Fri, 03 Jul 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://tholman.com/post/cursor-effects/</guid></item><item><title>Why Backwards Compatibility is Critical</title><link>/backwards-compatible/</link><description>&lt;p&gt;Backwards compatibility is not something I see discussed much in tech circles. It's all new-new-new, fast-fast-fast. Piling features on top of one another and tightly coupling releases between services. Previously Facebook, the &lt;a href="https://www.alexa.com/topsites"&gt;4th most popular site on the internet&lt;/a&gt; no less, had the mantra of &amp;quot;move fast and break things&amp;quot;.
These are the kinds of sentiments I see all around me, particularly from startup and SaaS companies. I've always felt that coupling releases too closely was insanity inducing and seen first hand how corrosive they were to a customer experience of the product.&lt;/p&gt;
&lt;p&gt;But the web hasn't always been like this. The core backbone of the internet, in the form of TCP/IP, DNS, HTTP and even HTML and CSS, has been unchanged for many years - or at least changed in manner that doesn't break previous versions. As an example, both &lt;a href="http://spacejam.com"&gt;Space Jam's website&lt;/a&gt; and &lt;a href="http://www.milliondollarhomepage.com/"&gt;Million Dollar Homepage&lt;/a&gt; both still function on modern browsers, having been created in 1996 and 2005 respectively.
So what happened? There isn't one conclusive answer to this, more a prevailing zeitgeist amongst developers and product managers. But in my view, it's due to the large investment that technology has seen over the past 20 years. It's grown exponentially.
With that, we have seen bad business practises, ill thought out ideas and customers that are keeping a company afloat. These things existed before, but now manifest themselves in the technology that these organisations build.
Additionally, products are architected around small services given a single responsibility. Previously, the web was simple - throw a LAMP stack on a server somewhere and bobs your uncle. There were a lot less moving parts.&lt;/p&gt;
&lt;p&gt;Now this isn't going to be a nostalgic post where we reminisce the days of the &amp;quot;good ol' web&amp;quot; or something, because I find that all a bit petty. I want to discuss how we need to build things to last and practical ways to do that in the face of &amp;quot;moving fast&amp;quot; (side note: watch Bryan Cantrill's fantastic talk on the principles of tech leadership &lt;a href="https://www.youtube.com/watch?v=9QMGAtxUlAc"&gt;here&lt;/a&gt;)&lt;/p&gt;
&lt;h1&gt;But why do developers avoid making things backwards compatible?&lt;/h1&gt;
&lt;p&gt;This article wouldn't exist if there wasn't at least 1 answer to this question.
Primarily it boils down to &amp;quot;it's more effort&amp;quot;. If you're making a major change to a service, and you have all other teams that consume or otherwise use this service in some way to also make the needed change then it's reasonable to assume you don't really need the old system. And potentially more work to maintain it.
Your team may also not even have a &amp;quot;versioning&amp;quot; strategy in place. I've sat in meetings well over 5 hours of meetings about how to version services with no outcome. A lot of people have opinions about this, and often, developers seem more intent on arguing the others point rather than accomplishing the objective behind the change.
Furthermore, there have arguably been a number of failures in attempting to preserve backwards compatibility such as with Java and SQLite3.
These challenges can be major roadblocks in creating stability and backwards compatibility in your products services.&lt;/p&gt;
&lt;h1&gt;Why is it important then?&lt;/h1&gt;
&lt;p&gt;First we need to clarify that preserving backwards compatibility is not about holding onto legacy. If something is old, busted, broken or unused, then by all means, pave over it and start afresh. There's no need to attach infinite eels to yourself to support absolutely every single use case of your service. Things change as software changes. It's natural.
On the other hand, backwards compatibility is about not creating unnecessary work for hundreds of your users every time you make a change. Or coupling releases so tightly that everything has to be deployed at exactly the same time and caches flushed in sync. Or having no deprecation plan and changing external interfaces constantly.&lt;/p&gt;
&lt;p&gt;Stripe treads this line very careful (however, I am unaware of the overall experience as a developer there). Being a payments processor, there has to be certain guarantees about how things will be handled.
To accomplish this, Stripe use a date versioned API system. You get assigned the latest versioned API when you create an account and can easily update the API if you so wish. But you also have the option to leave it completely. In fact, there are still websites I built a few years ago with now old Stripe integrations that tick along fine. They have a great post about their versioning mechanism &lt;a href="https://stripe.com/blog/api-versioning"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How to do it&lt;/h1&gt;
&lt;p&gt;You might assume that because you use a /v1 and /v2 in your endpoints you're all set right? Well, not so fast. Ultimately, as humans we are subject to reason about things that we ourselves cannot fully understand. Therefore, what constitutes a major version bump for some, may not be for others.
So how can you do it?&lt;/p&gt;
&lt;h2&gt;1. General coding practise&lt;/h2&gt;
&lt;p&gt;If you're changing something minor like the name of a parameter on an interface or the type, then there is the possibility that you can support the old method by casting it to the new type and so forth. There are many general coding practises that allow your code to be bug hardened whilst not introducing lots of spaghetti.
Additionally, a good starting point for all backwards compatible changes is to mark the &amp;quot;old&amp;quot; code with a &amp;quot;deprecation&amp;quot; warning of some kind so that other developers in your team know not to use that code any more.&lt;/p&gt;
&lt;h2&gt;2. Documentation and Deprecations&lt;/h2&gt;
&lt;p&gt;If you're going to make a breaking change to something, you need a way to communicate that to the consumers of your product and you need to tell them how to update if they absolutely cannot be held on the previous version for some reason.
You can do this by giving the customer, plenty of warning via email, an account manager or a deprecation warning in the response. You could have a system whereby, when a deprecated API method is called, it logs it to a table. Each day, the table can then be scanned and you can tell the customer &amp;quot;You called X route which has been deprecated and will no longer receive updates, please see N website for documentation on how to update&amp;quot;.
Hand-in-Hand with this goes a clear policy on how long you will support &amp;quot;deprecated&amp;quot; routes. Depending on the market you're in that could be a few months or a few years. Either way, be clear to your customers. Again, Stripe does a pretty good job of saying &amp;quot;you can use this near indefinitely&amp;quot; and including that as part of its marketing to developers.&lt;/p&gt;
&lt;h2&gt;3. Pivoting&lt;/h2&gt;
&lt;p&gt;If making something backwards compatible has become so incredibly painful that you'd rather play hopscotch on a floor of hot coals, then you need to ask if the service has pivoted to a point where it's potentially a whole new thing.
As an example of this, I created a service for a messaging application that kept track of when a customer had last read a particular message. However, it then needed the functionality to manage if the customer had left a group message and then if the customer had muted the messages and so on. Before you knew it, it was no longer an API for managing if the customer had read a message or not but more a fully fledged notifications API.
In retrospect, I should have seen this inevitability. But the service had devolved to a point where it wasn't anything like the original. Although it was an internal only service, it's something that looking back I should have redone and gradually migrated over to the new service.
Although this may not be preserving the backwards compatibility in a true sense, as long as you provide a sensible upgrade path and don't immediately shutdown the old service then it's ok in my books.&lt;/p&gt;
&lt;h2&gt;4. Versioning&lt;/h2&gt;
&lt;p&gt;We've touched on this a few times in this post, and arguments about different versioning strategies has been talked about since time began.
I'm not going to provide any guidance on which one is best or which one should you chose - simply decide on one as a team and agree upon clear definitions about what constitutes a version upgrade. Then include this as part of your release strategy.
If you work with continuous deployment then perhaps look at something similar to Stripe or a Semver strategy that goes beyond a &amp;quot;/v1&amp;quot; and &amp;quot;/v2&amp;quot; route structure (although may include it).
It will depend on a few factors
_ Expectations of the market you are in - how long do you customers expect to use your product and forget about the implementation - hint it's often longer than you think
_ What is your release cycle like? - if it's daily then you need something to automate the process, if it's each decade where you pack your software onto a disc then it can be something manual * Do you have a lot of third party consumers - if there consumers to your service that go beyond your company then you will have different requirements about deprecation etc.&lt;/p&gt;
&lt;p&gt;TL;DR - Pick one and go with it. You can even pick different mechanism for different services!&lt;/p&gt;
&lt;h2&gt;5. Limit dependencies&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Mo' Dependencies, mo' problems - Notorious D.E.V&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By limiting the number of dependencies you use, versioning will be easier because you no longer need to provide constant security updates and check if every last version of your software works with it.
The Node community is particular bad at this one, and often does provide security and bug fixes down stream and instead just forces everyone to upgrade to the latest version. We can do better than this. But we make our lives a lot easier by reducing dependencies.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;There are lots of arguments against backwards compatibility and I can understand why. Personally speaking, I want to build to last. I'd like to think that in 10 years time I could still use my products without having to change the integration.
Something about seeing the spacejam website just sort of fills me with a warm glow of a moment in time that is accessible at any point.&lt;/p&gt;</description><author/><pubDate>Fri, 03 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/backwards-compatible/</guid></item><item><title>Fundamental computer science concepts every software developer should know</title><link>https://jasoneckert.github.io/myblog/fundamental-comp-sci/</link><description>&lt;p&gt;To be a software developer (a.k.a. programmer or software engineer) today, you don&amp;rsquo;t need a degree in computer science. In fact, computer science really isn&amp;rsquo;t about &amp;ldquo;how&amp;rdquo; you develop software today at all. It&amp;rsquo;s about how we approach software problems theoretically. And to be frank, you don&amp;rsquo;t need to worry about computer science theory to be a good software developer today. You just need to know how to solve problems using code, be good at using existing software frameworks, as well as know how to Google stuff and read programming language documentation.&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Fri, 03 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/fundamental-comp-sci/</guid></item><item><title>Video tutorials considered harmful</title><link>https://stop.zona-m.net/2020/07/video-tutorials-considered-harmful/</link><description>&lt;p&gt;Sometimes, 1000 words are worth much more than their video.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 02 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/video-tutorials-considered-harmful/</guid></item><item><title>The Platform</title><link>https://olshansky.info/movie/the_platform/</link><description>Olshansky's review of The Platform</description><author>🦉 olshansky 🦁</author><pubDate>Thu, 02 Jul 2020 20:09:51 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/the_platform/</guid></item><item><title>The Girl on the Train</title><link>https://arunmani.in/library/the-girl-on-the-train/</link><description>Fantastic thriller with a nice twist at the end.</description><author>Arun Mani</author><pubDate>Thu, 02 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://arunmani.in/library/the-girl-on-the-train/</guid></item><item><title>Harvard Decision For 2020 21 Academic Year</title><link>/2020/07/02/Harvard-Decision-for-2020-21-Academic-Year.html</link><description>Thoughts:</description><author>rrich.io</author><pubDate>Thu, 02 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/2020/07/02/Harvard-Decision-for-2020-21-Academic-Year.html</guid></item><item><title>5.15 Card Game Successfully Kickstarted</title><link>https://www.csun.io/2020/07/02/5.15-card-game-kickstarter.html</link><description>My cousins made a card game!</description><author>Cameron Sun</author><pubDate>Thu, 02 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.csun.io/2020/07/02/5.15-card-game-kickstarter.html</guid></item><item><title>Disentanglement Theory</title><link>http://spirals.blog/articles/disentanglement/</link><description>&lt;blockquote&gt;
&lt;p&gt;Author’s note:
If you’ll permit me, I’d like to try an experimental approach to writing articles than I’m used to. This is a play on an idea that I’m not entirely sure is correct yet. It’s an opinion, it’s in “beta”, and it could be wrong. Thank you for reading.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Think of a problem you have in your life. It could be anything. A turf war at work. Something your partner is doing. Maybe you feel like shit all the fucking time. Perhaps you're lonely, or confused about life, or bored with everything, or feel like nobody understands you or one of ALL the other problems we face. That makes you the same as everyone else. That makes you human.&lt;/p&gt;
&lt;p&gt;Just get to the point: &lt;a href="#diagram"&gt;GO TO THE VISUAL 👀&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Well, great then. We’re all a LOT more alike than we want to admit. Or, in some cases, know. The truth is, we are all very bloody similar. We’re not that different in what we’re experiencing. We know this because of foreign films. And art. And sad love songs written in every language, that ever existed; ever. The stories and the myths that we all try to live and re-enact in our own lives. All of it. We suffer together. We suffer the same. It might look different on the surface, but humans suffer the same ways everywhere.&lt;/p&gt;
&lt;p&gt;So what do we do about it? We’ve all got these “hairy-scaries”. Can we fix them? Can we do something to win the budget at work? Fix our partner? Instantly make ourselves feel better? Sometimes, yes, and sometimes this is a &lt;em&gt;&lt;strong&gt;very&lt;/strong&gt;&lt;/em&gt; bad idea. But what else makes sense to do? &lt;strong&gt;If we’re taking responsibility&lt;/strong&gt;, we look inwards, not outwards.&lt;/p&gt;
&lt;h2&gt;“I wanted to change the world”&lt;/h2&gt;
&lt;h3&gt;AKA: “I wanna fix my shit yo”&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;When I was a young man, I wanted to change the world.&lt;/p&gt;
&lt;p&gt;I found it was difficult to change the world, so I tried to change my nation.&lt;/p&gt;
&lt;p&gt;When I found I couldn’t change the nation, I began to focus on my town. I couldn’t change the town, and as an older man, I tried to change my family.&lt;/p&gt;
&lt;p&gt;Now, as an old man, I realize the only thing I can change is myself, and suddenly I realize that if long ago I had changed myself, I could have made an impact on my family. My family and I could have made an impact on our town. Their impact could have changed the nation, and I could indeed have changed the world.&lt;/p&gt;
&lt;p&gt;Author: Unknown Monk, 1100 A.D.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Understanding and acceptance&lt;/h2&gt;
&lt;p&gt;I propose we may fix our problems in life by:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Understanding ourselves and the world&lt;/li&gt;
&lt;li&gt;Accepting ourselves and the world&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These become the two components that make up our exercise. Understanding and accepting. Just the two. Let’s delve deeper.&lt;/p&gt;
&lt;p&gt;I heard once on the &lt;a href="https://tim.blog/2020/05/18/jim-dethmer/"&gt;Tim Ferris show&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The path to peace is not through greater understanding but greater acceptance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If that one was your’s, Tim, then good on ya. That’s a good one.&lt;/p&gt;
&lt;p&gt;It got me thinking; &lt;strong&gt;a lot&lt;/strong&gt;. As someone who is CONSTANTLY overthinking, I also understand the benefits of and practice regularly, states of awareness - like meditation. This was a much-needed puzzle piece. I wasn’t putting the two together. Tools like Spiral help you understand things, but they &lt;em&gt;in themselves&lt;/em&gt; don’t bring peace. &lt;strong&gt;We must first understand, then learn to accept what we know to be true.&lt;/strong&gt; &lt;a href="https://www.franklincovey.com/the-7-habits/habit-5.html"&gt;Seek first to understand before being understood.&lt;/a&gt; Then there comes a time where understanding is limiting you. You’re overthinking it, scrutinizing it too much, and not letting yourself truly “allow” it. We need to accept it.&lt;/p&gt;
&lt;p&gt;Like Spiral, this applies to macro and micro. But we’re going to focus on the micro. Us. You. Me. The shit we got goin’ on in our lives.&lt;/p&gt;
&lt;p&gt;This is where I came up with an idea that I wanted to share. It’s called Disentanglement.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://spirals.blog/articles/disentanglement/disentanglement.jpg" id="diagram" target="_blank"&gt; &lt;img alt="Disentanglement theory" src="http://spirals.blog/articles/disentanglement/disentanglement.jpg" /&gt; &lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Disentanglement&lt;/h2&gt;
&lt;p&gt;Here are the major ideas:&lt;/p&gt;
&lt;h3&gt;1. The Story&lt;/h3&gt;
&lt;p&gt;We all bullshit. Don’t pretend you don’t. Unless we’re near enlightened, live 10000% in a place where we’ve transcended personal ego, and kissed the feet of gods - we bullshit.&lt;/p&gt;
&lt;p&gt;What’s that mean? It means we tell stories that we &lt;em&gt;think&lt;/em&gt; are true, maybe even &lt;em&gt;&lt;strong&gt;believe&lt;/strong&gt;&lt;/em&gt; are true; and aren’t.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“I can’t leave the country because it’s too dangerous”&lt;/li&gt;
&lt;li&gt;“She’ll never like me because I’m too nerdy”&lt;/li&gt;
&lt;li&gt;“I’m not good enough for that job”&lt;/li&gt;
&lt;li&gt;“I feel like shit”&lt;/li&gt;
&lt;li&gt;&amp;quot;&amp;lt;insert race here&amp;gt;’s are just here to take our jobs&amp;quot;&lt;/li&gt;
&lt;li&gt;“I need more money”&lt;/li&gt;
&lt;li&gt;“Nobody understands me”&lt;/li&gt;
&lt;li&gt;“Unless my hair looks EXACTLY like this, random people who I don't know will think I'm ugly and I'll feel terrible for the rest of the day and probably end up crying”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dude.&lt;/p&gt;
&lt;p&gt;They’re all stories. Are they objectively true, without a scrap of doubt, undeniably representative of all realities? Probably not. They’re made up of a messy tangle of other stories. And those stories are further messed up balls of crap. And so on, until you reach the thread, then the end of the thread, where things stop – and you discover the truth.&lt;/p&gt;
&lt;p&gt;What pains us, what we feel 99% of the time, what we believe is just a mixed-up bunch of other things. All are rolling around and getting more tangled up. &lt;strong&gt;Disentanglement is the process of slowly “un-knotting” all the stories, beliefs, “truths”, customs, etc. until we get to the truth of the matter.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;2. Understanding&lt;/h3&gt;
&lt;p&gt;How do we “disentangle” ourselves? Carefully trace each string until you come to a knot.&lt;/p&gt;
&lt;p&gt;&lt;img alt="What?" src="http://spirals.blog/articles/disentanglement/what.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Ask questions. Hard ones. Deep ones. &lt;em&gt;Personal&lt;/em&gt; ones. Ones that hurt. Ones that pierce the vulnerable comfort layer we all got goin’ on and say, “Hey, you’ve got some work to do”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Why?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s my favorite question. Why?&lt;/p&gt;
&lt;p&gt;Shutup.&lt;/p&gt;
&lt;p&gt;“Why” is like a shovel – it digs deeper. &lt;em&gt;It forces the brain to consider the nature of what we think is the core of something.&lt;/em&gt; Why? Because in order to explain something, you need to know it’s components. And in order to identify the components, you need to “chunk into it”, go further in.&lt;/p&gt;
&lt;p&gt;“Why” in the visual context of Disentanglement creates the force to go deeper. It’s your “momentum” if you will. What about direction then?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Where is this coming from?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What are the “things” that make this problem up? If “why” goes deep, “where from” then &lt;em&gt;&amp;quot;goes broad&amp;quot;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Understanding" src="http://spirals.blog/articles/disentanglement/understanding.png" /&gt;&lt;/p&gt;
&lt;p&gt;There are many other questions you could ask. What can you think of?&lt;/p&gt;
&lt;h3&gt;3. Acceptance&lt;/h3&gt;
&lt;p&gt;Here is the kicker, and just when you thought all the work was done. You cried or screamed, or sat there in disbelief and yet the most important, hardest part was still coming. Accepting it.&lt;/p&gt;
&lt;p&gt;But hold on, this isn’t always what you think. Accepting can be reframing it, seeing it from a different perspective, coming to a realization that you were wrong about someone or something. Accepting can be a beautiful, enlightening, aha moment.&lt;/p&gt;
&lt;p&gt;Other times it can be one of the hardest, longest marathons you’ve run. If that’s the case, dig deeper. You’re still entangled. Rinse and repeat.&lt;/p&gt;
&lt;p&gt;How do we “accept” something? &lt;em&gt;“Is this some zen/yoga/meditation bullshit?”&lt;/em&gt; Yeah, kinda.&lt;/p&gt;
&lt;p&gt;Acceptance may be a little different from what you’ve experienced before – it comes from understanding deeply. It’s not a blind, “do what you will”, “throw caution to the wind”, “let go of this reality” kind of thing. It’s a &lt;strong&gt;felt empathy&lt;/strong&gt; - to all parts of what the situation is. We need the understanding to &lt;em&gt;&lt;strong&gt;know&lt;/strong&gt;&lt;/em&gt; all the pieces. But then we take it a step further and try to, even if for a moment, &lt;em&gt;&lt;strong&gt;be&lt;/strong&gt;&lt;/em&gt; all the pieces.&lt;/p&gt;
&lt;p&gt;We integrate all the perspectives into our world view. We take the best of each one, recognizing that no “one thing” is 100% true, and bring it “into us”. It’s a stunning, freeing, feeling that leaves one far more peaceful and lighter.&lt;/p&gt;
&lt;p&gt;It often comes about, or results in some kind of “reframe”. Seeing things in a different light can turn your worst enemy into your best friend. Sometimes this is just the shift we needed to “love that part of ourselves” or “really appreciate what the other person was saying”.&lt;/p&gt;
&lt;p&gt;Here are some questions/tools to cultivate more acceptance in things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“How do I know it’s true?”&lt;/li&gt;
&lt;li&gt;“How many ways do I know it’s NOT true?&lt;/li&gt;
&lt;li&gt;“If there was something about this that was positive, that I’m not yet seeing, what would it be?”&lt;/li&gt;
&lt;li&gt;“If it wasn’t true, how would my life look?”&lt;/li&gt;
&lt;li&gt;“Is this belief mine, or is it something given to me?”&lt;/li&gt;
&lt;li&gt;“What am I protecting right now?”&lt;/li&gt;
&lt;li&gt;“When did I first decide to believe that?”&lt;/li&gt;
&lt;li&gt;“Where do I feel this on my body right now? What’s it doing?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These questions “loosen” the tangle, allowing you to accept something (a root cause or belief) or go deeper into it.&lt;/p&gt;
&lt;p&gt;Sometimes you’ll uncover something so powerful it knocks you on your ass. Literally. These might be the “end of the thread” kinda realizations. They can feel incredible, and they can feel terrible. But they’re often very intense. Not always, of course, but often. &lt;strong&gt;It’s the difference between an “Aha!”, and an “Ohhhhhh fuck…”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;They’re regularly the root cause of something. Something that happened a long time ago, usually in the imprint period (0~7 years old). A defensive mechanism, a way of handling a problem that you never bothered to change, an automatic behavior. There are thousands and thousands of these. Some work for us, some don’t.&lt;/p&gt;
&lt;h2&gt;The Path to Peace&lt;/h2&gt;
&lt;p&gt;Disentanglement Theory is an attempt to get to the bottom of things, The &lt;em&gt;&lt;strong&gt;real&lt;/strong&gt;&lt;/em&gt; bottom, and then heal it. It requires courage, patience, empathy, love, strength, and intuition. It builds emotional intelligence, your sense of love for yourself and the world, deeper happiness, and a generally pretty chillin’ vibe. It’s sweet.&lt;/p&gt;
&lt;p&gt;As always, I would love to know your thoughts. After all, no idea is entirely true, right?&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I will end this with a quote from Gandhi on the matter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“There is no path to peace - Peace is the path.”
~ Mahatma Gandhi&lt;/p&gt;
&lt;/blockquote&gt;</description><author>A Matter of Perspective</author><pubDate>Thu, 02 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/disentanglement/</guid></item><item><title>Socially Distant Polygons</title><link>https://nickp.svbtle.com/socially-distant-polygons</link><description>&lt;p&gt;Imagine a polygon, like the blue one below. Where should you stand in that polygon such you are as far as possible from your nearest vertex? This seems like a useful thing to be able to calculate in 2020 (hope this blog post ages well). Ostensibly this should be easy to compute too, but it’s not obviously that the red dot in the image below is in fact the furthest point from any of the polygon vertices. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/eJ25xLUH9siqT4PiRdsYFb0xspap.png"&gt;&lt;img alt="Screenshot 2020-07-01 15.14.55.png" src="https://svbtleusercontent.com/eJ25xLUH9siqT4PiRdsYFb0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A first guess might be to stand half the longest edge length away from one of the vertices. But unfortunately that doesn’t work. If you try a square you’ll see it’s best to stand in the centre which is slightly further away from each corner. This shows that we need to consider points on the interior of the polygon to make sure they are covered too. Stated another way we are trying to calculate the minimum radius circle &lt;code class="prettyprint"&gt;R&lt;/code&gt;, such that the area of the union of circles positioned at &lt;code class="prettyprint"&gt;(xi, yi)&lt;/code&gt; the vertices each having &lt;code class="prettyprint"&gt;R&lt;/code&gt; have the same area as the polygon &lt;code class="prettyprint"&gt;P&lt;/code&gt;.  If the radius is too small the polygon won’t be covered and just as the area completely coverage the polygon. That very last point is the point we are searching for. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/x9cU4ZZRdWGKHFACMiNTnZ0xspap.png"&gt;&lt;img alt="Screenshot 2020-07-01 15.12.32.png" src="https://svbtleusercontent.com/x9cU4ZZRdWGKHFACMiNTnZ0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If we write this area of the union or the circle as a function of &lt;code class="prettyprint"&gt;R&lt;/code&gt; then &lt;code class="prettyprint"&gt;UnionArea(R)&lt;/code&gt; will be monotonic, namely if &lt;code class="prettyprint"&gt;R1 &amp;lt; R2&lt;/code&gt;, then &lt;code class="prettyprint"&gt;UnionArea(R1) &amp;lt;= UnionArea(R2)&lt;/code&gt;. This nice yields a short solution, where we try increasing values of &lt;code class="prettyprint"&gt;R&lt;/code&gt; until the &lt;code class="prettyprint"&gt;UnionArea(R) == Area(P)&lt;/code&gt;. Keep increasing &lt;code class="prettyprint"&gt;R&lt;/code&gt; until we’ve filled up the polygon with orange (union of circle) and as so as we have done so, stop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/6nTimmsvwf6WPmbGW9ARhs0xspap.gif"&gt;&lt;img alt="output.gif" src="https://svbtleusercontent.com/6nTimmsvwf6WPmbGW9ARhs0xspap_small.gif" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Knowing the function is monotonic we can do a binary search over the range &lt;code class="prettyprint"&gt;R = {0 .. MAX}&lt;/code&gt;, and we want the smallest value of &lt;code class="prettyprint"&gt;R&lt;/code&gt; which covers 100% of the polygon.&lt;/p&gt;

&lt;p&gt;This is easy enough to code but computing the union of thousands of circles gets very complicated and slows things down. Although it’s short to code using a computational geometry library, this solution quickly falls over for polygons like this horror:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/cG2rZZMwXvw1Cs7NvHryd30xspap.gif"&gt;&lt;img alt="output.gif" src="https://svbtleusercontent.com/cG2rZZMwXvw1Cs7NvHryd30xspap_small.gif" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s look at this again. We are searching for the point inside the polygon that is further away from any vertex. If we can construct a region around each vertex where all points inside that region are nearest to that vertex then the furthest point is going to lie somewhere on the boundary of those regions. &lt;/p&gt;
&lt;h2 id="voronoi-diagrams_2"&gt;Voronoi Diagrams &lt;a class="head_anchor" href="#voronoi-diagrams_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The problem of decomposing space into regions containing a set of points such that each point in a region is nearest to that point is called a Voronoi decomposition. Here’s what it looks like for a polygon’s vertices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/7WthKpvq5m5Ndk3c4adQUc0xspap.png"&gt;&lt;img alt="Screenshot 2020-07-01 16.38.36.png" src="https://svbtleusercontent.com/7WthKpvq5m5Ndk3c4adQUc0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let’s try and compute the Voronoi diagram for a set of points. A naive approach is to iterate through each point, then for each other point we find the perpendicular bisector which delineates a half plane, collecting the union of these half planes gives us these regions around each point. In the following image region is being constructed around the red vertices. The green points are the midpoint of the red vertex with all the other vertices of the polygon. These lie on the perpendicular bisector that delineates the half-planes which are show in green. Any point that isn’t in one of these half-planes is nearer to the red vertex than any other vertex. This is the red region, in this case only shown inside the polygon. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/fkAxpawhW7sdnaWkw6uPfA0xspap.png"&gt;&lt;img alt="Screenshot 2020-07-01 15.48.32.png" src="https://svbtleusercontent.com/fkAxpawhW7sdnaWkw6uPfA0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Performing this operation for all vertices of the polygon will give the decomposition of space within the polygon which looks like this. Again any point inside a red region is nearer to the polygon vertex inside that same region than any other polygon vertex.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/sj2Upcqa6Muvoz2q9muEpA0xspap.png"&gt;&lt;img alt="Screenshot 2020-07-01 15.53.23.png" src="https://svbtleusercontent.com/sj2Upcqa6Muvoz2q9muEpA0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This works well but again we are maintaining a growing set of half-planes, which while simpler than the circle still gets too complicated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/wA6GUjyKWz32qyE9fyyPnW0xspap.gif"&gt;&lt;img alt="output.gif" src="https://svbtleusercontent.com/wA6GUjyKWz32qyE9fyyPnW0xspap_small.gif" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which yields&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/p6AzRRd49JNzMvBPGg2fio0xspap.jpg"&gt;&lt;img alt="movie-016.jpg" src="https://svbtleusercontent.com/p6AzRRd49JNzMvBPGg2fio0xspap_small.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Possibly the best way to compute the Voronoi diagram is to use Fortune’s algorithm. It is such an elegant algorithm to watch as it directly traces out the regions while sweeping from bottom to top. &lt;a href="https://www.youtube.com/watch?v=rvmREoyL2F0"&gt;This is what I mean!&lt;/a&gt; Fortune’s algorithm works but sorting the vertices from bottom to top and processing them in order. While doing so it maintains a piece-wise parabola that looks like the beach which describes regions nearest to the points currently under consideration. The algorithm uses a balanced tree structure to maintain the beach line and a priority queue for updating and accessing the next even. As a result it can compute the Voronoi decomposition in &lt;code class="prettyprint"&gt;O(n log n)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="aside_2"&gt;Aside &lt;a class="head_anchor" href="#aside_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is a very interesting correspondence between three core algorithms in computational geometry: Voronoi diagrams, Delaunay triangulations and convex hulls. We’ve already described Voronoi diagrams. The convex hull of a set of points is the minimum area convex polygon that encloses. This concept generalizes to more than two dimensionals. One way of computing the Voronoi regions in two dimensions that is fun to think about is to start with the 2D vertices &lt;code class="prettyprint"&gt;(xi, yi)&lt;/code&gt; and turn them into 3D coordinates by “lifting” them onto a parabola by adding &lt;code class="prettyprint"&gt;zi = xi^2 + yi^2&lt;/code&gt;. So now you have a bunch of 3D coordinates of the form &lt;code class="prettyprint"&gt;(xi, yi, xi^2 + yi^2)&lt;/code&gt;. Compute the convex hull of these points which will be a polyhedron and keep just the faces that face downward. Remove the third coordinate and each face will describe a 2D region that corresponds to a Voronoi region. &lt;/p&gt;

&lt;p&gt;There is even a duality between a Voronoi diagram and a Delaunay triangulation of the same points. A Delaunay triangulation is one that maximizes the minimum angle of any triangle yield “good looking” triangles. The interesting thing here is that if you take a Voronoi diagram and convert the edges to vertices and the vertices to edges you get the corresponding Delaunay triangulation of the same set of points. So the two are dual to each other.&lt;/p&gt;

&lt;p&gt;The correspondence between these three algorithms means that if you can compute one you can compute the other without too much further effort.&lt;/p&gt;
&lt;h2 id="solution_2"&gt;Solution &lt;a class="head_anchor" href="#solution_2"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We are now in a position to solve our original problem as the key conceptual observation to make is  that the furthest point inside the polygon will lie either on a vertex of the Voronoi diagram of the set of polygon vertices, or on the intersection of a Voronoi region edge with a polygon edge. We can now compute the candidate points and for each work out which ones lies furthest from any vertex of the polygon. In the following images the dotted line represents edges of Voronoi regions that intersect the polygon and green crosses candidate points that could be the furthers. The red dot is the furthest point.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/8CsdApbnkHJVK8rapuHhGg0xspap.png"&gt;&lt;img alt="figure-000.png" src="https://svbtleusercontent.com/8CsdApbnkHJVK8rapuHhGg0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/i1LGjUEoeFWBSMfiP6SjX90xspap.png"&gt;&lt;img alt="figure-021.png" src="https://svbtleusercontent.com/i1LGjUEoeFWBSMfiP6SjX90xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://svbtleusercontent.com/kB51b8HhcKCVcsDScgDZtu0xspap.png"&gt;&lt;img alt="figure-050.png" src="https://svbtleusercontent.com/kB51b8HhcKCVcsDScgDZtu0xspap_small.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m not sure if the solution point can be constructed directly any other way other than constructing the candidates efficiently and testing each one in turn. I’d be really interested to see if this problem can be solved any other way. This blog post was inspired by ACM ICPC World Finals 2018 Question G.&lt;/p&gt;</description><author>Nicholas Pilkington</author><pubDate>Thu, 02 Jul 2020 02:44:53 GMT</pubDate><guid isPermaLink="true">https://nickp.svbtle.com/socially-distant-polygons</guid></item><item><title>Creating website screenshots with Python and pyppeteer</title><link>https://stribny.name/posts/creating-website-screenshots-with-python-and-pyppeteer/</link><author>Posts by Petr Stribny</author><pubDate>Wed, 01 Jul 2020 22:38:26 GMT</pubDate><guid isPermaLink="true">https://stribny.name/posts/creating-website-screenshots-with-python-and-pyppeteer/</guid></item><item><title>Of manels, and  neutrality of technology</title><link>https://stop.zona-m.net/2020/07/of-manels-and-neutrality-of-technology/</link><description>&lt;p&gt;Where do manels really come from (or start)?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 01 Jul 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/07/of-manels-and-neutrality-of-technology/</guid></item><item><title>A Simple Custom React Hook to Keep State in Query String</title><link>https://everttimberg.io/blog/custom-react-hook-query-state/</link><description>A common problem with many web apps is that it is not easy to share links to another user. This is usually due to the fact that the transient page state is only stored in memory.
I ran into this recently with a page in an app that allowed the user to view a parameter over time. The filter parameters (id, startTime, and endTime) were all stored in the component state and so if the user refreshed the page, all of the previous selection was lost.</description><author>Posts on Evert Timberg</author><pubDate>Wed, 01 Jul 2020 17:27:00 GMT</pubDate><guid isPermaLink="true">https://everttimberg.io/blog/custom-react-hook-query-state/</guid></item><item><title>Installing RDKit on Google Colab</title><link>https://web.navan.dev/posts/2020-07-01-Install-rdkit-colab.html</link><description>Install RDKit on Google Colab with one code snippet.</description><author>Navan's Archive</author><pubDate>Wed, 01 Jul 2020 17:23:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-07-01-Install-rdkit-colab.html</guid></item><item><title>Launching the Coding Career Handbook!</title><link>https://www.swyx.io/launching-coding-career</link><description>I'm launching my career advice book today!</description><author>swyx's site RSS Feed</author><pubDate>Wed, 01 Jul 2020 16:08:37 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/launching-coding-career</guid></item><item><title>Uncut Gems</title><link>https://olshansky.info/movie/uncut_gems/</link><description>Olshansky's review of Uncut Gems</description><author>🦉 olshansky 🦁</author><pubDate>Wed, 01 Jul 2020 11:38:14 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/movie/uncut_gems/</guid></item><item><title>Books and Links: June</title><link>http://evantravers.com/articles/2020/07/01/books-and-links-june/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/07/flowers.jpg" /&gt;&lt;/p&gt;&lt;p&gt;The cicadas in our yard have been proclaiming the arrival of Summer... I joke that in Alabama, the temperature of summer follows the same curve as the cicadas scream... slow for a bit, then escalating quickly. God has been good to my little family. While there is much in the world to break our hearts or create fear, when I surrender my anxiety and throw my trust on Him, this season is sweet indeed.&lt;/p&gt;
&lt;p&gt;On the creativity front, lots of &lt;a href="/articles/2020/06/"&gt;posts written this month&lt;/a&gt;... some random updates on ongoing projects:&lt;/p&gt;
&lt;p&gt;I'm still happily hacking away on my &lt;a href="/articles/series/hammerspoon-headspace/"&gt;headspace project&lt;/a&gt;. Just today I finally &lt;a href="https://github.com/evantravers/hammerspoon-config/commit/285703adb2d86925b63f115b93208ebf1a9061ae"&gt;fixed the v2 version&lt;/a&gt;... now it reliably blocks an app no matter where it's launched! I'm going to live in it for a while, then I'll do an update post once I've been using it a bit longer.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="A visualization depicting the links between notes." src="https://images.evantravers.com/articles/2020/07/zettels.png" /&gt;
  &lt;figcaption&gt;My zettelkasten grows... the constellation in the center is that which is linked up, and all the years of unlinked notes are floating around.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I'm also still working on my zettelkasten. I'm playing with &lt;a href="https://obsidian.md"&gt;obsidian.md&lt;/a&gt;... and I think with a few tweaks it'll do perfectly. I've finished (I think!) the transition from plain text notes to zettel, I'm working on writing that up too.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;p&gt;I need to get back in the habit of reading again... I'm working on and off on a couple... but I've been doing more blog/web reading.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#building-a-lego-powered-submarine-20---magnetic-couplings---youtube" id="building-a-lego-powered-submarine-20---magnetic-couplings---youtube"&gt;&lt;/a&gt;Building a Lego-powered Submarine 2.0 - magnetic couplings - YouTube&lt;/h3&gt;
&lt;p&gt;This &lt;em&gt;utterly&lt;/em&gt; delighted me today when I saw it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=MdfUSNzc0Xk&amp;amp;feature=youtu.be"&gt;Building a Lego-powered Submarine 2.0 - magnetic couplings - YouTube&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#case-study-analyzing-notion-app-performance--perfperfperf" id="case-study-analyzing-notion-app-performance--perfperfperf"&gt;&lt;/a&gt;Case study: Analyzing Notion app performance · PerfPerfPerf&lt;/h3&gt;
&lt;p&gt;Incredibly detailed analysis of a 3rd-party application from a performance perspective. Recommended read if you are interested in working on the performance of your application.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But if you’re building a software product, chances are you’re relatively unaffected. And in this case, having a quick app is more important than ever. Internet is slowing down due to increased demand, and people are holding on to their phones for longer – so if your app is slow, your users will be affected by it.&lt;/p&gt;
&lt;p&gt;And slow app means worse business.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://3perf.com/blog/notion/"&gt;Case study: Analyzing Notion app performance · PerfPerfPerf&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#what-happened-to-the-webmaster---the-history-of-the-web" id="what-happened-to-the-webmaster---the-history-of-the-web"&gt;&lt;/a&gt;What Happened to the Webmaster - The History of the Web&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Which brings us to ownership, that fundamental quality of a web creator we have lost over the years. The web is simply too big and monolithic for any person to know how any complex website works in its entirety. And even with smaller sites, the web has matured to a point where it’s perfectly plausible for a website to change hands many times over.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://thehistoryoftheweb.com/postscript/what-happened-to-the-webmaster/"&gt;What Happened to the Webmaster - The History of the Web&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#tradeoffs-and-shifting-complexity---daverupertcom" id="tradeoffs-and-shifting-complexity---daverupertcom"&gt;&lt;/a&gt;Tradeoffs and Shifting Complexity - daverupert.com&lt;/h3&gt;
&lt;p&gt;Some wisdom from Mr. Rupert. There is nothing perfect, there is only moving the pain from one are to another.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If that sounds a lot like modern day Front-end Development, you already see where I’m going with this. Not much has changed since Tesler’s day, code runs on either the client or the server. Thankfully today we have a few more levers to pull like “The Edge”, but the principle still applies; you get “advances” by shifting where the complexity lives. There’s good technical nuance, but most of the web’s fresh #hotdrama gets reduced to this for me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://daverupert.com/2020/06/tradeoffs-and-shifting-complexity/"&gt;Tradeoffs and Shifting Complexity - daverupert.com&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#accessible-to-some---manuel-matuzović" id="accessible-to-some---manuel-matuzović"&gt;&lt;/a&gt;Accessible to some - Manuel Matuzović&lt;/h3&gt;
&lt;p&gt;This is &lt;em&gt;awesome&lt;/em&gt;. A simulation of what it's like to visit a site that's designed to be accessible for people with capabilities you don't have. Most of the time it's unsighted people trying to use sighted websites, here's a 100% &amp;quot;sighted accessible&amp;quot; site that's 100% unusable.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I guess that most of you could not access all the information. How does that feel? Especially with my b------ justifications. Pretty bad, right? Now imagine having a similar experience on most websites you visit. That’s not just annoying and troublesome, but it makes you angry and sad.&lt;/p&gt;
&lt;p&gt;Please remember how this experience made you feel every time you work on a new website, page, or component. Make your websites accessible to all, not just to some.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://www.matuzo.at/blog/accessible-to-some/"&gt;Accessible to some - Manuel Matuzović&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Wed, 01 Jul 2020 10:50:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/07/01/books-and-links-june/</guid></item><item><title>Linux on the Desktop in 2020</title><link>https://jorin.me/linux-impressions/</link><description>One year ago I still had a MacBook Pro for work and a MacBook Air at home. Now I have a Thinkpad T490 running Manjaro + KDE and a Dell XPS 13 running Ubuntu + Gnome.</description><author>jorin.me</author><pubDate>Wed, 01 Jul 2020 09:00:00 GMT</pubDate><guid isPermaLink="true">https://jorin.me/linux-impressions/</guid></item><item><title>The Black Swan: The Impact of the Highly Improbable</title><link>https://olshansky.info/book/the_black_swan/</link><description>Olshansky's review of The Black Swan: The Impact of the Highly Improbable by Nassim Nicholas Taleb</description><author>🦉 olshansky 🦁</author><pubDate>Wed, 01 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://olshansky.info/book/the_black_swan/</guid></item><item><title>Feasible setup for passwords and backups</title><link>https://nutcroft.mataroa.blog/blog/feasible-setup-for-passwords-and-backups/</link><description>&lt;p&gt;People on the internet say it's a good idea to backup your data. Obviously, normal people ignore them. No one likes complicated processes with unclear long-term benefits&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;However, there is a neat way to do it.&lt;/p&gt;
&lt;h2 id="borg-for-backups"&gt;borg for backups&lt;/h2&gt;
&lt;p&gt;It is &lt;a href="https://rsync.net/products/attic.html"&gt;well known&lt;/a&gt; &lt;a href="https://www.borgbackup.org/"&gt;borg&lt;/a&gt; is the &lt;a href="https://www.stavros.io/posts/holy-grail-backups/"&gt;Holy Grail of backups&lt;/a&gt;. Along with &lt;a href="https://www.rsync.net/"&gt;rsync.net&lt;/a&gt; it’s a battle-tested combination that has worked great for many.&lt;/p&gt;
&lt;p&gt;However, there is a (not so much anymore) new player in town, &lt;a href="https://restic.net/"&gt;restic&lt;/a&gt;. Does everything better except one important thing. Specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;restic is one binary in contrast to borg (Go vs Python/C)&lt;/li&gt;
&lt;li&gt;restic does not need a server-side component&lt;/li&gt;
&lt;li&gt;restic can work with multiple protocols vs borg's SSH&lt;/li&gt;
&lt;li&gt;restic supports multiple machines backing up to the same repository&lt;/li&gt;
&lt;li&gt;restic supports multiple unlock keys&lt;/li&gt;
&lt;li&gt;borg has better performance? — &lt;a href="https://stickleback.dk/borg-or-restic/"&gt;claimed here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;borg is a more mature project&lt;/li&gt;
&lt;li&gt;borg supports multiple compression algorithms while restic doesn’t support compression (&lt;a href="https://github.com/restic/restic/issues/21"&gt;yet?&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last one is quite important if one is paying for the extra space. But, your data might already be compressed, in which case, borg’s compression won't mean much to you.&lt;/p&gt;
&lt;h2 id="pass-for-passwords"&gt;pass for passwords&lt;/h2&gt;
&lt;p&gt;It's sad that in 2020 every website implements authentication and authorization in their own nonideal and potentially insecure way. And it still eludes me why &lt;a href="https://en.wikipedia.org/wiki/WebAuthn"&gt;WebAuthn&lt;/a&gt; wasn't invented and implemented in 2000. In any case, we still need to manually&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt; create, save, input, change passwords.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.passwordstore.org/"&gt;pass&lt;/a&gt; is the &lt;em&gt;standard unix password manager&lt;/em&gt;. It’s a very thin porcelain over GPG, which acts as a password manager. The command line interface, along with the bash completion is lovable. The way it works is, it creates a specific GPG key and then encrypts each password as a file, inside a directory, &lt;code&gt;~/.password-store&lt;/code&gt;. The passphrase of that GPG key is one’s master password. &lt;/p&gt;
&lt;p&gt;There is also a sweet variety of &lt;a href="https://www.passwordstore.org/#extensions"&gt;extensions and clients&lt;/a&gt; on top of it.&lt;/p&gt;
&lt;h2 id="frank-for-2fa"&gt;frank for 2FA&lt;/h2&gt;
&lt;p&gt;It was a happy simple life in the past, a password manager would solve all your problems. Now we need to solve 2FA/MFA too. The most famous solution, Google Authenticator, has a couple of problems. Namely, it’s Google’s, so one day it might not even be in the app store. To make matters worse, it doesn’t allow exporting. Once you import the secret, it’s locked in, forevermore. Finally, it isn’t synced to your Google account, so if one loses their phone, they are done for.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Google: Don't lose your phone!&lt;br /&gt;
Normal person: Oh noes! I thought there would be no consequences :(&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some password managers like 1Password offer cloud 2FA solutions, but we would have to trust them to enjoy that. I couldn’t find any solid standalone CLI solutions, so I made &lt;a href="https://github.com/sirodoht/frank"&gt;a thing&lt;/a&gt; of my own. &lt;a href="https://imgur.com/gallery/6eleD"&gt;Bad idea&lt;/a&gt;—I know! But I used a pretty &lt;a href="https://github.com/pquerna/otp"&gt;good OTP library&lt;/a&gt; (I think) and just wrote the terminal input part.&lt;/p&gt;
&lt;p&gt;Combining with gopass + sed we get this magnificent, ^R-able, one-liner for retrieving our AWS MFA key:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span style="color: #657B83;"&gt; &lt;/span&gt;frank&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #859900;"&gt;$(&lt;/span&gt;gopass&lt;span style="color: #657B83;"&gt; &lt;/span&gt;aws.amazon.com&lt;span style="color: #657B83;"&gt; | &lt;/span&gt;sed&lt;span style="color: #657B83;"&gt; &lt;/span&gt;-n&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;'2p'&lt;/span&gt;&lt;span style="color: #859900;"&gt;)&lt;/span&gt;&lt;span style="color: #657B83;"&gt; | &lt;/span&gt;pbcopy
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The sed part exists because the MFA secret is in the second line of the gopass output. &lt;a href="https://ss64.com/osx/pbcopy.html"&gt;pbcopy&lt;/a&gt; auto-copies it.&lt;/p&gt;
&lt;h2 id="limitations"&gt;Limitations&lt;/h2&gt;
&lt;p&gt;As you might have guessed by now, there are several limitations in this way of managing one's cybernetic life. For starters, borg is complicated even for programmers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Programmer: Is this the passphrase? But then which one is the secret key? Do I have to
remember both my secret key and my passphrase? That's mental.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;gopass&lt;/code&gt; is not UX friendly unless you are weird; and &lt;code&gt;frank&lt;/code&gt; is the same. Not to mention that nothing works from your own phone as nothing is synced, which is a major deal-breaker for many.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Weird person: gopass is nice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yet, the article's title is unambiguous: a &lt;em&gt;feasible&lt;/em&gt; option.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Incidentally, that's also the reason people don't like taxes.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Not that we have, ourselves, to XOR &lt;code&gt;OrpheanBeholderScryDoubt&lt;/code&gt; 64 times. But still, a chore done more than 887 times according to &lt;code&gt;gopass ls|wc -l&lt;/code&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>nutcroft</author><pubDate>Wed, 01 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/feasible-setup-for-passwords-and-backups/</guid></item><item><title>Transcribing Hipaa Into Roam</title><link>/2020/07/01/Transcribing-HIPAA-Into-Roam.html</link><description/><author>rrich.io</author><pubDate>Wed, 01 Jul 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/2020/07/01/Transcribing-HIPAA-Into-Roam.html</guid></item><item><title>Generics for Go</title><link>https://lwn.net/Articles/824716/</link><description>Gives some background, the current state, and potential timeline for including generics in the Go programming language (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Wed, 01 Jul 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/824716/</guid></item><item><title>Organic Proposals</title><link>https://camhashemi.com/essays/organic-proposals/</link><description>&lt;p&gt;Proposing solutions to problems is a critical part of knowledge work. The efficiency and effectiveness of our proposals are key measures of our success. It’s something I had to learn the hard way.&lt;/p&gt;&lt;p&gt;By the end of my second year as a software engineer, I had only made one or two proposals to small problems assigned to me. As I got into my third year, I began proactively making proposals to open problems that I noticed.&lt;/p&gt;&lt;p&gt;At first, the proposal-making process was chaotic and painful. I would identify a problem, make its solution my passion project, and hammer away at a proposal for the team. The bigger the proposal was, the more I felt like a good engineer. I would proudly send my proposal to the team, ready to counter any criticism and push for my solution. I was confident that I was making a change for the better, and that it would be gratefully accepted by my team.&lt;/p&gt;&lt;p&gt;I was wrong. Those early proposals were consistently met with resistance: the bigger the proposal, the greater the resistance. The more energy I spent making a proposal, the more energy I needed to defend it. Given my naive confidence preceding each proposal, I was very confused and frustrated with this pattern. Thankfully, I had an experienced manager who I could talk to. He shared an idea with me that has greatly improved the efficiency and effectiveness of my proposals, and I’m happy to share that idea with you now.&lt;/p&gt;&lt;h2 id="treating-ideas-like-plants"&gt;Treating Ideas like Plants&lt;/h2&gt;&lt;p&gt;The gist of the wisdom was this: &lt;em&gt;evolve your proposal organically&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;In practice, this looks something like:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Identify the problem&lt;/li&gt;&lt;li&gt;Propose solutions to the problem&lt;/li&gt;&lt;li&gt;Gather feedback&lt;/li&gt;&lt;li&gt;Start again at step (1)&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;My initial proposals didn’t grow organically. Instead, they grew in my secret homemade laboratory, where the problems were as big as I made them and the solutions were as clear as I could see them. Once the proposal was fully formed, I pushed it onto my team as &lt;strong&gt;the&lt;/strong&gt; __problem and &lt;strong&gt;the&lt;/strong&gt; solution. This style put my team in an awkward spot. Maybe the problem was not as big as I thought it was, or maybe the solution was more complex than I could account for, or maybe it didn’t line up with our priorities at the time. Regardless, I was completely blind to all of this important context until I made the proposal. &lt;em&gt;After&lt;/em&gt; I made the proposal, that context slammed into my proposal like a ton of bricks. These collisions hurt my confidence and taxed my relationships with teammates.&lt;/p&gt;&lt;p&gt;The organic approach doesn’t have the same hazardous momentum. Instead of identifying a problem and immediately working on the solution in secret, I would instead ask my team if they knew about the problem and whether any thought had been put into it yet. This is like planting the seed of a proposal. Maybe my teammates have an existing proposal for the problem that can bring me up to speed. Maybe there are agreed workarounds or planned solutions to the problem that weren’t clear to me before. Or maybe there &lt;em&gt;is&lt;/em&gt; a shared desire for someone to tackle the problem head-on. In that case, the seed has been planted.&lt;/p&gt;&lt;p&gt;Given a planted seed, I need to nurture it within a small pot. The organic approach is to identify a few solutions to the problem and quickly sketch them out. Once I have a feel for the lay of the land, I can ask one or two thoughtfully selected teammates if they have any insight into the problem or what they think of those initial solutions. Their feedback is like a trickle of water on the seed. Each level of their involvement increases the strength of the seed until a clear direction is formed. Once we have something that can eventually turn into a solution, a sprout is formed.&lt;/p&gt;&lt;p&gt;Now that sprout needs more water and sun. I go back to my lab and flesh out the viable solutions until they hit some critical decision points or uncertainties. These decision points are like branches on our sprout. I don’t know which will be the strongest in the end, so I grow them in parallel until we need to choose one of them and cut the rest off. Maybe my favorite branch only looks good from where I’m standing, or maybe it only grew quickly in the beginning and won’t mature as nicely as another. Once the proposal starts looking healthy and attractive, our young plant is ready for prime-time.&lt;/p&gt;&lt;p&gt;With this healthy young plant in hand, I can more easily and confidently write a polished proposal that addresses all of the context and questions that arose during the seed and sprout phases. I’m no longer limited to my own awareness and preferences: I have my teammates’ awareness and preferences in mind as well. By the time the proposal is sent to the broader team, I should already have some support for it and some momentum behind it. Rather than artificially creating a proposal that my teammates are completely surprised by, I organically created a proposal that my teammates helped create. The gain in efficiency and effectiveness of such proposals has changed my career for the better.&lt;/p&gt;&lt;h2 id="grow-organically-die-organically"&gt;Grow Organically, Die Organically&lt;/h2&gt;&lt;p&gt;The advantage of the organic approach is not so much that my good ideas succeed eventually, it’s that my bad ideas fail early.&lt;/p&gt;&lt;p&gt;The problem with artificial systems is that the costs of wrong decisions are only faced after they get released into the world. With organic systems, the costs of wrong decisions continuously feed back into the development of the system. In an organic system, survival means you&amp;rsquo;ve adapted to the costs of your bad decisions. With an artificial system, one can go very far without ever facing the real world. In nature, the “production” environment is consistently identical to the “development” environment. The longer something is confined in a laboratory, the more likely it is to collapse as soon as it faces the real world.&lt;/p&gt;&lt;p&gt;The &lt;em&gt;beauty&lt;/em&gt; of the organic approach is that the wrong proposals die quickly and painlessly. When our fear of death for our own ideas is greater than the beauty of death for the wrong ideas, we hide those ideas from the world so that they don’t die young. When the beauty of death for the wrong ideas is greater than the fear of death for our own ideas, we push those ideas out into the world to see if they can survive and grow on their own. One approach is ego-centric and fragile, while the other is selfless and robust.&lt;/p&gt;&lt;p&gt;I’m not saying that after this 1:1 my ego dissolved into the atmosphere and I floated like a feather towards enlightenment. I still have my pet ideas that I push onto my team. Sometimes they’re rejected, sometimes they’re accepted; sometimes for better and sometimes for worse. But the principle still holds: organically grown proposals are more robust than artificially constructed proposals. The same applies to biology (Darwin), politics (see House of Cards), product (&lt;a href="https://blog.crisp.se/2016/01/25/henrikkniberg/making-sense-of-mvp"&gt;MVP&lt;/a&gt;), writing (&lt;a href="https://twitter.com/davidklaing/status/1174484916559478785?s=20"&gt;Content Triangle&lt;/a&gt;), and business (&lt;a href="http://www.startuplessonslearned.com/2008/09/lean-startup.html"&gt;The Lean Startup&lt;/a&gt;). The universality of this pattern is a hint to understand it more deeply.&lt;/p&gt;&lt;h2 id="caveats-tricks-and-tactics"&gt;Caveats, Tricks, and Tactics&lt;/h2&gt;&lt;p&gt;&lt;em&gt;Choosing the right people to show your seedling is an art&lt;/em&gt;. People who give constructive feedback are a good start. People with the most context on the problem are an obvious second place to look. Decision-making influence is another important factor. If someone could clearly say no to your proposal for reasons that they are solely responsible for, then it’s worthwhile planting a seed in their garden before growing a tree in yours. They’re the one with the axe.&lt;/p&gt;&lt;p&gt;&lt;em&gt;Focusing on&lt;/em&gt; &lt;strong&gt;&lt;em&gt;your&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;solution instead of&lt;/em&gt; &lt;strong&gt;&lt;em&gt;the&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;problem is artificial.&lt;/em&gt; There are an infinity of solutions for any given problem (someone has probably proved this somewhere), so it’s very important to identify the solution that solves a number of problems at the same time. This requires having an understanding of all of the various problems, micro-problems, and quality criteria beforehand. In addition, all of this context is constantly changing and the optimal solution is changing with it. If that context is understood, a solution that meets the most important criteria as well as some of the small-but-adds-up criteria can reveal itself, both now and in the future. Focusing a proposal on the problem and all of the context around it and the various solutions has been much more effective for me than focusing on my one solution to a poorly articulated problem.&lt;/p&gt;&lt;p&gt;&lt;em&gt;A proposal can be too organic&lt;/em&gt;. Nature is efficient in the long-run but inefficient in the short-term. That’s why we have venture funding and incubators, egg shells and embryos. Some things need a level of protection from the environment to increase their chance of success in the wild. Sometimes asking for permission can kill a good idea on arrival. That said, if I’m on a team where good ideas are killed quickly and surprise is the only way good things can happen, there more serious problems than whether a single proposal succeeds or fails. The long-term costs of a hostile environment are far greater than the short-term reward of strong-arming any proposal.&lt;/p&gt;&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;&lt;p&gt;The organic approach to proposals improves one&amp;rsquo;s effectiveness, efficiency, and relationships. Bad proposals die early and good proposals grow stronger. Feedback and support from the team is built from day one. Surprise and resistance are spread out over time, wasting less energy for everyone involved. Best of all, it’s a process that grows one’s team instead of growing one’s ego. All of these gains add up to a more pleasant and impactful experience for ourselves, our teams, and our users.&lt;/p&gt;</description><author>Cam Hashemi</author><pubDate>Tue, 30 Jun 2020 22:48:00 GMT</pubDate><guid isPermaLink="true">https://camhashemi.com/essays/organic-proposals/</guid></item><item><title>The first thing Twitter would really need</title><link>https://stop.zona-m.net/2020/06/the-first-thing-twitter-would-really-need/</link><description>&lt;p&gt;If Twitter DID really work for its users, that is&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 30 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/the-first-thing-twitter-would-really-need/</guid></item><item><title>Software disenchantment</title><link>https://tonsky.me/blog/disenchantment/</link><description>&lt;p&gt;Nikita Prokopov, in &lt;a href="https://tonsky.me/blog/disenchantment/"&gt;&lt;em&gt;Software disenchantment&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;You don’t have to be a genius to write fast programs. There’s no magic trick. The only thing required is not building on top of a huge pile of crap that modern toolchain is.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nikita makes a lot of great points about the general decline of software quality, &lt;a href="https://zacs.site/blog/linear-python.html"&gt;many&lt;/a&gt; of which &lt;a href="https://zacs.site/blog/the-root-of-all-evil.html"&gt;I have&lt;/a&gt; made &lt;a href="https://zacs.site/blog/learn-c.html"&gt;before&lt;/a&gt;. It&amp;#8217;s nice to hear this coming from someone else.&lt;/p&gt;


                &lt;p&gt;&lt;a href="https://tonsky.me/blog/disenchantment/"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Tue, 30 Jun 2020 19:35:54 GMT</pubDate><guid isPermaLink="true">https://tonsky.me/blog/disenchantment/</guid></item><item><title>Quicksand</title><link>https://utf9k.net/blog/quicksand/</link><description>Being stuck in place, or believing that you are at least, is not fun</description><author>utf9k</author><pubDate>Tue, 30 Jun 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://utf9k.net/blog/quicksand/</guid></item><item><title>Batch png to pdf with Inkscape &amp;amp; PDFtk</title><link>https://voussoir.net/writing/inkscape_batch_png_pdf</link><description>&lt;article&gt;
&lt;p&gt;&lt;a href="/writing"&gt;Back to writing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class="tag_link" href="/writing/tags/today_i_did_this"&gt;[today_i_did_this]&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Batch png to pdf with Inkscape &amp;amp; PDFtk&lt;/h1&gt;
&lt;p&gt;Today, I had 57 png images of QR codes, and needed to create a single pdf document where each page contained a single QR code with the file's name shown centered above the QR. From start to finish, without planning ahead, it took me 23 minutes, a pace which would have required me to do 1 image every 24 seconds if I were to do them by hand. Plus, any subsequent tweaks can be done in a flash.&lt;/p&gt;
&lt;p&gt;I used &lt;a href="https://inkscape.org/"&gt;Inkscape&lt;/a&gt; and &lt;a href="https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/"&gt;PDFtk&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create one svg manually&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open Inkscape and adjust the document page size to your liking.&lt;/li&gt;
&lt;li&gt;Add the image to the page. I chose to embed the image rather than linking, but in retrospect, linking would have been the correct choice.&lt;/li&gt;
&lt;li&gt;Add the text box to the page. With the text selected, press CTRL+SHIFT+T to open the Text and Font menu, choose Center alignment, and click apply.&lt;/li&gt;
&lt;li&gt;Arrange the image and label to your liking.&lt;/li&gt;
&lt;li&gt;Save the document.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate svgs for all other images&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open the template svg in a text editor and copy everything.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a Python file, and start by:&lt;/p&gt;
&lt;div class="highlight python"&gt;&lt;pre&gt;&lt;span class="n"&gt;TEMPLATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'''&lt;/span&gt;
&lt;span class="s1"&gt;paste the svg file here&lt;/span&gt;
&lt;span class="s1"&gt;&lt;/span&gt;&lt;span class="s1"&gt;'''&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you chose to embed the image, it will be stored as base64. In that case, delete the actual base64 text, but leave the &lt;code&gt;data:image/png;base64,&lt;/code&gt; prefix. After the comma, add &lt;code&gt;{image_base64}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xlink:href="data:image/png;base64,{image_base64}"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you chose to link the image, you'll find the file path. Replace it with &lt;code&gt;{image_path}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xlink:href="{image_path}"&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find the element that contains the label text, and replace the text with &lt;code&gt;{label_text}&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The rest of the Python script was as follows:&lt;/p&gt;
&lt;div class="highlight python"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt;
&lt;span class=""&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;glob&lt;/span&gt;

&lt;span class=""&gt;&lt;/span&gt;&lt;span class="n"&gt;filenames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*.png&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class=""&gt;&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;label_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;# do some transformations on the filename&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rb&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;image_base64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ascii&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TEMPLATE&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="narg"&gt;image_base64&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;image_base64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="narg"&gt;label_text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;label_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.png&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.svg&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using linking instead of embedding, this would have been more like:&lt;/p&gt;
&lt;div class="highlight python"&gt;&lt;pre&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filenames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;label_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;...&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;# do some transformations on the filename&lt;/span&gt;
    &lt;span class="n"&gt;svg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TEMPLATE&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="narg"&gt;image_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="narg"&gt;label_text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;label_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.png&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.svg&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;w&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;svg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Convert svgs to pdf&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On Windows, a for-loop in the command line looks like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;for %x in (*.png) do (start /w inkscape --without-gui --export-pdf=%~nx.pdf %~nx.svg)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Combine all pages into single pdf&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pdftk *.pdf cat output "all.pdf"&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If I need to make any updates to the template, I can&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open any of the svgs and make the changes.&lt;/li&gt;
&lt;li&gt;Copy it back into the Python file and redo the &lt;code&gt;{templating}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run the python script, inkscape export loop, and pdftk merger.&lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commits/master/voussoir.net/writing/inkscape_batch_png_pdf/inkscape_batch_png_pdf.md"&gt;View this document's history&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/147587b253cdfcd32a36d67df260934ceaa51a1b"&gt;&lt;time datetime="2020-09-20T21:27:33-07:00"&gt;2020-09-20&lt;/time&gt; Add tag today_i_did_this.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/33e00c9985353008b9f460a92c1049f6f833a39d"&gt;&lt;time datetime="2020-07-11T16:37:11-07:00"&gt;2020-07-11&lt;/time&gt; Use start /w to wait for the process to finish before next one.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.voussoir.net/voussoir/voussoir.net/commit/47b98020821918d6b4442f6e59a3f6e776bc231d"&gt;&lt;time datetime="2020-06-29T20:40:08-07:00"&gt;2020-06-29&lt;/time&gt; Add inkscape_batch_png_pdf.md.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;address&gt;Contact me: writing@voussoir.net&lt;/address&gt;
&lt;p&gt;If you would like to subscribe for more, add this to your RSS reader: &lt;a href="/writing/writing.atom" rel="alternate" type="application/atom+xml"&gt;https://voussoir.net/writing/writing.atom&lt;/a&gt;&lt;/p&gt;
&lt;/article&gt;</description><author>voussoir.net/writing</author><pubDate>Tue, 30 Jun 2020 06:40:08 GMT</pubDate><guid isPermaLink="true">https://voussoir.net/writing/inkscape_batch_png_pdf</guid></item><item><title>Graduation project: My presentation</title><link>https://boerman.dev/posts/graduation/presentation/</link><description>&lt;h1 id="graduated"&gt;Graduated!&lt;/h1&gt;
&lt;p&gt;After long months of work, today I finished my graduation project with a 7.5! That means I am now a graduated msc Electrical Engineering. Many thanks to Kees van Berkel and Marc Geilen for their supervising work!&lt;/p&gt;
&lt;p&gt;Due to the corona crisis the presentation was done fully online through microsoft teams. I have made a recording of the 30 min presentation, links to all material can be found below. I will finish my blog parts about my graduation project somewhere in the future, but first I am going to enjoy a holiday over the summer.&lt;/p&gt;</description><author>Blog Frank Boerman</author><pubDate>Tue, 30 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boerman.dev/posts/graduation/presentation/</guid></item><item><title>Server Sided GraphQL with Apollo Client</title><link>https://aknapen.nl/blog/server-sided-graphql-with-apollo-client/</link><description>During development of the dashboard I’m making for ClaimR I found myself in the position where I wanted to query a GraphQL endpoint from my backend. (It’s a NextJS powered project, hence the server sided logic is written in Node.) So, I started looking for GraphQL clients but with little success.
graphql-request seemed like a match, with what looked like a recent release earlier this year. However, on closer inspection it’s pretty clear that it has been abandoned.</description><author>Adriaan Knapen</author><pubDate>Tue, 30 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://aknapen.nl/blog/server-sided-graphql-with-apollo-client/</guid></item><item><title>The silent change in the nature of design</title><link>https://stop.zona-m.net/2020/06/the-silent-change-in-the-nature-of-design/</link><description>&lt;p&gt;Who are designers? Are they ALWAYS designers?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 30 Jun 2020 02:49:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/the-silent-change-in-the-nature-of-design/</guid></item><item><title>AWS Amplify - Access Denied</title><link>https://tiltingatwindmills.dev/aws-amplify-access-denied/</link><description>In my continuing journey to learn more about Gatsby, React, and all things
serverless and single page app I hosted the prototype of my…</description><author>Tilting at Windmills</author><pubDate>Mon, 29 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://tiltingatwindmills.dev/aws-amplify-access-denied/</guid></item><item><title>Rising to Red - An Introduction</title><link>http://spirals.blog/articles/red-introduction/</link><description>&lt;div class="toc"&gt;
&lt;p&gt;Red represents the “third stage” of human existence. If you’re new to Spiral, please first read:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/what-is-spiral-dynamics/"&gt;What is Spiral Dynamics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/beige-introduction/"&gt;Beginning in Beige&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/purple-introduction/"&gt;Progressing to Purple&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These articles will provide the necessary context for some of the concepts here.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Hey! You!&lt;/h2&gt;
&lt;p&gt;I &lt;em&gt;&lt;strong&gt;fucking&lt;/strong&gt;&lt;/em&gt; love Red. That’s right, I started my article like that. What are &lt;em&gt;&lt;strong&gt;YOU&lt;/strong&gt;&lt;/em&gt; gonna do about it? But I do. It’s sexy, brave, fiery, and full of adventure. It defends, it’s funny, and it doesn’t give a fuck (and yeah, sometimes that’s a BIG problem).&lt;/p&gt;
&lt;p&gt;Am I talking your language? Did I get your attention? Good chance you’re filtering through Red, or it appeals to a substantial Red in you! If this language made you feel uncomfortable (and fair enough), or you thought it was entirely inappropriate for what you were expecting to read, you’re probably not filtering through Red as much (which is totally fine too).&lt;/p&gt;
&lt;p&gt;If it’s not yet apparent, Red likes to be heard. Depending on how healthy it is, sometimes this “loud” is fun and expressive (like a rock concert), or it’s loud like a fight breaking out.&lt;/p&gt;
&lt;p&gt;Red is often abrupt and doesn’t want to say more than it has to. To the point and in not-so-many-words. Which is why I’m now going to stop the article because you get the point, right? Cool.&lt;/p&gt;
&lt;div class="dramatic-break"&gt;&lt;/div&gt;
&lt;p style="text-align: center;"&gt;Red also likes to joke.&lt;/p&gt;
&lt;div class="dramatic-break"&gt;&lt;/div&gt;
&lt;p&gt;I’ll stop before I lose those who aren’t resonating. Red can be intense for some and rightly so. If we’re still growing in Red as an individual, it can be very intimidating to experience Red’s energy, &lt;em&gt;especially if you’re the focus&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Especially if it’s unhealthy&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let’s go back to Purple for a second. Where did all this come from? I thought we were still singing “Kumbaya”…&lt;/p&gt;
&lt;h2&gt;The World Outside (Of Purple)&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Kayaking" src="http://spirals.blog/articles/red-introduction/kayaking.jpg" /&gt;
&lt;em&gt;Photo by Kalen Emsley @kalenemsley&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let’s first start by asking, “What’s the problem of Purple?” If we were all experiencing a beautiful, simple life without having to worry about the lions and starving to death, why would we ever leave this paradise? How did we get from Purple to where we are today? Surely there must be something else?&lt;/p&gt;
&lt;p&gt;While Purple is significantly safer than Beige, it’s not immune. There are still “other Purples” that we need to worry about, harsh conditions of the world that require us to move, and the world outside of our ancestor’s protection.&lt;/p&gt;
&lt;p&gt;At an individual level, we see this reflected around 3-6 years old, usually starting when we begin kindergarten or school. For the first time in our lives, our Purple (parents/family) leaves us alone with complete strangers to fend for ourselves with a room full of other kids. Talk about a different environment!&lt;/p&gt;
&lt;p&gt;But, as we find out, it’s not &lt;em&gt;all&lt;/em&gt; bad. In fact, it gives us individually a chance to explore who “I” am! Who am I without my mum and dad? How do I behave outside the tribe? What do I find interesting? As someone tentatively entering Red, we begin to reach out further from our “safe place,” taking more risks. We adventure into the surrounding world around us.&lt;/p&gt;
&lt;h2&gt;Curiosity &lt;s&gt;killed the cat 🐈&lt;/s&gt; made the Red&lt;/h2&gt;
&lt;p&gt;In Purple, we often live in fear of the outside world, as it regularly meant death if we were alone. When we enter Red, we re-address our &lt;a href="https://spirals.blog/articles/internal-external/"&gt;Agent/Arena relationship&lt;/a&gt; yet again, redefining our understanding of where we sit in the grand scheme of things.&lt;/p&gt;
&lt;p&gt;Whether driven by boredom, a growing sense of frustration that the Shaman’s rain dances are not working (Duh!), or sheer curiosity; &lt;em&gt;some Purples&lt;/em&gt; step outside the “Purple Circle” to seek their &lt;strong&gt;own&lt;/strong&gt; quests.&lt;/p&gt;
&lt;p&gt;In many ways, our entire identity was defined by the group in Purple. We don’t choose our language, our parents and their beliefs, the food of our culture, or our place of birth. These are all given to us when we enter this world. As Red gains confidence, standing on its own, these layers are peeled back and sometimes replaced with what the Red wants. “I don’t want to come home for dinner, mum! I want to play outside with my new friends!”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The individual is developing in his or her Self, his first real comprehension of the fact that he or she lives as a person, that, “I am a self. I am something that is separate and distinct from the other things.”&lt;/p&gt;
&lt;p&gt;– Clare Graves - &lt;a href="https://youtu.be/tt3Uk1f3y_U?t=1210"&gt;In Conversation with Clare W. Graves. (Youtube)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;“I’m Different!” - The Red Perspective&lt;/h2&gt;
&lt;p&gt;Red’s power comes from this ability to separate itself from the group. Different to Purple, Red is &lt;em&gt;&lt;strong&gt;fully&lt;/strong&gt;&lt;/em&gt; aware of it’s “self” and lives to prove this (to itself AND to others). One might say that Red is driven by a strong need of &lt;strong&gt;“significance”&lt;/strong&gt;. This “need” drives the behaviors common to Red’s as they “express-self” (&lt;a href="https://spirals.blog/articles/i-vs-we/"&gt;as opposed to “sacrifice-self” in Purple&lt;/a&gt;). A Red values anything that contributes to its idea of “self.” Red worships the ego as the solution to all its problems. As you can imagine, this can be healthy…and not so healthy.&lt;/p&gt;
&lt;h3&gt;Healthy Red&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Different" src="http://spirals.blog/articles/red-introduction/different.jpg" /&gt;
&lt;em&gt;Photo by Tong Nguyen van @duytanphoto&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What does it mean for a color to be “healthy”? As &lt;a href="https://spirals.blog/articles/purple-introduction/"&gt;we saw in Purple&lt;/a&gt;, a color is healthy when it’s integrated the previous colors, and is balanced across the Spiral between the “I” and “We.” For Red, this means a stable, healthy Purple, which will allow for someone to feel &lt;em&gt;safe&lt;/em&gt; enough to &lt;em&gt;express&lt;/em&gt; in Red.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Funky or eccentric fashion choices&lt;/li&gt;
&lt;li&gt;Taking a gap-year after high-school to go and “see the world.”&lt;/li&gt;
&lt;li&gt;That fun, new position you and your partner want to try in bed 😉&lt;/li&gt;
&lt;li&gt;Speaking up for yourself (not rudely or arrogantly)&lt;/li&gt;
&lt;li&gt;Rollercoasters and theme parks&lt;/li&gt;
&lt;li&gt;Going to a music concert with your friends (very Purple as well, Purple/Red)&lt;/li&gt;
&lt;li&gt;Drawing, painting, playing music, artistic expression (when done for yourself)&lt;/li&gt;
&lt;li&gt;Getting out in nature and exploring&lt;/li&gt;
&lt;li&gt;Motorbikes&lt;/li&gt;
&lt;li&gt;Saying no to things (with Purple)&lt;/li&gt;
&lt;li&gt;Etc&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If this list appeals to you, &lt;strong&gt;great&lt;/strong&gt;! Healthy Red is a fun, engaging, exciting way to enrich your life, especially if done with a Purple base, and with others. We’ll address more practical techniques and tools to explore a healthy Red in posts to come.&lt;/p&gt;
&lt;h3&gt;Unhealthy Red&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Screw you" src="http://spirals.blog/articles/red-introduction/unhealthy.jpg" /&gt;
&lt;em&gt;Photo by Harry Grout @harryjamesgrout&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As we’ve learned in other articles, all colors can have “healthy” and “unhealthy” expressions. What does this mean for Red, and why does it occur? How can we identify these &lt;em&gt;tendencies&lt;/em&gt; in ourselves?&lt;/p&gt;
&lt;p&gt;Spirals build on themselves. We often use a “house” metaphor to illustrate the importance of &lt;strong&gt;focusing on Healthy Purple before “moving on to”/“fixing” other colors&lt;/strong&gt;. If Purple represents the foundation of everything we build upon, then we could extend this story to say that Red forms the “walls” of our house. Without foundation, we can’t erect the walls.&lt;/p&gt;
&lt;p&gt;What does this look like in practice? Notice in yourself, your environment or the world, expressions of this “Red” energy &lt;strong&gt;without&lt;/strong&gt; feeling safe first, or taking into consideration how our actions will affect the tribe. What are some examples of this?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Crime&lt;/li&gt;
&lt;li&gt;Drug &lt;strong&gt;ab&lt;/strong&gt;use&lt;/li&gt;
&lt;li&gt;Butting into conversations just to be heard&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always&lt;/strong&gt; needing to be seen or heard – the center of attention&lt;/li&gt;
&lt;li&gt;Unable to control addictions&lt;/li&gt;
&lt;li&gt;Getting angry/aggressive/frustrated often&lt;/li&gt;
&lt;li&gt;Fighting others, or generally being combative to assert one’s Self or power&lt;/li&gt;
&lt;li&gt;Swearing/cursing to the point that it’s upsetting to others&lt;/li&gt;
&lt;li&gt;Avoiding the law because you “Can’t be fucked following what your boss tells you to do.”&lt;/li&gt;
&lt;li&gt;Shirking responsibilities&lt;/li&gt;
&lt;li&gt;Partying to the point that it’s terrible for your health (Can sometimes merge with some Orange tendencies)&lt;/li&gt;
&lt;li&gt;Taking without giving, constantly&lt;/li&gt;
&lt;li&gt;Picking on other countries (macro) or people (micro)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Many more&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What do all of these have in common? Is there a pattern that you can see emerging from these expressions? What do you notice?&lt;/p&gt;
&lt;p&gt;One could say that they all share an underlying sense of insecurity. Whether at the collective level in fighting other warring tribes or at the individual level in an overactive ego, most of it comes from an internal place of “not feeling good enough” – Low Purple.&lt;/p&gt;
&lt;p&gt;We can start to see, now, the relationships forming between these colors, and how they interact. Without an internal “truth” and &lt;em&gt;&lt;strong&gt;knowing&lt;/strong&gt;&lt;/em&gt; that you belong, are safe, and are accepted by others, our self-expression will almost always be twisted somehow.&lt;/p&gt;
&lt;p&gt;In these situations, Red regularly tries to “protect” Purple. It forms a defensive barrier around the Self, so it doesn’t get hurt again. Often, a past/childhood trauma (when Purple couldn’t stand up for itself) forms an internal or collective strategy to ensure that &lt;em&gt;never&lt;/em&gt; happens again. This results in the Purple never being exposed or vulnerable, an overactive, assertive Red energy, and a whole lot of issues.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;Partner:&lt;/strong&gt; “Hey. So, I’ve been thinking about us a lot…and…I think I love you.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low Purple/Red:&lt;/strong&gt; “What? No, you don’t! Don’t say shit like that”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Partner:&lt;/strong&gt; “No, really! I do! You mean a lot to me.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Low Purple/Red:&lt;/strong&gt; “I don’t need this in my life. I’ve been hurt before, and you’ll just hurt me too. Goodbye”&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Ever been part of, or heard, a conversation like this? There’s a lot to unpack here, but the short of it is: Red tries to protect a wounded Purple, never letting itself heal, and becoming aggressive to anyone who gets close enough to try.&lt;/p&gt;
&lt;p&gt;The good news is, it doesn’t have to be this way. If you feel trapped, in pain, or that no-one understands the trauma you’ve been through that’s created the “tough exterior” you wear, you’re not alone. Investing time and energy to heal, be vulnerable, and rebuild our relationship with ourself and others, can be a great way to improve your Purple and thus this unhealthy Red expression. We’ll discuss this in more depth as well in other articles.&lt;/p&gt;
&lt;h2&gt;Becoming the Hero&lt;/h2&gt;
&lt;p&gt;Let us return to the story of our Purple, stepping outside of the nest/tribe to discover themselves and the world. After all their adventures, mishaps, quests, and discoveries, they make their way back to what is familiar, but this time it feels different.&lt;/p&gt;
&lt;p&gt;The tribe is enamored with the bravery this new Red has shown, being gone so long, and sharing all their stories. Purple looks to Red as a hero, an influential leader to help protect and provide for them. One who has conquered the “Outside world” and returned victorious! Of course, the Red is living in such a way that he believes everything should add to their “self” and find they very much enjoy this new-found attention.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Chief" src="http://spirals.blog/articles/red-introduction/chief.jpg" /&gt;
&lt;em&gt;Photo from Mad Max: Fury Road&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;A lo, the Chief arises! Our Red leader, the protector of the realm, the conquerer of Purple’s enemies, and the mightiest and wisest of us all. The new hero can outwit, outfight, and outsmart everyone they know because of their mighty Red perspective.&lt;/p&gt;
&lt;p&gt;The Red inspires other Purples to shift into Red, forming gangs or bands of warriors. Blood is life, and the gods are those of power and strength. After all, the only thing a Red respects is a more significant Red…&lt;/p&gt;
&lt;h3&gt;“What did you call me?”&lt;/h3&gt;
&lt;p&gt;At times, there are those younger Red’s who feel they have what it takes to be the one calling the shots. They challenge the Chief/Warlord/King often resulting in a fight to the death. Whoever wins is the new leader; “I am the Red’ est, baddest mother fucker of them all. Let it be known!”&lt;/p&gt;
&lt;p&gt;Have you ever seen two overly Red individuals on the street walk past each other, only for one to yell, “You looking at me, mate?” Ok, perhaps the “mate” is particular to drunk Australians on the beaches at 3am; however, the sentiment is universal.&lt;/p&gt;
&lt;p&gt;“I’m more Red than you. What are you going to do about it?”&lt;/p&gt;
&lt;p&gt;So begins what I like to call a “Red Off!”. As neither Red is willing to be the “lesser” or “weaker” of the two, things escalate; quickly.&lt;/p&gt;
&lt;p&gt;“Oh yeah? Tell that to your girlfriend, who was in MY bed last night.”&lt;/p&gt;
&lt;p&gt;You get the picture.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;How does Red work in our relationships?&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Couple enjoying festival" src="http://spirals.blog/articles/red-introduction/relationship.jpg" /&gt;
&lt;em&gt;Photo by Slim Emcee @truth_from_africa_photography&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Red is not all bad – in fact, it’s critical (as many colors are) for operating successfully and happily in our world. A great example of how Red can be used (outside of our internal Red; a sense of importance/significance) is relationships.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Hey, so, I saw you from the other side of the room – annnnnd I’ll be honest, you really caught my eye. Can I buy you a drink?”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Red takes the risk. If we’re still developing our Red, this situation can be incredibly scary. Talking to an attractive stranger in a crowded place with everyone watching? What if it went wrong? Oh god, what if they think I’m ugly. Better not.&lt;/p&gt;
&lt;p&gt;Red doesn’t care about what others think, it just acts. When balanced with a healthy Purple, this can empower us to take bold actions to improve our lives and the lives of others. Sometimes we need to go out on a limb to create the life we want. Healthy Red is a &lt;strong&gt;fantastic&lt;/strong&gt; tool for this.&lt;/p&gt;
&lt;p&gt;The best relationships I’ve ever had were Healthy Purple + Healthy Red (and a few others, but this was the base). When building a connection with someone, it’s vital for both parties to be able to safely express how they feel, get things off their chest, and tell it how it is – without the other person taking it too personally. Communication is &lt;em&gt;&lt;strong&gt;essential&lt;/strong&gt;&lt;/em&gt; for any long-term relationship. If you’re just after a good ol’ Red fling, then forget this for now 😉.&lt;/p&gt;
&lt;p&gt;We’re attracted to partners with healthy colors. Healthy Red in a relationship enables the fun, adventurous, sexy attraction that helps it feel fresh and engaging. Have you ever been in a marriage or long-term bond with someone where you two were &lt;em&gt;always&lt;/em&gt; enjoying your time together, trying new things, expressing, having fun, and creating a safe space to just “be together”? Healthy Purple + Healthy Red is very fulfilling in this respect.&lt;/p&gt;
&lt;p&gt;On the flip-side, can you recognize relationships where one or both individuals were still developing their Red? Shyness, unwillingness to get out of the house, apathy/sluggishness, boredom, not standing up for themselves or saying what they really mean – all these may be traits that Red is still “under construction” for this person.&lt;/p&gt;
&lt;h2&gt;Leading Red&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Encouragement" src="http://spirals.blog/articles/red-introduction/encourage.jpg" /&gt;
&lt;em&gt;Photo by Felix Rostig @felixrstg&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a complex topic for another time, we’ll address how to lead or encourage healthy Red briefly. The first step (if you didn’t already know) is ensuring there’s a healthy Purple first. This is crucial before stepping into ANYTHING else, as a Red trying to lead a Low Purple to step into their Red can be extremely frightening. Healthy Purple comes first.&lt;/p&gt;
&lt;p&gt;But let’s say whoever we’re leading IS in a stable place, they’re perhaps just a little shy, or not as well versed in expressing themselves. What can we do to help our loved ones “come into their own?” &lt;strong&gt;(Provided we’re the right person to do so, and have permission)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Personally, I start with Purple activities we both enjoy, and turn up the volume a little. For example, a tranquil bike ride along the bay might turn into an amiable race to the next destination. A moment of shyness could be reframed into an opportunity to come out of the shell by both of you talking to the waiter about the town you’re visiting. Cuddling on the couch watching your favorite movie might progress into a “Netflix and chill” kind of situation.&lt;/p&gt;
&lt;p&gt;At its core, Healthy Purple + Red has a joyous love for all involved. It wants to be funny, lighten the situation, not take things so seriously and have a good time with everyone, or alone if it pleases – Red doesn’t care.&lt;/p&gt;
&lt;h2&gt;What’s YOUR Red?&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Taking a bath" src="http://spirals.blog/articles/red-introduction/bath.jpg" /&gt;
&lt;em&gt;Photo by Roberto Nickson @rpnickson&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As we’re starting to see, the complexity of these colors dramatically increases as we progress through the Spiral. This article has tried to touch most of the significant points of Red to form an introduction, however, &lt;strong&gt;it’s impossible to cover everything&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So what does Red mean to you? How does your Red express itself in your life, in your emotions, and your body? Is it a passionate, intense fire that burns for love? Is it a soft, joyous love for good food, good people, and good vibes? Perhaps we recognize some of the unhealthy tendencies we keep – getting angry at things we really ought not to, being a little too selfish at times, or not thinking about others enough.&lt;/p&gt;
&lt;p&gt;Whichever it is for you, we now have a new tool in our Spiral Toolbox to understand a different perspective. Spiral builds empathy. Whether we resonate or not with any given color is irrelevant – as long as we can &lt;em&gt;understand&lt;/em&gt; someone’s intention before judging them.&lt;/p&gt;
&lt;p&gt;I challenge you to write a list of all the Red activities you do. The healthy ones and the no-so-healthy ones. Which ones are working for you, and which one’s aren’t (you may need to get some external perspective on this)?&lt;/p&gt;
&lt;p&gt;For those still developing Red, a great way to grow in this area of life is to write a list of all the “Red” things we’ve wanted to do. Skydiving, sexy lingerie, traveling to Bali. Write whatever is relevant for you down, and make an active effort to check them off! Even better is when you share this list with another Red, turning it into all the exciting things you can explore in yourself and the relationship/friendship.&lt;/p&gt;
&lt;p&gt;So go! Be free! Live! Express, love, cry, fuck, laugh, and have a good time doing it all. Life is meant to be lived – and even better when you’re most alive with those closest to you. Take command of your life. Live the way you’ve always wanted to be. Listen to the little voice inside your heart that whispers, “Do it”. Red awaits you.&lt;/p&gt;
&lt;h2&gt;Leaving Red&lt;/h2&gt;
&lt;p&gt;Too much Red in your life? Partied enough, or sick of running out of money on your backpacking adventures? Looking to find something a little more stable in your life? Tired of the constant taking and sizing-up of those around you?&lt;/p&gt;
&lt;p&gt;Fear not friends. The Spiral does not end here. &lt;a href="https://spirals.blog/articles/blue-introduction"&gt;In the next color&lt;/a&gt;, we’ll investigate how Blue helps keep Red in check. A powerful force of justice and truth shall emerge from the madness of Red to save us from sin and chaos alike. Red’s beware! The organized armies of “sacrifice-self” are back, but not like our Purple friends. Blue possess’s something else entirely…&lt;/p&gt;
&lt;p&gt;&lt;img alt="Disapproval" src="http://spirals.blog/articles/red-introduction/blue.jpg" /&gt;
&lt;em&gt;Photo by Ahmed Carter @ahmedcarter&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Sweet Lord, what did I just read?&lt;/h2&gt;
&lt;p&gt;Don’t worry. All our posts won’t be written this way if it’s style didn’t click with you. It was merely to illustrate how Red writes and thinks, with the article itself being an example of Red. They won’t all be like this. Much. Well, maybe a little bit 😀.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 28 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/red-introduction/</guid></item><item><title>Trailer Profile</title><link>https://dustin.lammiman.ca/teardrop/shape/</link><description>&lt;p&gt;Drawing the shape for the profile of the trailer.&lt;/p&gt;</description><author>Dustin.Lammiman</author><pubDate>Sun, 28 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dustin.lammiman.ca/teardrop/shape/</guid></item><item><title>Trailer Floor Complete</title><link>https://dustin.lammiman.ca/teardrop/floor2/</link><description>&lt;p&gt;Finished putting the floor on the trailer.&lt;/p&gt;</description><author>Dustin.Lammiman</author><pubDate>Sun, 28 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://dustin.lammiman.ca/teardrop/floor2/</guid></item><item><title>Reflecting on one year of writing</title><link>https://nickolinger.com/blog/reflecting-on-one-year-of-writing</link><description>Thoughts on the past year of writing, how to improve, and new site features.</description><author>&amp;gt; nick</author><pubDate>Sun, 28 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nickolinger.com/blog/reflecting-on-one-year-of-writing</guid></item><item><title>Blogging lessons from working for a large blogging company</title><link>https://maxrozen.com/blogging-lessons</link><description>For a short period, I was employed by a company that drove most of its revenue from blogging. Here's what I learned while I was there.</description><author>Max Rozen</author><pubDate>Sat, 27 Jun 2020 18:52:00 GMT</pubDate><guid isPermaLink="true">https://maxrozen.com/blogging-lessons</guid></item><item><title>Why I avoid Cargo: dependency versions</title><link>https://dorotac.eu/posts/cargo_versions/</link><description>&lt;h1&gt;Why I avoid Cargo: dependency versions&lt;/h1&gt;
&lt;p&gt;Ever since I started making use of &lt;a href="https://doc.rust-lang.org/cargo/"&gt;Cargo&lt;/a&gt; to build the Rust pieces of &lt;a href="https://source.puri.sm/Librem5/squeekboard/"&gt;Squeekboard&lt;/a&gt;, I've hit a wall whenever I needed to add something nontrivial to the build process. I haven't documented them before, so whenever I complained about Cargo, I ended up looking ridiculous without having anything to show for the complaints.&lt;/p&gt;
&lt;p&gt;Last week I spent three days solving a problem with building Squeekboard that should have been solveable in 30 minutes, in large part due to Cargo.&lt;/p&gt;
&lt;h2&gt;Buster and Bullseye&lt;/h2&gt;
&lt;p&gt;Squeekboard is a crucial part of the software stack of the &lt;a href="https://puri.sm/products/librem-5/"&gt;Librem5&lt;/a&gt; mobile phone. It's primary goal is to fit in well in &lt;a href="https://pureos.net/"&gt;PureOS&lt;/a&gt;, which powers the phone. PureOS is in turn based on Debian, and inherits a lot of its practices, which are followed by projects related to the Librem5, including Squeekboard.&lt;/p&gt;
&lt;p&gt;One such practice is that Rust crates are vendored by Debian, and not by the application author. They are installable with &lt;code&gt;apt&lt;/code&gt;, and end up in a local repository in &lt;code&gt;/usr/share/cargo/registry&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Librem5's base operating system is moving from Debian 10 to Debian 11. I was &lt;a href="https://source.puri.sm/Librem5/squeekboard/-/issues/200"&gt;asked&lt;/a&gt; to make Squeekboard work on both in the transition period. Debian 10 ships with gtk-0.5.0, whereas Debian 11 ships with gtk-0.7.0, which contain some incompatibilities, and Squeekboard's build process must adjust to them, depending on where the build happens.&lt;/p&gt;
&lt;p&gt;Piece of cake: there's one variable, which needs to be turned into one decision. I did this a million times. Little did I know Cargo hates simple solutions.&lt;/p&gt;
&lt;h2&gt;What's the version we're using?&lt;/h2&gt;
&lt;p&gt;It's not unusual for projects to support two versions of the same dependency. Perhaps the versions come from different vendors. C programs don't have trouble with this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;gtk.h&amp;gt;
#if GTK_VERSION==0.5
  // old stuff
#endif
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rustc won't know dependency versions by itself, but Cargo should turn it to something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#[cfg(dependency.gtk.version = "0.5.*")]
use gio::SimpleActionExt; // Doesn't exist in later versions of gtk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But… I haven't managed to find any equivalent. It makes sense, Cargo can pull several copies of the same crate, and I think their pieces can even be used in the same files if one is not careful. So there's no good reason this should have worked. Fair, let's try something else.&lt;/p&gt;
&lt;h2&gt;What's the available version?&lt;/h2&gt;
&lt;p&gt;If the compilation process can't tell us what versions we're dealing with, perhaps we can check that before compilation. In Meson, we'd do something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gtk-rs = dependency("gtk-rs")
if gtk.version().startswith("0.5.")
      add_project_arguments('--cfg old_gtk', language : 'rust')
endif
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then, in Rust:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#[cfg("old_gtk")]
use gio::SimpleActionExt; // Doesn't exist in later versions of gtk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the only remaining thing is to create the dependency lookup procedure. While Squeekboard is Debian-focused, building on non-Debian systems is still important, so it must build with crates.io. Thankfully, we have &lt;code&gt;cargo search&lt;/code&gt;. Let's try with a vendored registry:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@c684b7b31b07:/# CARGO_HOME=/mnt/build/eekboard/debian/cargo/ cargo search gtk
error: dir /usr/share/cargo/registry does not support API commands.
Check for a source-replacement in .cargo/config.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oh no. We can forget about it. I'm not willing to write a tool that searches for crates in all the ways that Cargo supports, and I'm honestly boggled that Cargo doesn't properly do it itself.&lt;/p&gt;
&lt;p&gt;As a bonus, the output of cargo search just doesn't make sense. I'm looking for the regex crate, which is at version "1.3.9":&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ cargo search regex=1
combine-regex-1 = "1.0.0"      # Re-export of regex 1.0 letting combine use both 0.2 and 1.0
webforms = "0.2.2"             # Provides form validation for web forms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Totally useless :(. But I still have a few tricks up my sleeve.&lt;/p&gt;
&lt;h2&gt;Use a build flag&lt;/h2&gt;
&lt;p&gt;Isn't this obvious? Let's skip all that dependency detection, and just order the build system to use one, in the dumbest fashion possible. The way you'd do it with Meson:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if get_option("legacy") == true
  gtk-rs = dependency("gtk-rs", version=0.5)
  add_project_arguments('--cfg old_gtk', language : 'rust')
else
  gtk-rs = dependency("gtk-rs", version&amp;gt;0.5)
endif
squeekboard = executable('squeekboard',
  dependencies: [gtk-rs],
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add to that the conditional in the Rust file, and we're done. Cargo is not Meson, but we can call it with flags too, and then instruct it to use the right dependency. Right?&lt;/p&gt;
&lt;p&gt;Wrong.&lt;/p&gt;
&lt;p&gt;While Cargo allows choosing dependency versions, they are selected based on target, not on flags. You can use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[target.'cfg(unix)'.dependencies]
openssl = "1.0.1"
[target.'cfg(not(unix))'.dependencies]
openssl = "1.0.0"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can remember that the &lt;code&gt;cfg()&lt;/code&gt; syntax supports features:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[target.'cfg(feature="legacy")'.dependencies]
gtk="0.5.*"
[target.'cfg(not(feature="legacy"))'.dependencies]
gtk="0.7.*"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but then you see this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# cargo build
warning: Found `feature = ...` in `target.'cfg(...)'.dependencies`. This key is not supported for selecting dependencies and will not work as expected. Use the [features] section instead: https://doc.rust-lang.org/cargo/reference/features.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And when you follow that web page, you learn that you can specify other dependencies, but not other versions. Foiled again!&lt;/p&gt;
&lt;p&gt;Again, I'm boggled why such a basic piece of functionality is working in such a complicated and restrictive way. Wouldn't it be easier to abolish the weird &lt;code&gt;feature = [dep]&lt;/code&gt; syntax and instead let &lt;code&gt;foo.dependencies&lt;/code&gt; work, with all the fine-grained control over what the dependencies are?&lt;/p&gt;
&lt;h2&gt;Embedded crates&lt;/h2&gt;
&lt;p&gt;But I didn't stop there. If the deps can't be specified the usual way, then let's get there through a back door. If I can't choose a version, I will choose a crate. 0.5 turns into a crate called "legacy", and 0.7 into one called "current". My Cargo.toml looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[dependencies]
current = {path="deps/current", optional=true}
old = {path="deps/old", optional=true}

[features]
legacy = ["old"]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;deps/old/Cargo.toml&lt;/code&gt; contained the actual version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[dependencies]
gtk-rs = "0.5.*"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the current one had &lt;code&gt;0.7.*&lt;/code&gt;. When we choose the crate, we choose the dependency with it! So clever! There's no way it won't work!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@c684b7b31b07:~/foo/foo# CARGO_HOME=/mnt//build/eekboard/debian/cargo/ cargo build
error: failed to select a version for the requirement `gtk = "0.5.*"`
  candidate versions found which didn't match: 0.7.0
  location searched: directory source `/usr/share/cargo/registry` (which is replacing registry `https://github.com/rust-lang/crates.io-index`)
required by package `old v0.1.0 (/root/foo/foo/deps/old)`
    ... which is depended on by `foo v0.1.0 (/root/foo/foo)`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What!? This cannot be! Why oh why?&lt;/p&gt;
&lt;p&gt;My only guess is that cargo pulls all the dependencies indiscriminately, regardless of whether it actually needs them or not. Obviously, this entire shebang is because we &lt;em&gt;don't&lt;/em&gt; have one of them! Why is Cargo missing the point of choosing dependency versions so hard?&lt;/p&gt;
&lt;h2&gt;Nuclear option&lt;/h2&gt;
&lt;p&gt;With this in mind, there's only one solution left. If Cargo is greedy enough to snatch everything it sees, then we'll just not let it know there are possibly any other dependencies. We'll generate a Cargo.toml after we know which dependency we need, and we'll never let Cargo know about the other dependency. The details of the generation are quite straightforward: just change depedencies based on build flags. The build scripts get complicated, though. Now they must include &lt;code&gt;--manifest-path&lt;/code&gt;. This looks trivial, but this changes the root of the crate, so now we need to give it the path to the sources again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[lib]
name = "rs"
path = "@path@/src/lib.rs"
crate-type = ["staticlib", "rlib"]

# Cargo can't do autodiscovery if Cargo.toml is not in the root.
[[bin]]
name = "test_layout"
path = "@path@/src/bin/test_layout.rs"

[[example]]
name = "test_layout"
path = "@path@/examples/test_layout.rs"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it works. Finally.&lt;/p&gt;
&lt;p&gt;Sadly, we sacrificed autodetection of tests and binaries, as well as distro-agnosticism.&lt;/p&gt;
&lt;h2&gt;You're doing it all wrong!&lt;/h2&gt;
&lt;p&gt;I'm sure some of you will see the struggle and consider it self-inflicted. "Why didn't you try X?", "You're fighting the tool because your model is outdated!", "This is not a bug". Some of them will be valid criticisms, and I'm going to address those I could think of.&lt;/p&gt;
&lt;h3&gt;Use multiple Cargo.lock versions&lt;/h3&gt;
&lt;p&gt;I could have used "*" as the dependency version, and instead rely on two versions of Cargo.lock to select the actual dependency I want. That is troublesome.&lt;/p&gt;
&lt;p&gt;I don't want to know exactly what versions of Rust crates (or any other deps really) the upstream distro is shipping. This is why I use distros in the first place: they remove some burden of deps auditing from me. All I want to know is the minor version for API compatibility reasons. However, Cargo.lock forces me to care about dependencies by asking for a hash of each. I would have to find out what dependency is available, and feed Cargo.lock with its hash. That hits the same problem with detecting what we have again.&lt;/p&gt;
&lt;h3&gt;Vendor your crates yourself&lt;/h3&gt;
&lt;p&gt;Squeekboard is just one project out of many in PureOS, and all the others follow Debian's best practices: use Debian's software versions whenever possible. On one hand, this is designed to set right expectations, on the other it relegates the responsibility for auditing and updating to Debian, as explained in the previous argument.&lt;/p&gt;
&lt;p&gt;In this light, I'm already letting Debian vendor my crates, and that won't change.&lt;/p&gt;
&lt;h3&gt;Cargo is designed for crates.io, not for distributions or local repositories&lt;/h3&gt;
&lt;p&gt;I'm not sure if this is Cargo's explicit goal to be useful with crates.io, but my experience says other sources are in practice playing catch-up. If I relied exclusively on crates.io, I would have no problems.&lt;/p&gt;
&lt;p&gt;However, the build policy in PureOS requires builds to happen without a network connection. That means we can't use crates.io. We've already eliminated vendoring before, and so we're stuck with some form of a local repository, which clearly isn't well-supported by Cargo.&lt;/p&gt;
&lt;h2&gt;Insights&lt;/h2&gt;
&lt;p&gt;My insight from this adventure is that Cargo doesn't prioritize users who want to control their own sources of software at the moment. It's inflexible in the way that favours crates.io, where the implicit assumption is that all possible crates and versions are available. After all, it crashes when a non-available version is specified even if unused.&lt;/p&gt;
&lt;p&gt;Cargo also doesn't want application developers to offload dependency checking. It's recommended to commit Cargo.toml together with the application, but there's no provision to ignore it when doing a build with local versions of the same crates, like when you do in distro builds.&lt;/p&gt;
&lt;p&gt;Cargo is not composable the way other build systems are. When building a C program, artifacts in the form of shared or static libraries are placed in a well-known directory. Cargo creates an opaque directory structure for compiled crates in the &lt;code&gt;target&lt;/code&gt; directory, which cannot be used by another build system later due to lack of documentation. Sadly, this means that when Cargo fails to solve a need, there's no alternative.&lt;/p&gt;
&lt;p&gt;The same creates a network effect, where Cargo is de facto the only tool that builds useful Rust programs. It's difficult to the point of pointlessness to "build" serde and gtk-rs separately, and then "link" them with the main program using manual &lt;code&gt;rustc&lt;/code&gt; calls.&lt;/p&gt;
&lt;p&gt;Creating composable artifacts would undermine Cargo's monopoly and allow a better integration with distributions as well as other programming languages in my opinion. Build systems should not infect all software they touch.&lt;/p&gt;</description><author>dcz's posts</author><pubDate>Sat, 27 Jun 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/cargo_versions/</guid></item><item><title>Blast from the past - Linux Telephony API</title><link>https://blog.herlein.com/post/lti/</link><description>&lt;p&gt;A trip down memory lane:  the first linux telephony drivers&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 27 Jun 2020 14:10:43 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/lti/</guid></item><item><title>Rainbow – an attempt to display colour on a B&amp;amp;W monitor</title><link>https://www.anfractuosity.com/projects/rainbow/</link><description>The aim of this project was to display a colour image on a black and white monitor, by overlaying an acetate bayer filter (inkjet printed) over the monitor and mosaicing a colour image. I obtained an Eizo B&amp;#38;W monitor from ebay, which I was intending for use viewing B&amp;#38;W photos and was curious if I [&amp;#8230;]</description><author>Anfractuosity</author><pubDate>Sat, 27 Jun 2020 09:42:19 GMT</pubDate><guid isPermaLink="true">https://www.anfractuosity.com/projects/rainbow/</guid></item><item><title>Some more coronavirus facts and feelings from Italy</title><link>https://stop.zona-m.net/2020/06/some-more-coronavirus-facts-and-feelings-from-italy/</link><description>&lt;p&gt;just a small update, six weeks after the end of #ItalyLockdown&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 27 Jun 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/some-more-coronavirus-facts-and-feelings-from-italy/</guid></item><item><title>A Bookmark to Temporarily Disable your Pi-hole</title><link>https://www.mikekasberg.com/blog/2020/06/26/a-bookmark-to-temporarily-disable-your-pihole.html</link><description>&lt;p&gt;I use a &lt;a href="https://pi-hole.net/"&gt;Pi-hole&lt;/a&gt; on my home network and I love it! It
works by configuring your local network to use the Pi-hole as the DNS server,
and the Pi-hole refuses to resolve domains of sites you want to block. It
does a pretty good job of blocking everything from unwanted trackers to ads and
malware. Sometimes, though, it’s annoying because it blocks a link that I
actually want to visit. Maybe I’m trying to visit a sponsored Google link,
an Amazon product link, or a link from an email. In any case, I just don’t want
the link to be blocked, and the Pi-hole gets in the way. This can be
inconvenient because the usual process to temporarily allow blocked traffic is
to open the Pi-hole admin page in a new tab, login, and click the link to disable
it in the menu. Too much work! So I came up with a slightly easier way. I use a
bookmark in my bookmarks toolbar that will disable the Pi-hole for 30 seconds.&lt;/p&gt;

&lt;p&gt;Do you want a “Disable Pi-hole” bookmark for your own Pi-hole? You can generate
one using the form below! You’ll need the &lt;strong&gt;IP address&lt;/strong&gt; of your own Pi-hole (on
your local network). (Pro tip: You can use &lt;code class="language-plaintext highlighter-rouge"&gt;pi.hole&lt;/code&gt; in place of the IP address
for most Pi-hole setups. Try it and see if it works for you!) You’ll also need
the &lt;strong&gt;webpassword&lt;/strong&gt;, which you can get by running &lt;code class="language-plaintext highlighter-rouge"&gt;cat
/etc/pihole/setupVars.conf&lt;/code&gt; on your Pi-hole (probably via ssh). I find 30s to be
a good default &lt;strong&gt;duration&lt;/strong&gt; for it to be disabled, but you can adjust that as
well if you want. Then just save the link as a bookmark (for example, by
right-clicking it) and you’re done!&lt;/p&gt;

&lt;form class="simple-form"&gt;
  &lt;label for="ip"&gt;Pi-hole IP:&lt;/label&gt;
  &lt;input id="ip" type="text" value="192.168.0.1" /&gt;
  &lt;br /&gt;
  &lt;label for="webpw"&gt;webpassword:&lt;/label&gt;
  &lt;input id="webpw" type="text" value="cec933c941073878ba603c01cd1b96" /&gt;
  &lt;br /&gt;
  &lt;label for="duration"&gt;Duration (s):&lt;/label&gt;
  &lt;input id="duration" type="number" value="30" /&gt;
  &lt;br /&gt;
 &lt;button type="button"&gt;Generate Link!&lt;/button&gt;
&lt;/form&gt;

&lt;p&gt;&lt;strong&gt;Bookmark this link:&lt;/strong&gt; &lt;a href="http://192.168.0.1/admin/api.php?disable=30&amp;amp;auth=" id="link"&gt;Disable Pi-hole (30s)&lt;/a&gt;&lt;/p&gt;

&amp;amp;</description><author>Mike Kasberg's Blog</author><pubDate>Sat, 27 Jun 2020 05:45:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/06/26/a-bookmark-to-temporarily-disable-your-pihole.html</guid></item><item><title>Links - June 27, 2020</title><link>https://faingezicht.com/links/2020/06/27/links/</link><description/><author>Avy Faingezicht</author><pubDate>Sat, 27 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/links/2020/06/27/links/</guid></item><item><title>Four years of Nextcloud</title><link>https://kyrofa.com/posts/four-years-of-nextcloud/</link><description>I&amp;rsquo;m a few weeks late on celebrating Nextcloud&amp;rsquo;s four year anniversary, but I&amp;rsquo;m doing it anyway! My how time flies. I became a part of the ownCloud community back in 2012. Heck, you can still find blog posts about how I ran it on this very blog if you scroll down far enough. Then, in 2015, I saw the post about the Western Digital/ownCloud collaboration on what would eventually become the Nextcloud Box.</description><author>kyrofa's blog</author><pubDate>Sat, 27 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://kyrofa.com/posts/four-years-of-nextcloud/</guid></item><item><title>Versioned Docs in 30 Seconds with Amplify Console's Branch Subdomains</title><link>https://www.swyx.io/amplify-console-branch-subdomains</link><description>Amplify Console just got the ability to create a custom subdomain for every new branch. This makes creating versioned docs a cinch!</description><author>swyx's site RSS Feed</author><pubDate>Fri, 26 Jun 2020 19:34:09 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/amplify-console-branch-subdomains</guid></item><item><title>Sharpening the Saw</title><link>/sharpen-the-saw/</link><description>&lt;p&gt;Sharpening the saw is Habit 7 in the cringe inducing book entitled &amp;quot;7 Habits of Highly Effective People&amp;quot;. This post isn't yet another book review but rather the work we do to make the rest of my work, better, faster and more consistently. The label Covey gave to this work was &amp;quot;sharpening the saw&amp;quot;.
It conveys the idea that, given a new saw, one cannot just continuously cut wood all day, every day. Time needs to be given to sharpen the saw, literally, so that the wood cutting rate remains consistent.&lt;/p&gt;
&lt;p&gt;As a developer, I interact with hundreds of tools, websites and system a day. Each one has it's own cognitive overhead such as keyboard shortcuts and the like. Furthermore, as technology is so rapidly evolving, there is seldom reason why you shouldn't attempt to iterate your approach to problems. My quest to sharpen the saw started, like most new things, with a question - &amp;quot;How can I make my life easier as less stressful&amp;quot;.&lt;/p&gt;
&lt;h2&gt;1. Keeping better personal notes&lt;/h2&gt;
&lt;p&gt;Most of the people I admire across a broad spectrum of industries love to keep notes. Learning from your mistakes is very easy to say but not so easy to actually do. And more importantly, implement a system to do so.
I solved this by doing the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creating a new GitHub repo called Notes, each note is then a simple text or markdown file. I chose GitHub for storing this so I do not need anything asides from my YubiKey and a terminal - simple and low friction when moving across machines. Also text will never die, platforms will, eventually - even the best&lt;/li&gt;
&lt;li&gt;Treating my Todoist Inbox as a brain dump - I run my life on Todoist, so it's a super easy way, if I have a bunch of ideas to just dump them into Todoist. Since this is my task manager, I can process them as if they were a task. If they need action, I will expand them and sort them into their appropriate project. If the idea is a new project entirely (more than 2 actions), I will either do it or look at where I can schedule it&lt;/li&gt;
&lt;li&gt;Keeping a &lt;code&gt;currently.txt&lt;/code&gt; file open in one terminal window that I update before I context switch to something else. For example, if my wife calls me to help her with something round the house or someone comes to the door, I quickly write what I was &amp;quot;currently&amp;quot; doing. When I then come back, rather than trying to rack my brain to figure out where I was, I just read that document.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. Improving my Desktop Productivity Setup&lt;/h2&gt;
&lt;p&gt;I want to expand on this section a bit more in a personal infrastructure post but here is a brief summary of how I got my PC to work for me rather than me working for it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Store my dotfiles in GitHub and have them auto sync from any of machines when they are edited, this keeps the aliases, functions and programs in sync across the machines&lt;/li&gt;
&lt;li&gt;Switch my terminal from Bash to ZSH and install a bunch of plugins to make hopping around the shell easier&lt;/li&gt;
&lt;li&gt;Got a USB switcher so I could clamshell my Macbook's (personal and work) and switch between them easily&lt;/li&gt;
&lt;li&gt;Got well acquainted with the *nix terminal and keyboard shortcuts&lt;/li&gt;
&lt;li&gt;Purchased a solid keyboard as I try to avoid using the mouse at all costs&lt;/li&gt;
&lt;li&gt;Analysing all software deeply and attempting to speed up its performance as much as possible&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. Dedicated learning time&lt;/h2&gt;
&lt;p&gt;Each week, I spend at least 20 minutes learning something new. But it can't just be anything. It has to be something that will further my knowledge in a new paradigm. Learning a new JS framework will not extend my knowledge in a new paradigm. Learning how the TCP/IP stack works in *nix or how a certain part of the V8 engine works will.
Personally, I enjoy teaching others so part of my &amp;quot;learning&amp;quot; time can involve teaching others things I already know. The effect this has on the brain and knowledge storage is fairly well documented and I'm not a neuroscientist (yet) so I'll leave it to them to explain why this is so effective at knowledge retention.&lt;/p&gt;
&lt;p&gt;Additionally, I find attending meetups (such as LeicesterJS, one I help run), and speaking with other developers fascinating. I like to hear of their problems and throw myself in. It helps improve my questioning ability - something I did not cultivate enough early in my career. In the past, I was very much &amp;quot;open the bonnet and have a rummage&amp;quot; kind of debugger, this approach works for a lot of problems, but there are others such as ones &lt;a href="https://digest.bps.org.uk/2018/05/04/learning-by-teaching-others-is-extremely-effective-a-new-study-tested-a-key-reason-why/"&gt;documented&lt;/a&gt; where this strategy does not cut it. To combat this, I have invested time in trying to be better at asking questions. As a child we are very akin to simply asking &amp;quot;why&amp;quot; all the time, but asking good questions is more than just why as often things boil down to more than 1 problem. It's about asking questions that carve away at the ultimate nugget of truth based on absolutes.
These questions also help me when presenting new ideas. If I present an idea after having read about it on a large companies engineering blog, I would have no foundation of which to base my reasoning on. Instead, by gathering data and arriving at a solution that way, it has a basis to stand on. Don't try to wedge a solution from someone else into a problem you are experiencing, it mostly won't fit.&lt;/p&gt;
&lt;h2&gt;4. Post mortems and reviews&lt;/h2&gt;
&lt;p&gt;Part of learning from your mistakes involves reviewing what happened, what went wrong and most importantly why. Although at my workplace we do not have an engineering blog or a culture of writing post mortems for absolutely every issue, I've found it personally beneficial to keep a &amp;quot;war&amp;quot; log of all the big issues I've faced, why they came about and how we solved them. I keep these write ups in my personal notes.&lt;/p&gt;
&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;I'm happy I spent time doing this, and is a process I will continue to follow. Hopefully this helped you practically speaking as there is a lot of wish-wash in this sector. If you have any more suggestions let me know on &lt;a href="https://twitter.com/joshghent"&gt;twitter&lt;/a&gt;. You can also following progress of my startup &lt;a href="https://turboapi.dev"&gt;TurboAPI&lt;/a&gt; - &lt;a href="https://www.indiehackers.com/product/turboapi"&gt;here&lt;/a&gt;&lt;/p&gt;</description><author/><pubDate>Fri, 26 Jun 2020 13:17:00 GMT</pubDate><guid isPermaLink="true">/sharpen-the-saw/</guid></item><item><title>Sugata Mitra - The Hole in the Wall</title><link>https://yasha.solutions/posts/sugata-mitra-the-hole-in-the-wall/</link><description>The saying goes it takes a village to raise a kid.
But what if you leave a computer in the village?
That&amp;rsquo;s more or less what the idea Mitra has been developping for many years, as part of an experiment aiming at testing the principles that Mitra named Minimally invasive education.
The project started in 1999 (20+ years ago).
  Kalkaji, New Delhi
  The story is best told by Mitra himself in one of his many TED talks, but the TLDR version is pretty simple:</description><author>Yasha Solutions</author><pubDate>Fri, 26 Jun 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://yasha.solutions/posts/sugata-mitra-the-hole-in-the-wall/</guid></item><item><title>COVID19 brings more proprietary software to italian public schools</title><link>https://stop.zona-m.net/2020/06/covid19-brings-more-proprietary-software-to-italian-public-schools/</link><description>&lt;p&gt;Because it costs less, of course. But&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 25 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/covid19-brings-more-proprietary-software-to-italian-public-schools/</guid></item><item><title>Link to https://www.cassie.codes/</title><link>https://qubyte.codes/links/1593104782918</link><description>&lt;p&gt;Cassie&amp;#x27;s new blog looks great! &lt;a href="https://qubyte.codes/links/1593104782918"&gt;Cassie Evans&amp;#x27;s Blog&lt;/a&gt;&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Thu, 25 Jun 2020 20:06:22 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/links/1593104782918</guid></item><item><title>Minimal CSS</title><link>https://benovermyer.com/blog/2020/06/minimal-css/</link><description>&lt;p&gt;After years of using a CSS framework for my site, I've now dropped it entirely.&lt;/p&gt;
&lt;p&gt;Inspired by the movement to reduce the filesize and cruft of websites that have no need for graphics or heavy JavaScript, I decided to cut out as much as possible. This started a few months ago with removing my web fonts and replacing them with system fonts.&lt;/p&gt;
&lt;p&gt;Today, I removed &lt;a href="https://bulma.io" rel="external"&gt;Bulma&lt;/a&gt; from my site. I opted instead for the most basic CSS I could. I still write it as SCSS, and I rely on several CSS3 features, but the file size has dropped dramatically. So has the load time.&lt;/p&gt;
&lt;p&gt;This may be just a phase, but for now, I'm really enjoying the new minimal aesthetic.&lt;/p&gt;</description><author>Ben Overmyer's Site</author><pubDate>Thu, 25 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://benovermyer.com/blog/2020/06/minimal-css/</guid></item><item><title>On being an idiomatic JavaScript programmer</title><link>https://nickolinger.com/blog/on-being-an-idiomatic-javascript-programmer</link><description>What does it mean to write idiomatic JavaScript in 2020?</description><author>&amp;gt; nick</author><pubDate>Thu, 25 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nickolinger.com/blog/on-being-an-idiomatic-javascript-programmer</guid></item><item><title>My personal website v2.0</title><link>https://www.mootoday.com/blog/my-personal-website-v2-0</link><description>A complete rewrite of my personal website and blog with Svelte, Sapper, mdsvex and Tailwind CSS. Blog posts can be reviewed on a preview URL and discussed in a pull request. The site follows best practices; accessibility (a11y), top Lighthouse score, Google's web vitals, and SEO.</description><author>www.mootoday.com - RSS Feed</author><pubDate>Wed, 24 Jun 2020 16:48:01 GMT</pubDate><guid isPermaLink="true">https://www.mootoday.com/blog/my-personal-website-v2-0</guid></item><item><title>Starting Over: The Gear I Would Buy if I Had to Do it All Over Again</title><link>https://zacs.site/blog/starting-over.html</link><description>&lt;p&gt;As best I can remember, I have bought seventeen backpacks in my life. Seven backpacking ones&lt;sup id="fnref1"&gt;&lt;a href="#fn1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;, and a mix of ten book bags and assault packs&lt;sup id="fnref2"&gt;&lt;a href="#fn2" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;. Each time I bought something new, I upgraded in some way. I went from the &lt;a href="https://www.outdoorgearlab.com/reviews/camping-and-hiking/budget-backpacking-pack/teton-sports-scout-3400"&gt;Teton Sports Scout 3400&lt;/a&gt; to the &lt;a href="http://www.texsport.net/canvas-bags-gear-bags/wolcott-external-frame-pack.html"&gt;Texsport Wolcott&lt;/a&gt; because it carried better. Next came the &lt;a href="https://speartacticalreviews.wordpress.com/2015/08/06/kelty-falcon-664000-reveiw/"&gt;Kelty Falcon 4000&lt;/a&gt; because I needed more space and wanted greater versatility and modularity. I continued pursuing those goals in purchasing the &lt;a href="https://www.itstactical.com/gear/carry-everything-and-the-kitchen-sink-with-the-eberlestock-skycrane-ii-pack/"&gt;Eberlestock J79 Skycrane II&lt;/a&gt;, which I eventually replaced with the &lt;a href="https://blisterreview.com/recommended/mystery-ranch-terraplane"&gt;Mystery Ranch Terraplane&lt;/a&gt;. With nine more liters of space yet coming in at 60% of the weight, I could not rationalize sticking with the Skycrane II no matter how much I liked it.  &lt;/p&gt;
                &lt;p&gt;&lt;a href="https://zacs.site/blog/starting-over.html"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Wed, 24 Jun 2020 13:15:03 GMT</pubDate><guid isPermaLink="true">https://zacs.site/blog/starting-over.html</guid></item><item><title>On the meaningless reporting on COVID19</title><link>https://stop.zona-m.net/2020/06/on-the-meaningless-reporting-on-covid19/</link><description>&lt;p&gt;Or many other topics, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 24 Jun 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/on-the-meaningless-reporting-on-covid19/</guid></item><item><title>True to self</title><link>http://dimitarsimeonov.com/2020/06/24/true-to-self</link><description>&lt;p&gt;According to a famous study, the most common regret of old people on their deathbed was “I wish I’d had the courage to live a life true to myself, not the life others expected of me”.&lt;/p&gt;

&lt;p&gt;Well, I’d like to dissect a little bit what “true to self” might mean. How do we know which of our thoughts are coming from our true self, and which of them are coming from outside. I am not going to claim that someone is trying to plant certain thoughts in your head. Instead I assert that &lt;strong&gt;most of our thoughts are not genuine.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They are mind tricks played on us by our environment. Every tweet, post, article that we read, every ad that we see, every movie or show that we watch occupies a part of our consciousness. It doesn’t go away when the event is over, but instead it lingers and decays. And then the environment re-enforces it.&lt;/p&gt;

&lt;p&gt;This dynamic is hard to see from an individual level. We all are able to think critically about our environment and &lt;em&gt;seemingly&lt;/em&gt; make each decision for ourselves. Yet, if we switch the vantage point and look in aggregate it becomes crystal clear.&lt;/p&gt;

&lt;p&gt;Consider a parallel universe far far away where exists an imaginary company called JarJar which produces and sells jars. They create a new type of jar called “meesan jarjar”. In terms of quality and price the meesan jarjars are the same as mason jars in our universe. Over time JarJar the company does all kinds of marketing, from traditional ads to hidden ads, to reverse psychology PR. They do packaging experiments, promotions, and discounts. They pay the “customer acquisition cost” and they capture a part of the market.&lt;/p&gt;

&lt;p&gt;Each individual customer may have their own reasons for going with a meesan jarjar instead of mason jars, which may seem rational. Asking each of them might reveal a story about how their reasons, or lack of reasons. The reason might be clear to them or it might be subtle enough that it evades reasoning. The most effective reasons are strong enough to affect behavior, yet subtle enough that the subject doesn’t realize they’re being controlled.&lt;/p&gt;

&lt;p&gt;When you look in aggregate - the fact is there - a significant number customers have changed their behavior as a result of JarJar’s growth efforts. In other words - JarJar has pulled a mind trick on us.&lt;/p&gt;

&lt;p&gt;A company, a movement, a religion, an influencer doesn’t care what we think, as long as we do what they want us to do - to buy their product, to pray to their god, to shout their slogans, or to like and subscribe to their channel. They just try convincing us to bid their will in various ways, until something works. They don’t necessarily realize the mind tricks they’re playing on us - they’re just doing whatever works for them.&lt;/p&gt;

&lt;p&gt;…&lt;/p&gt;

&lt;p&gt;Back to our individual point of view.&lt;/p&gt;

&lt;p&gt;Next time that we think we need to buy a certain item - where did that thought come from? What does buying that item achieve for us? If I buy meesan jarjars, do they make my cooking more enjoyable?&lt;/p&gt;

&lt;p&gt;These questions are hard to answer when we identify with our thoughts. Especially since all mind tricks worth their dinero are subtler than thoughts. Instead, we can observe our thoughts, but try not to identify with them. For example, if you think &lt;em&gt;“I need to call Jar Jar”&lt;/em&gt;, instead reframe it as &lt;em&gt;“There is a thought that I need to call Jar Jar”&lt;/em&gt;. Then go one step further and ask &lt;em&gt;“Where is that thought coming from?”&lt;/em&gt; Is it coming from an inner need to spend time with a friend, or is it coming from a social obligation.&lt;/p&gt;

&lt;p&gt;Going through that exercise even a couple times reveals that &lt;strong&gt;we cannot trust our thoughts to have our best interest in mind.&lt;/strong&gt; This is a deeply unsettling conclusion. For a while I didn’t know what to do with it.&lt;/p&gt;

&lt;p&gt;I still don’t know, but I’ve been taking steps to try and re-align my thoughts with my happiness and prosperity.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Making space for my thoughts to develop without external influence. I often place my phone and laptop and other electronics outside the room at night, and I only keep a notebook to write stuff down. After a few minutes my mind stops itching for my phone.&lt;/li&gt;
  &lt;li&gt;Meditating and trying to get in touch with my feelings, to evaluate stuff in my life through a clearer  perception of my feelings. Meditation calms the waves of my emotions and makes it easy to see what’s beneath them. I’m still a beginner.&lt;/li&gt;
  &lt;li&gt;Trying to get my information from more primary sources and randomized controlled experiments. While I still consume a lot of “clickbait” high glycemic index information, I’ve been appreciating more the process of making my own conclusions from the facts.&lt;/li&gt;
  &lt;li&gt;I’ve also eliminated caffeine and greatly reduced the amount of alcohol I consume. These are ways to escape from what’s actually happening in my head. Caffeine suppresses my feelings, and alcohol suppresses my thinking.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I opened this story with the study of the regrets of the dying. And this study has had a bunch of criticism. To be honest, today I don’t care about minimizing my regret when I get old and feeble. What I care is about is living in a manner true to myself, because I’ve thought about it and I’ve searched my feelings, and I’ve found that I suffer when the independence of my thinking is impaired.&lt;/p&gt;

&lt;p&gt;Thank you for reading.&lt;/p&gt;</description><author>D13V</author><pubDate>Wed, 24 Jun 2020 04:47:14 GMT</pubDate><guid isPermaLink="true">http://dimitarsimeonov.com/2020/06/24/true-to-self</guid></item><item><title>Caching computation in Python</title><link>https://heitorpb.github.io/bla/caching-python/</link><description>What is memoization and how to use it to cache the output of functions in Python.</description><author>Heitor's log</author><pubDate>Wed, 24 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://heitorpb.github.io/bla/caching-python/</guid></item><item><title>Links - June 24, 2020</title><link>https://faingezicht.com/links/2020/06/24/links/</link><description/><author>Avy Faingezicht</author><pubDate>Wed, 24 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/links/2020/06/24/links/</guid></item><item><title>Planning the GHT?</title><link>https://www.wildernessprime.com/expeditions/great-himalaya-trail/planning/</link><description>&lt;h1&gt;Resources for people planning the Great Himalaya Trail.&lt;/h1&gt;&lt;p&gt;&lt;img alt="" src="https://res.cloudinary.com/wildernessprime/image/upload/w_1600,dpr_auto/v1550183229/overview-map-5000.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The Great Himalaya Trail is the combination of several trail networks stretching the length of the
Himalaya range, with sections in India, Nepal, Bhutan and Tibet. From April to September 2019 &lt;a href="https://www.wildernessprime.com/about/"&gt;Mathi&lt;/a&gt; and I
hiked the Nepal section from Kanchenjunga (on the Indian border in the East) to Hilsa (on the Chinese border
in the West).&lt;/p&gt;
&lt;p&gt;The concept of the high route is that it follows the highest feasible continuous route across the
country, averaging 3,750m (12,000ft) of elevation, with passes reaching 6,200m (20,300ft).
In total 1,400km (870 miles) over 115 days of hiking, with 120,000m (400,000ft) of elevation gain -
that's an average climb of 1,000m (3,300ft) per day. Including rest days, we completed the trek in 154 days.&lt;/p&gt;
&lt;p&gt;Although the route passes through the more popular trekking areas of Everest and Annapurna, many
sections visit some of the most remote corners of Nepal. We completed trek with the minimum of support,
so no guides or porters us unless absolutely necessary for safety or mandated by local law.&lt;/p&gt;
&lt;h2 id="latest-info"&gt;Latest info&lt;/h2&gt;
&lt;p&gt;After finishing the GHT, I made comprehensive trail notes and a FAQ for people planning the trail:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/faq/"&gt;Frequently Asked Questions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gps-routes/"&gt;GPS routes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/trail-notes/"&gt;Trail notes&lt;/a&gt; (also available &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/trail-notes-no-maps/"&gt;without maps&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/spreadsheets/d/14x_OJ4mJNoHuj1LnYnyGULdE3P9kG6CwOdY1t0sv_H8/edit"&gt;Trail notes data (spreadsheet)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="questions"&gt;Questions?&lt;/h2&gt;
&lt;p&gt;A great place to ask questions is my &lt;a href="https://chat.whatsapp.com/D5kC4kBc7SALDE8WctMmrH"&gt;GHT WhatsApp group&lt;/a&gt;.
In the group are several people who have completed the trek, and several who are planning it.&lt;/p&gt;
&lt;h2 id="vlog"&gt;Vlog&lt;/h2&gt;
&lt;p&gt;I filmed a short vlog style video every day of the trek. You can find weekly summaries here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-01"&gt;Week 1: Kanchenjunga&lt;/a&gt; - I'm hiking up the Kanchenjunga Base Camp trail towards the far north east corner of Nepal.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-02"&gt;Week 2: Kanchenjunga&lt;/a&gt; - I reached the amazing Kanchenjunga Base Camp, and started the first really remote section.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-03"&gt;Week 3: Makalu&lt;/a&gt; - The trail is getting really tough as I cross the first high pass.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-04"&gt;Week 4: Makalu&lt;/a&gt; - I get a helicopter rescue and finally meet my hiking buddy Mathilde.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-05"&gt;Week 5: Everest&lt;/a&gt; - We cross the highest, most technical and most dangerous passes of the whole trek.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-06"&gt;Week 6: Everest&lt;/a&gt; - We hike through the most spectacular scenery as we take a detour to Cho Oyu Base Camp.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-07"&gt;Week 7: Rolwaling&lt;/a&gt; - More amazing scenery as we tackle yet another major pass.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-08"&gt;Week 8: Rolwaling&lt;/a&gt; - We leave the high mountains and get our first taste of how hot and humid Nepal can be at the lower elevations.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-09"&gt;Week 9: Helambu&lt;/a&gt; - A week of slogging through heat, humidity and leeches into the high mountains again.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-10"&gt;Week 10: Langtang&lt;/a&gt; - Another huge pass with full mountaineering gear, and we take a very refreshing swim on the way down.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-11"&gt;Week 11: Ganesh Himal&lt;/a&gt; - Finally monsoon hits, we both get sick and make some huge navigational blunders. A hard week!&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-12"&gt;Week 12: Manaslu&lt;/a&gt; - Some more pleasant trekking and spectacular views as we join the Manaslu Circuit trail.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-13"&gt;Week 13: Annapurna&lt;/a&gt; - Into the Annapurna region now, so easy hiking through beautiful scenery, but a big change of plans at the end.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-14"&gt;Week 14: Mustang&lt;/a&gt; - We take an unconventional exit from Annapurna, and enter the utterly spectacular Dolpa region.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-15"&gt;Week 15: Dolpa&lt;/a&gt; - The scenery gets better and better as we trek through Dolpa, but will we make it out of the mountains in one piece? Major navigation and tent disasters this week.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-16"&gt;Week 16: Dolpa&lt;/a&gt; - Long, hot, exhausting days across rugged terrain as we continue through Dolpa&amp;hellip; and we're lucky to be alive after some terrible decisions.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-17"&gt;Week 17: Rara&lt;/a&gt; - Baking in the sun, sinking in the mud, and we cross the final 5,000m pass of the trek.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/week-18"&gt;Week 18: Humla&lt;/a&gt; - An emotional end to the trek as we arrive at the Chinese border.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="older-info"&gt;Older info&lt;/h2&gt;
&lt;p&gt;Here's some blog posts I wrote during my preparation for the GHT. Some have post-trail updates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Itinerary: &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/itinerary-summary/"&gt;Summary&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/itinerary-resupply/"&gt;Resupply&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Navigation: &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/navigation-sources/"&gt;Sources&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/navigation-methods/"&gt;Methods&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/navigation-gps/"&gt;GPS routes&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/navigation-flashcards/"&gt;Flashcards&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/navigation-emergencies/"&gt;Emergencies&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/navigation-apps/"&gt;Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gear: &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gear-pack/"&gt;Pack&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gear-camping/"&gt;Camping&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gear-sleeping/"&gt;Sleeping&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gear-cooking/"&gt;Cooking&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gear-mountaineering/"&gt;Mountaineering&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gear-miscellaneous/"&gt;Miscellaneous&lt;/a&gt;, &lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/gear-clothes/"&gt;Clothes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/communication/"&gt;Communication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/food/"&gt;Food&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/temperatures/"&gt;Temperatures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wildernessprime.com/expeditions/great-himalaya-trail/trash/"&gt;Trash&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Wilderness Prime</author><pubDate>Wed, 24 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.wildernessprime.com/expeditions/great-himalaya-trail/planning/</guid></item><item><title>Configuration Management in Python</title><link>https://trigonaminima.github.io/2020/06/py-config/</link><description>There are a lot of ways to maintain configuration in Python project. I’ve recently learnt to do it in way that is not something new that I’ve found, but it was new to me. I’ll discuss my progression from basic hard-coding constants in a project to this new method.</description><author>Playground</author><pubDate>Wed, 24 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://trigonaminima.github.io/2020/06/py-config/</guid></item><item><title>The game breaking Deal Breaker card</title><link>https://captnemo.in/monopoly-deal/</link><description>&lt;p&gt;I have a presentation I sometimes give about Monopoly being a terrible game&lt;sup id="fnref:1"&gt;&lt;a class="footnote" href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;.
I usually end it by pointing the audience to Monopoly Deal, which I introduce it as
“the only Monopoly edition you can enjoy”.&lt;/p&gt;

&lt;p&gt;The advantages are obvious:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Much shorter game length.&lt;/li&gt;
  &lt;li&gt;No dice rolls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even if you lose badly on luck, you’ve only lost 15 minutes. While it is better than Monopoly, that isn’t to say it is a well designed game (6.3 on BoardGameGeek).&lt;/p&gt;

&lt;p&gt;The one major dent in the otherwise decent game is the “Deal Breaker” card, which breaks the game. I’ve house-ruled the game
since forever to keep the card out of the game, since it breaks the most important rule of game design:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;h2 id="games-should-be-fun"&gt;Games should be fun&lt;sup id="fnref:9"&gt;&lt;a class="footnote" href="#fn:9" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;Deal Breaker stops people from doing that. How? Read on.&lt;/p&gt;

&lt;p&gt;&lt;img alt="" src="/img/deal-breaker.jpg" /&gt;&lt;/p&gt;

&lt;aside&gt;
&lt;details&gt;
Aside: Monopoly Deal (2-5 players) Basic Rules (Click to expand)
The objective of the game is to get 3 sets of properties in distinct colors. The first player to 3 sets wins the game. There are some action cards, which let you get money/properties from other players. Important action cards, relevant for this post:
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Deal Breaker&lt;/strong&gt; card lets you "steal" a complete set from another player.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Just Say No&lt;/strong&gt; card lets you say no to any action that any player takes against you. It is the only way to counter a Deal Breaker card.&lt;/li&gt;
&lt;/ul&gt;

&lt;img alt="Just say no card in Monopoly deal" src="/img/just-say-no.jpg" /&gt;

&lt;a href="https://youtu.be/Gc0XrTjmCV8"&gt;Here's a short 3 minute video&lt;/a&gt; if you'd like to learn the complete rules.
&lt;/details&gt;
&lt;/aside&gt;
&lt;hr /&gt;

&lt;p&gt;A lot of metagaming discussion with &lt;a href="#link-somewhere-nice"&gt;friends&lt;/a&gt; resulted in the following observations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The Deal Breaker is a very powerful card (It takes you 1/3rd of the way to a victory).&lt;/li&gt;
  &lt;li&gt;You can assume the single Deal Breaker card to be worth a complete set.&lt;/li&gt;
  &lt;li&gt;The best use of such a card is to &lt;em&gt;win the game&lt;/em&gt;. Using it earlier means giving other players a chance to drag you down from 2-&amp;gt;1 set. But if you use it to win the game, the game ends immediately.&lt;/li&gt;
  &lt;li&gt;Hence, Deal Breaker will always end up being the last card of the game.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are playing a game with the Deal Breaker card, you’d want to save it till the very end, and win the game with it. The only possible case for not winning is the other player having a “Just Say No” card, and playing it on the Deal Breaker to negate your move.&lt;/p&gt;

&lt;p&gt;Ergo, the metagame converges to the following:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Any game with Deal Breaker will end up having the Deal Breaker as the last turn.&lt;/li&gt;
  &lt;li&gt;The only way to prevent someone else from winning with the Deal Breaker is to play a Just Say No on the Deal Breaker.&lt;/li&gt;
  &lt;li&gt;If you have a Just Say No card, you &lt;em&gt;must save it till the end of the game for the Deal Breaker&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are 2 Deal Breakers, and 3 Just Say Nos in the game. However, considering a single Deal Breaker is enough to win the game, and the chances of you getting a second of either card are fairly small - both the Deal Breaker and Just Say No cards will end up getting hoarded for the endgame.&lt;/p&gt;

&lt;p&gt;What this results in is something that breaks the fundamental rule of game design:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;h2 id="players-are-disincentivized-from-playing-the-just-say-no-card"&gt;Players are disincentivized from playing the Just Say No card.&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;As any Exploding Kittens player can confirm, playing a Just Say No card is one of the coolest moves in the game. It lets you stick it to the player who dares ask you for 8M&lt;sup id="fnref:7"&gt;&lt;a class="footnote" href="#fn:7" rel="footnote"&gt;3&lt;/a&gt;&lt;/sup&gt; rent. It lets you pretend you’re counting your money, and then pull out a trump card and feel awesome! By disincentivizing players from playing the coolest card in the game, the Deal Breaker card makes things less fun. And that breaks our “rule of fun”.&lt;/p&gt;

&lt;p&gt;In fact, the mere existence of a Deal Breaker card changes the equation. Note that there may be cases where you lose with a Just Say No card because you were hoarding it for the eventual Deal Breaker (which might never come). Someone asks you for 4M rent, and you have to pay up despite having a Just Say No card, because &lt;em&gt;you must save the damn card for when someone steals your set&lt;/em&gt;. There are a few rare exceptions, but the Deal Breaker creates too many plays where not playing the Just Say No is indeed the correct move.&lt;/p&gt;

&lt;p&gt;So here is the more interesting corollary observation:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;h2 id="the-mere-existence-of-the-deal-breaker-card-breaks-the-game-by-making-the-just-say-no-card-unplayable-and-worthless"&gt;The mere existence of the Deal Breaker card breaks the game by making the Just Say No card unplayable and worthless.&lt;sup id="fnref:2"&gt;&lt;a class="footnote" href="#fn:2" rel="footnote"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hence, if you’re playing Monopoly Deal, please house-rule the Deal Breaker card and make it easier for everyone. Two easy ways are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Remove the card from the game entirely.&lt;/li&gt;
  &lt;li&gt;Reduce the power of the game to be same as a Forced Deal, except let it break a set.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;I have the &lt;a href="https://slides.com/captn3m0/monopoly"&gt;slides here&lt;/a&gt;, but they don’t stand well on their own. &lt;a class="reversefootnote" href="#fnref:1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:9"&gt;
      &lt;p&gt;Any game that eliminates players from the game breaks this rule. Popular examples are Monopoly and Mafia/Werewolf. Also see &lt;a href="https://danielsolisblog.blogspot.com/2015/07/one-thing-to-avoid-in-game-design.html"&gt;this amazing post&lt;/a&gt; on the biggest mistake that Guillotine makes (The “Callous Guard” card). &lt;a class="reversefootnote" href="#fnref:9"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:7"&gt;
      &lt;p&gt;Turns out, that there is no symbol in the unicode for &lt;a href="https://boardgames.stackexchange.com/questions/23909/what-is-the-monopoly-m-symbol-called"&gt;Monopoly Money&lt;/a&gt; &lt;a class="reversefootnote" href="#fnref:7"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:2"&gt;
      &lt;p&gt;We decided Deal Breaker might make sense in 6+ player games with many more cards, where it might help even the playing grounds a bit for a losing player (much more likely) instead of helping the almost-winning-player score a victory. &lt;a class="reversefootnote" href="#fnref:2"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>Nemo's Home</author><pubDate>Wed, 24 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://captnemo.in/monopoly-deal/</guid></item><item><title>More alternatives to Google Analytics</title><link>https://lwn.net/Articles/824294/</link><description>Looks at some heavier replacements for Google Analytics, as well as the GoAccess log-based analytics tool (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Wed, 24 Jun 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/824294/</guid></item><item><title>Software Entropy</title><link>https://camhashemi.com/essays/software-entropy/</link><description>&lt;h2 id="defining-entropy"&gt;Defining Entropy&lt;/h2&gt;&lt;p&gt;Entropy is a measure of chaos, or disorder, in a system.&lt;/p&gt;&lt;p&gt;My college physics professor described entropy using two shoe closets.&lt;/p&gt;&lt;p&gt;Imagine a clean shoe closet, where all shoes are paired and sorted by color. The closet’s entropy is the total number of arrangements its shoes can have. A clean closet’s entropy is relatively small. There may be a few pairs of grey or blue shoes that can be switched around – but this doesn’t add much complexity. In a closet with low entropy, it’s easy to add or remove shoes from that closet as needed.&lt;/p&gt;&lt;p&gt;Now imagine a messy shoe closet. None of the shoes are paired, and they’re all tangled in a big pile. How many possible combinations can these shoes be in? You can quickly find out by trying to pull out the pair you want. The messy shoe closet has a much greater entropy than the clean one.&lt;/p&gt;&lt;p&gt;In short, we measure entropy by counting the number of possible states a system can be in. More states mean more entropy.&lt;/p&gt;&lt;h2 id="entropy-in-software"&gt;Entropy in Software&lt;/h2&gt;&lt;p&gt;In software, our building blocks are simple enough for us to measure entropy in a crude way. Take this model for example:&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-scala"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #a6e22e;"&gt;Transaction&lt;/span&gt;&lt;span style="color: #f92672;"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; createdAt&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; buyerId&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;String&lt;/span&gt;&lt;span style="color: #f92672;"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; sellerId&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;String&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; amount&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Int&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #f92672;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As simple as it seems, this model is like our messy shoe closet. There are many more ways for this model to be wrong than there are for it to be right. We can see that by comparing it to an organized shoe closet:&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-scala"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #a6e22e;"&gt;Transaction&lt;/span&gt;&lt;span style="color: #f92672;"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; createdAt&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;DateTime&lt;/span&gt;&lt;span style="color: #f92672;"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; buyerId&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;UserId&lt;/span&gt;&lt;span style="color: #f92672;"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; sellerId&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;UserId&lt;/span&gt;&lt;span style="color: #f92672;"&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; amount&lt;span style="color: #66d9ef;"&gt;:&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;Price&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #f92672;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When &lt;code&gt;createdAt&lt;/code&gt; was an arbitrary string, it could take on invalid values “foo” and “bar” just as easily as a valid value “06-23-2020”. There are many more possible states that the field can be in, and most of them are invalid. This choice of a broad data type allows chaos into our model. This unwanted chaos leads to misunderstandings, bugs, and wasted energy.&lt;/p&gt;&lt;p&gt;When each model is strongly typed to a strict set of values, this chaos is minimized. DateTime, UserId, and Price are typed such that all possible values are valid. Accordingly, these types are more predictable, easier to manipulate, and lead to less surprises in practice.&lt;/p&gt;&lt;p&gt;As in life, entropy is not all bad – some of it is desirable and some of it is not. In software, we need entropy to a certain extent: our code is valuable &lt;em&gt;because&lt;/em&gt; it supports a variety of possible dates, users, and prices. But when this chaos grows beyond the value it adds, our software becomes painful to use and painful to maintain.&lt;/p&gt;&lt;h2 id="modeling-software-entropy"&gt;Modeling Software Entropy&lt;/h2&gt;&lt;p&gt;Given our observations, we can describe a simple rule:&lt;/p&gt;&lt;p&gt;&lt;code&gt;complexity = number of total possible states&lt;/code&gt;&lt;/p&gt;&lt;p&gt;A construct with only a few possible states is simple. Booleans and enums are much simpler than strings. A system with one moving piece is much simpler than a system with many moving pieces.&lt;/p&gt;&lt;p&gt;Sometimes, our problems are essentially complex. In these cases, our solutions need some essential complexity to match. But when does essential complexity become unnecessary? In these cases, we can use another rule:&lt;/p&gt;&lt;p&gt;&lt;code&gt;cleanliness = number of valid possible states / number of total possible states&lt;/code&gt;&lt;/p&gt;&lt;p&gt;If there are thousands of total possible states, but only two of them are valid: it’s a messy solution. A simple example of this is representing a boolean value as a string.&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-python"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; value &lt;span style="color: #f92672;"&gt;==&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;"true"&lt;/span&gt;: do this&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;else&lt;/span&gt; &lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; value &lt;span style="color: #f92672;"&gt;==&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;"false"&lt;/span&gt;: do that&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;else&lt;/span&gt;: throw error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There are many ways for this code to go wrong; not just in execution but also in interpretation. Keeping our solutions clean improves correctness, readability, and maintainability. It’s one of the primary measures of “quality” in my view.&lt;/p&gt;&lt;h2 id="minimizing-software-entropy"&gt;Minimizing Software Entropy&lt;/h2&gt;&lt;p&gt;Given these definitions, we can ask ourselves some questions to guide our software decisions:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;How many possible states does this solution have?&lt;/li&gt;&lt;li&gt;How many of those states are invalid?&lt;/li&gt;&lt;li&gt;Is there any way to make the solution simpler, by trimming the number of &lt;em&gt;total&lt;/em&gt; possible states?&lt;/li&gt;&lt;li&gt;Is there any way to make the solution cleaner, by trimming the number of &lt;em&gt;invalid&lt;/em&gt; possible states?&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;The power of this concept is that it smoothly scales up and down the ladder of abstraction. It applies to basic data types just as well as it does to solution architecture and product development.&lt;/p&gt;&lt;p&gt;How many moving pieces does our solution need? When an unimaginable requirement flies in and tries to blow our solution to the ground, how many pieces can be left standing? When an unexpected input arrives, do invalid states propagate across the system, or are they contained and eliminated on sight? In short, how clean is our solution?&lt;/p&gt;&lt;p&gt;To make life possible, we utilize chaos by creating complex systems that support a diversity of people and their use cases. To make life predictable, we combat undesirable chaos by keeping those systems as clean and orderly as possible.&lt;/p&gt;&lt;p&gt;In software, we work in a world where chaos is measurable and cleanliness is achievable. We just need the right set of signals and responses to make it happen.&lt;/p&gt;</description><author>Cam Hashemi</author><pubDate>Wed, 24 Jun 2020 00:42:03 GMT</pubDate><guid isPermaLink="true">https://camhashemi.com/essays/software-entropy/</guid></item><item><title>Hardware Arx</title><link>https://truthindustri.es/hardware/2020/06/23/hardware-arx.html</link><description>Back in 2007 and 2008, I put together a system in Ruby which emulated a hardware drum machine, but changed one piece of the classic design: where most drum machines map beats to drums using booleans, this used floats. The floats expressed probability. Since then Arturia, Elektron, and other companies have released drum machines which allow you to do similar things, although they default every probability to 1.0, and you need to do some menu-diving in order to change that.</description><author>truth industri.es</author><pubDate>Tue, 23 Jun 2020 19:58:10 GMT</pubDate><guid isPermaLink="true">https://truthindustri.es/hardware/2020/06/23/hardware-arx.html</guid></item><item><title>Software-Mediated Drum Circle</title><link>https://truthindustri.es/hardware/2020/06/23/performance-system.html</link><description>Here’s a rough sketch for a software-mediated drum circle. This could be a good fit for Burning Man, a music festival, or similar settings.</description><author>truth industri.es</author><pubDate>Tue, 23 Jun 2020 18:58:10 GMT</pubDate><guid isPermaLink="true">https://truthindustri.es/hardware/2020/06/23/performance-system.html</guid></item><item><title>Things Quick Tip: Keyboard Shortcuts for Tags</title><link>http://evantravers.com/articles/2020/06/23/things-quick-tip-keyboard-shortcuts-for-tags/</link><description>&lt;p&gt;Things allows you to &lt;a href="https://culturedcode.com/things/mac/help/keyboard-shortcuts/"&gt;assign keyboard shortcuts&lt;/a&gt; to Tags.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="" src="https://images.evantravers.com/articles/2020/06/things_tags.png" /&gt;
  &lt;figcaption&gt;
    &lt;ol&gt;
      &lt;li&gt;Bring up the tag manager with &lt;code&gt;⌘⌃T&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;Notice the little boxes to the right? Click in one and press a key. Tada!&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This adds two bindings:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;With a task highlighted and press &lt;code&gt;⌃+&amp;lt;key&amp;gt;&lt;/code&gt;, Things.app will &lt;em&gt;toggle&lt;/em&gt; that tag on and off.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On any view, you can press &lt;code&gt;⌃⌥+&amp;lt;key&amp;gt;&lt;/code&gt; and Things.app will &lt;em&gt;filter&lt;/em&gt; that view to that tag.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I tend to not set &lt;em&gt;tons&lt;/em&gt; of these, because they conflict with my beloved &lt;a href="http://evantravers.com/articles/2019/04/03/my-keyboard-setup/#osx-readline"&gt;Readline shortcuts&lt;/a&gt;. I do use it for three tags: &lt;code&gt;Essential&lt;/code&gt;, which is just that. &lt;strong&gt;The One Thing&lt;/strong&gt; that I need to do that day. I also have bindings for tags I use for Focus level: &lt;code&gt;$High&lt;/code&gt; and &lt;code&gt;$Low&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I use the &amp;quot;toggle a tag&amp;quot; binding infrequently now. I typically handle all the tags at once in the inbox at the end of the day… and &lt;a href="https://twitter.com/culturedcode"&gt;@culturedcode&lt;/a&gt; added the feature where you can select multiple items and press &lt;code&gt;⌘⇧+T&lt;/code&gt; to tag multiple to-dos.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;⌃⌥+&amp;lt;key&amp;gt;&lt;/code&gt; filtering shortcut is still &lt;em&gt;very&lt;/em&gt; helpful, but increasingly I lean on using &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/a85100b1389b10c83a9e63eb279a2c83561b1784/spaces/deep.lua#L11"&gt;x-callback-urls to build filtered views&lt;/a&gt; for certain kinds of tasks.&lt;/p&gt;</description><author>trv.rs</author><pubDate>Tue, 23 Jun 2020 16:55:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/06/23/things-quick-tip-keyboard-shortcuts-for-tags/</guid></item><item><title>Upgrading Alpine Linux diskless setup on a Raspberry Pi</title><link>https://allanrbo.blogspot.com/2020/06/upgrading-alpine-linux-on-raspberry-pi.html</link><description>&lt;p&gt;Here's a procedure I've come up with to fully upgrade a diskless setup of Alpine Linux on a running Raspberry Pi. It's not pretty, but seems gets the job done, based on the tests I did.&lt;/p&gt;
&lt;p&gt;I tested this procedure on each version from 3.3 to to 3.12. The system I tested on had a working setup of Apache2 with PHP, as well as Samba. Here's the result of the testing.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Started with v3.3.&lt;/li&gt;
  &lt;li&gt;Confirmed 3.3 to 3.4. Package "php-apache2" package had disappeared and had to be manually replaced by "php5-apache2".&lt;/li&gt;
  &lt;li&gt;Confirmed 3.4 to 3.5.&lt;/li&gt;
  &lt;li&gt;Confirmed 3.5 to 3.6.&lt;/li&gt;
  &lt;li&gt;Confirmed 3.6 to 3.7.&lt;/li&gt;
  &lt;li&gt;Confirmed 3.7 to 3.8.&lt;/li&gt;
  &lt;li&gt;Could not boot after upgrading from 3.8 to 3.9. But a fresh installation of 3.9 was also unbootable, so assuming 3.9 is broken. Seems to be a &lt;a href="https://gitlab.alpinelinux.org/alpine/aports/-/issues/10155"&gt;known issue&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Confirmed 3.8 to 3.10. Package "php5-apache2" package had disappeared and had to be manually replaced by "php7-apache2".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The process I came up with can be summarized to:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Remount the SD card in read-write mode.&lt;/li&gt;
  &lt;li&gt;Move all files in the SD card FAT32 root to a subdirectory such as old/2020-06-23T04_22_54.&lt;/li&gt;
  &lt;li&gt;Download a fresh alpine-rpi-x.y.z-armhf.tar.gz file and untar it to the SD card root. This will give you Alpine Linux's newest Raspberry compatible Linux kernel image.&lt;/li&gt;
  &lt;li&gt;Remount the SD card back to read-only mode.&lt;/li&gt;
  &lt;li&gt;Update the /etc/apk/repositories (in the in-memory file system) to point to the target version.&lt;/li&gt;
  &lt;li&gt;Do an "apk upgrade --available" to download the updated versions of the packages you used, so they will be ready on the device after rebooting.&lt;/li&gt;
  &lt;li&gt;Reboot into the new setup.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If anything goes wrong, you can put the SD card in another PC, delete the broken setup, and copy your old working setup back out from the "old" directory.&lt;/p&gt;

&lt;p&gt;Here are the commands. As I don't know if this process will keep working in future versions, I recommend running them one line at a time and ensuring the line does what you expect.&lt;/p&gt;
&lt;pre class="code"&gt;
targetVersion=v3.12

# Move everything to a safe place as it is now.
mount -oremount,rw /media/mmcblk0p1
cd /media/mmcblk0p1
olddir=/media/mmcblk0p1/old/$(date --utc &amp;quot;+%Y-%m-%dT%H_%M_%S&amp;quot;)
mkdir -p $olddir
mv *  $olddir   # This will give a warning that it cannot move old into old. That's ok.
mv .* $olddir   # This will give a warning that it cannot move . and .. . That's ok.

# Download fresh Alpine Linux image and replace existing.
newImgFile=$(curl http://dl-cdn.alpinelinux.org/alpine/$targetVersion/releases/armhf/latest-releases.yaml --silent | grep &amp;quot;file: alpine-rpi-&amp;quot; | sed &amp;quot;s/ *file: //g&amp;quot;)
echo $newImgFile
mount -oremount,rw /media/mmcblk0p1
wget http://dl-cdn.alpinelinux.org/alpine/$targetVersion/releases/armhf/$newImgFile
wget http://dl-cdn.alpinelinux.org/alpine/$targetVersion/releases/armhf/${newImgFile}.sha512
sha512sum -c ${newImgFile}.sha512    # Ensure it says OK
tar -xzf $newImgFile
rm ${newImgFile}*
cp $olddir/usercfg.txt .
mount -oremount,ro /media/mmcblk0p1

# Update packages to the target distro.
cat &amp;gt; /etc/apk/repositories &amp;lt;&amp;lt;EOF
/media/mmcblk0p1/apks
http://dl-cdn.alpinelinux.org/alpine/$targetVersion/main
http://dl-cdn.alpinelinux.org/alpine/$targetVersion/community
EOF
setup-apkcache /media/mmcblk0p1/cache
apk update
apk upgrade --available
apk add
apk cache download
apk -v cache clean
lbu commit -d

reboot

# After reboot, ensure there aren't packages that no longer exist in this version.
apk add
&lt;/pre&gt;</description><author>Allan's Blog</author><pubDate>Tue, 23 Jun 2020 10:33:48 GMT</pubDate><guid isPermaLink="true">https://allanrbo.blogspot.com/2020/06/upgrading-alpine-linux-on-raspberry-pi.html</guid></item><item><title>How to Present Over Video Conference</title><link>https://nicolaiarocci.com/how-to-present-over-video-conference/</link><description>&lt;p&gt;As a non-native English speaker, presenting at conferences has always been super
challenging and intimidating. It&amp;rsquo;s even worse now that we&amp;rsquo;re forced into
online presenting because of the COVID19 situation. James Whittaker has a good
post on the topic, with great advice:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Remember, the inability to see and hear your audience is disconcerting but it
doesn’t mean you should give up. There are much bigger audiences in the wide
world that you will not have local access to. Getting good at video
presentations means expanding your audience and increasing your influence.&lt;/p&gt;</description><author>Nicola Iarocci</author><pubDate>Tue, 23 Jun 2020 08:05:25 GMT</pubDate><guid isPermaLink="true">https://nicolaiarocci.com/how-to-present-over-video-conference/</guid></item><item><title>5000 concepts for Europe: update 2020/06/23</title><link>https://stop.zona-m.net/2020/06/5000-concepts-for-europe-update-2020-06-23/</link><description>&lt;p&gt;Back in 2017, I launched the idea of a book listing the &lt;a href="https://stop.zona-m.net/2017/12/5000-concepts-for-europe-a-book-proposal"&gt;&amp;ldquo;5000 concepts that EVERY European should know&amp;rdquo;&lt;/a&gt;&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 23 Jun 2020 06:30:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/5000-concepts-for-europe-update-2020-06-23/</guid></item><item><title>Can You VNC to a Desktop on a Headless Raspberry Pi?</title><link>https://www.mikekasberg.com/blog/2020/06/22/vnc-for-headless-raspberry-pi.html</link><description>&lt;p&gt;&lt;strong&gt;No keyboard, mouse, or monitor required!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://www.mikekasberg.com/blog/2020/06/19/headless-setup-for-a-raspberry-pi-zero-w.html"&gt;last blog post&lt;/a&gt;, I figured out how to
enable SSH access to a Pi Zero W without attaching a mouse, keyboard, or
monitor. This us useful because it means you don’t need a micro-HDMI or
micro-USB OTG cable to attach a monitor, keyboard, or mouse. But can we take it
a step further? I wanted to find out if I could get a GUI desktop environment
running without attaching a monitor to the Pi. And I did it!&lt;/p&gt;

&lt;!--more--&gt;
&lt;p&gt;After gaining SSH access to the Pi, it was fairly simple to set up VNC and get
to a desktop environment on the Pi without ever connecting a monitor. Here’s
what I did:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Set up SSH access on the Pi (as I describe &lt;a href="https://www.mikekasberg.com/blog/2020/06/19/headless-setup-for-a-raspberry-pi-zero-w.html"&gt;here&lt;/a&gt;) and connect via SSH.&lt;/li&gt;
  &lt;li&gt;Setting up a VNC server on the Pi is easy because the OS &lt;a href="https://www.raspberrypi.org/documentation/remote-access/vnc/"&gt;comes with
one&lt;/a&gt;
installed. On the Pi, run &lt;code class="language-plaintext highlighter-rouge"&gt;sudo raspi-config&lt;/code&gt;.
    &lt;ol&gt;
      &lt;li&gt;Select &lt;code class="language-plaintext highlighter-rouge"&gt;Interfacing Options&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;Enable &lt;code class="language-plaintext highlighter-rouge"&gt;VNC&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;We’re done with config. Exit raspi-config.&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;On the computer you’re going to connect from, you’ll need to install a VNC
Viewer. Download and install &lt;a href="https://www.realvnc.com/en/connect/download/viewer/"&gt;RealVNC
Viewer&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Open VNC Viewer and connect to your Pi (using the same IP address you use to
ssh). Log in with the same credentials you use to SSH.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img alt="VNC Viewer showing Pi Desktop" src="https://www.mikekasberg.com/images/vnc-for-headless-raspberry-pi/vnc-pi.png" /&gt;&lt;/p&gt;

&lt;h2 id="is-this-actually-usable"&gt;Is This Actually Usable?&lt;/h2&gt;

&lt;p&gt;Kind of. I tested a VNC connection to a &lt;a href="https://www.raspberrypi.org/products/raspberry-pi-zero-w/"&gt;Raspberry Pi Zero
W&lt;/a&gt; desktop. The Pi
Zero has a 1GHz single-core CPU and only 512MB RAM – not much to work with! I
was able to log in to the default LXDE desktop environment, and the UI was
responsive enough to use.  Simple applications ran a little slow, but were
usable. It took about 4 seconds for the terminal app to open, and about 5
seconds for the text editor to open.  Once they were open, they were pretty
responsive. There wasn’t a noticeable delay when typing. Bigger apps, however,
weren’t really usable. Chromium took a whopping 35 seconds to open, and was very
slow to open a new tab. It felt like running Windows XP on an underpowered
computer. I think the slowness was primarily due to the limitations of the Pi
itself rather than the VNC setup.&lt;/p&gt;

&lt;p&gt;So overall, the VNC user interface would work well enough for doing some simple
setup, or installing whatever software you want to run on the Pi. But more
intensive things like web browsing are too slow to be really useful. And that
makes sense. If you want to use the Pi as a simple desktop computer for things
like web browsing, you’ll want to get a better version than the Pi Zero anyway.
I’d say the Pi Zero is &lt;strong&gt;not&lt;/strong&gt; usable for even simple desktop work.  But if
you’re using it for a simple project or home server and you need a GUI to set it
up, VNC could be really helpful! Honestly though, if you’re comfortable enough
at the terminal, I’d probably just stick to SSH.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This is part 3 of a 3-part series exploring the Raspberry-Pi Zero.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Part 1:&lt;/strong&gt; &lt;a href="https://www.mikekasberg.com/blog/2020/06/19/headless-setup-for-a-raspberry-pi-zero-w.html"&gt;Headless Setup for a Raspberry Pi Zero-W&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Part 2:&lt;/strong&gt; Can You VNC to a Desktop on a Headless Raspberry Pi?&lt;/li&gt;
&lt;/ul&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Tue, 23 Jun 2020 05:45:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/06/22/vnc-for-headless-raspberry-pi.html</guid></item><item><title>Starting System-as-Root Android in a LXC container</title><link>https://wantguns.dev/blog/starting-android-in-gentoo/</link><description>&lt;p&gt;As I progress in my GSoC journey, my next task is to boot System-As-Root based Android in an LXC container inside Gentoo. As the name suggests, SAR devices use /system as their rootdir instead of /boot. SharkBait was based on the older booting mechanism.
If you would want to know more about Android's Booting mechanism, I would recommend to have a look at this &lt;a href="https://wantguns.dev/blog/android-boot-high-jinks/"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Basically if you own a device that &lt;strong&gt;&lt;em&gt;shipped&lt;/em&gt;&lt;/strong&gt; with Android 9 (even the ones which are updated to Android 10) you would want to follow this guide.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;This setup expects some prerequisites which are as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Have Gentoo installed as a chroot in your Android device. &lt;a href="https://wantguns.dev/blog/install-gentoo/"&gt;guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;You should have a LXC enabled Kernel. &lt;a href="https://wiki.gentoo.org/wiki/LXC#Kernel_with_the_appropriate_LXC_options_enabled" rel="external"&gt;guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;You should have encryption disabled on your phone. &lt;a href="https://github.com/Zackptg5/Disable_Dm-Verity_ForceEncrypt" rel="external"&gt;guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;You should have SELinux disabled.&lt;/li&gt;
&lt;li&gt;You should have the &lt;strong&gt;schedtune&lt;/strong&gt; cgroup disabled.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The 4th and 5th prerequisites are addressed in the next section.&lt;/p&gt;
&lt;h2 id="preparing-the-boot-image"&gt;Preparing the boot image&lt;/h2&gt;
&lt;p&gt;Clone the SAR-Preinit repository&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;git&lt;/span&gt;&lt;span class="z-string"&gt; clone&lt;/span&gt;&lt;span class="z-string"&gt; https://gitlab.com/WantGuns/sar-preinit.git&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;-depth&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pull out your device's &lt;code&gt;boot.img&lt;/code&gt; in the artifacts directory.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;cd&lt;/span&gt;&lt;span class="z-string"&gt; sar-preinit&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;adb&lt;/span&gt;&lt;span class="z-string"&gt; root&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;adb&lt;/span&gt;&lt;span class="z-string"&gt; shell&lt;/span&gt;&lt;span class="z-string"&gt; dd&lt;/span&gt;&lt;span class="z-string"&gt; if=/dev/block/bootdevice/by-name/boot&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; |&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt; dd&lt;/span&gt;&lt;span class="z-string"&gt; of=artifacts/boot.img&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now unpack the boot.img using the Makefile provided and edit the &lt;strong&gt;bootimg.cfg&lt;/strong&gt; file produced in &lt;code&gt;out/unpack&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;make&lt;/span&gt;&lt;span class="z-string"&gt; unpack&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;nvim&lt;/span&gt;&lt;span class="z-string"&gt; out/unpack/bootimg.cfg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add this string to the &lt;code&gt;cmdline&lt;/code&gt; key, if not already present.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;androidboot.selinux=permissive cgroup_disable=schedtune&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This addresses the 4th and 5th prerequisites. If the kernel you are currently using is not LXC-enabled, you could swap the &lt;strong&gt;zImage&lt;/strong&gt; inside the unpack directory with the LXC-enabled kernel image.&lt;/p&gt;
&lt;p&gt;Now we can finally repack and patch the boot image for the use of SharkBait.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;make&lt;/span&gt;&lt;span class="z-string"&gt; repack&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;boot-mod.img&lt;/code&gt; under the out directory is the patched boot which we need. Just don't flash it yet.&lt;/p&gt;
&lt;h2 id="preparing-the-bootstrap-init"&gt;Preparing the bootstrap-init&lt;/h2&gt;
&lt;p&gt;Since System-As-Root requires a special environment unlike Android's older iterations, we need a &lt;strong&gt;init&lt;/strong&gt; to bootstrap Android in the container.
Currently the &lt;strong&gt;bootstrap-init&lt;/strong&gt; requires NDK for building, this is subject to change for native compilation later.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;People who are in a hurry could checkout the pre-built binaries provided &lt;a href="https://gitlab.com/WantGuns/bootstrap-init/-/jobs/608731821/artifacts/browse/libs/" rel="external"&gt;here&lt;/a&gt; and skip the hassle of manually setting up their environment and compiling it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you're not one of them, continue following.
Clone the repository and edit the Makefile's provided NDK path with your own NDK path.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;git&lt;/span&gt;&lt;span class="z-string"&gt; clone&lt;/span&gt;&lt;span class="z-string"&gt; https://gitlab.com/WantGuns/bootstrap-init.git&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;-depth&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;cd&lt;/span&gt;&lt;span class="z-string"&gt; bootstrap-init&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;nvim&lt;/span&gt;&lt;span class="z-string"&gt; Makefile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then call &lt;code&gt;make&lt;/code&gt; in the bootstrap-init folder. This will build the required binary for different architechtures, we should focus on arm64-v8a inside the libs folder.&lt;/p&gt;
&lt;p&gt;Copy the downloaded/compiled &lt;strong&gt;bootstrap-init&lt;/strong&gt; to Gentoo's home, we will need it later.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;adb&lt;/span&gt;&lt;span class="z-string"&gt; push&lt;/span&gt;&lt;span class="z-string"&gt; libs/arm64-v8a/bootstrap-init&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu/home/init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="preparing-gentoo-for-android"&gt;Preparing Gentoo for Android&lt;/h2&gt;
&lt;p&gt;Chroot into Gentoo and start setting it up.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;adb&lt;/span&gt;&lt;span class="z-string"&gt; root&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;adb&lt;/span&gt;&lt;span class="z-string"&gt; shell&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt;# Now switched to Android's shell&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt; Generate SSH key pairs, (will come in use later)&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;ssh-keygen&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;t&lt;/span&gt;&lt;span class="z-string"&gt; ed25519&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;C&lt;/span&gt;&lt;span class="z-string"&gt; android&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;f&lt;/span&gt;&lt;span class="z-string"&gt; /data/ssh/id_ed25519&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;mount&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;t&lt;/span&gt;&lt;span class="z-string"&gt; proc&lt;/span&gt;&lt;span class="z-string"&gt; /proc&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu/proc&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;mount&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;-rbind&lt;/span&gt;&lt;span class="z-string"&gt; /dev&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu/dev&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;mount&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;-rbind&lt;/span&gt;&lt;span class="z-string"&gt; /sys&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu/sys&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;chroot&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu&lt;/span&gt;&lt;span class="z-string"&gt; /bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt;# Now switched to Gentoo's root&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;source&lt;/span&gt;&lt;span class="z-string"&gt; /etc/profile&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;mkdir&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;p&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/{system,vendor,data,system,cache}&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;mkdir&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;p&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/lxc/android/{rootfs,run,artifacts}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;All the commands henceforth are executed in the Gentoo chroot unless specified otherwise.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="fstab"&gt;Fstab&lt;/h3&gt;
&lt;p&gt;Edit Gentoo's fstab with mount entries for Android's partitions.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt;###/etc/fstab#####&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt; Android mounts&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;/dev/mmcblk0p63&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/system&lt;/span&gt;&lt;span class="z-string"&gt; ext4&lt;/span&gt;&lt;span class="z-string"&gt; ro,barrier=1,inode_readahead_blks=&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;8&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;/dev/mmcblk0p55&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/persist&lt;/span&gt;&lt;span class="z-string"&gt; ext4&lt;/span&gt;&lt;span class="z-string"&gt; noatime,nosuid,nodev,barrier=1,data=ordered,nomblk_io_submit&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;/dev/mmcblk0p64&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/vendor&lt;/span&gt;&lt;span class="z-string"&gt; ext4&lt;/span&gt;&lt;span class="z-string"&gt; ro,barrier=1,inode_readahead_blks=&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;8&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;/dev/mmcblk0p62&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/cache&lt;/span&gt;&lt;span class="z-string"&gt; ext4&lt;/span&gt;&lt;span class="z-string"&gt; noatime,nosuid,nodev,barrier=1,data=ordered,nomblk_io_submit,noauto_da_alloc&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;/dev/mmcblk0p66&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/data&lt;/span&gt;&lt;span class="z-string"&gt; ext4&lt;/span&gt;&lt;span class="z-string"&gt; noatime,nosuid,nodev,barrier=1,data=ordered,nomblk_io_submit,noauto_da_alloc,inode_readahead_blks=&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt;8&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt; Bind into container&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;/run&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/lxc/android/rootfs/run&lt;/span&gt;&lt;span class="z-string"&gt; none&lt;/span&gt;&lt;span class="z-string"&gt; bind&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="install-lxc"&gt;Install LXC&lt;/h3&gt;
&lt;p&gt;At the time of writing this blog, LXC's version 4 does not work for the setup. I would recommend to install the version 3.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;emerge&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;av&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;-autounmask=y&lt;/span&gt;&lt;span class="z-string"&gt; =app-emulation/lxc-3.0.3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After this is done, setup the helper scripts for the container.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;cd&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/lxc/android&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt;# lxc's config&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;cat&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;gt;&lt;/span&gt;&lt;span class="z-string"&gt; config&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.uts.name = android&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.rootfs.path = /var/lib/lxc/android/rootfs/&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.init.cmd = /init&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.net.0.type = none&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.autodev = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.log.level = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.log.file = /var/log/lxc/hellalxc.log&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.hook.pre-start = /var/lib/lxc/android/pre-start.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.hook.post-stop = /var/lib/lxc/android/post-stop.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.cgroup.cpu.rt_runtime_us = 950000&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;lxc.console.path = none&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt;# pre-start.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;cat&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;gt;&lt;/span&gt;&lt;span class="z-string"&gt; pre-start.sh&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;#!/bin/sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;cp /var/lib/lxc/android/artifacts/init /var/lib/lxc/android/rootfs/init&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;mkdir -p /var/lib/lxc/android/rootfs/dev&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;mkdir -p /run&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;if [ -f /run/.android-shutdown ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        # we're shutting down; don't respawn&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        echo &amp;quot;Shutting down, won't restart.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;# handle cgroup&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;mkdir /sys/fs/cgroup/cpu/lxc&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;echo 950000 &amp;gt; /sys/fs/cgroup/cpu/lxc/cpu.rt_runtime_us&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt;# post-stop.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;cat&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;gt;&lt;/span&gt;&lt;span class="z-string"&gt; post-stop.sh&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;# do not reboot / restart when debugging&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;if [ -f /run/.android-debug ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        echo &amp;quot;Debug mode, won't power off.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        exit 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;# clean rootfs for SAR-enabled devices.&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;rm -rf /var/lib/lxc/android/rootfs/*&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;# leave mark to prevent container restart&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;touch /run/.android-shutdown&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;if [ -f /run/.android-reboot ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        echo &amp;quot;Rebooting...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        reboot&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        echo &amp;quot;Powering off...&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;        poweroff&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;EOF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Copy the &lt;strong&gt;bootstrap-init&lt;/strong&gt; binary to the &lt;strong&gt;artifacts&lt;/strong&gt; folder.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;cp&lt;/span&gt;&lt;span class="z-string"&gt; /home/init&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/lxc/android/artifacts/init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If it helps, this is the &lt;code&gt;/var/lib/lxc/android&lt;/code&gt; tree :&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;localhost&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/lxc/android&lt;/span&gt;&lt;span&gt; $&lt;/span&gt;&lt;span class="z-string"&gt; tree&lt;/span&gt;&lt;span class="z-string"&gt; .&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;├──&lt;/span&gt;&lt;span class="z-string"&gt; artifacts&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;│  &lt;/span&gt;&lt;span class="z-string"&gt; └──&lt;/span&gt;&lt;span class="z-string"&gt; init&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;├──&lt;/span&gt;&lt;span class="z-string"&gt; config&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;├──&lt;/span&gt;&lt;span class="z-string"&gt; post-stop.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;├──&lt;/span&gt;&lt;span class="z-string"&gt; pre-start.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;├──&lt;/span&gt;&lt;span class="z-string"&gt; rootfs&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;└──&lt;/span&gt;&lt;span class="z-string"&gt; run&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check if the container is getting detected by Android using &lt;code&gt;lxc-info android&lt;/code&gt;. If it is getting detected, we should be ready to go.&lt;/p&gt;
&lt;p&gt;Finally, setup the &lt;strong&gt;lxc.android&lt;/strong&gt; service so that the container auto-starts on boot.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;cd&lt;/span&gt;&lt;span class="z-string"&gt; /etc/init.d&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;ln&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;s&lt;/span&gt;&lt;span class="z-string"&gt; lxc&lt;/span&gt;&lt;span class="z-string"&gt; lxc.android&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;rc-update&lt;/span&gt;&lt;span class="z-string"&gt; add&lt;/span&gt;&lt;span class="z-string"&gt; lxc.android&lt;/span&gt;&lt;span class="z-string"&gt; boot&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As a bonus, we can also setup SSH for accessing Gentoo when Android boots. The &lt;strong&gt;dialhome&lt;/strong&gt; script mentioned below can be found &lt;a href="https://gitlab.com/sharkbaitOS/bootstrap/setup/-/blob/master/scripts/dialhome" rel="external"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;umask&lt;/span&gt;&lt;span class="z-constant z-numeric"&gt; 077&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;mkdir&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;p&lt;/span&gt;&lt;span class="z-string"&gt; ~/.ssh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;mount&lt;/span&gt;&lt;span class="z-string"&gt; /dev/block/by-name/userdata&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/data/&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;cat&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/data/ssh/id_ed25519.pub&lt;/span&gt;&lt;span class="z-keyword z-operator"&gt; &amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="z-string"&gt; ~/.ssh/authorized_keys&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;cp&lt;/span&gt;&lt;span class="z-string"&gt; dialhome&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/data/ssh/&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;chmod&lt;/span&gt;&lt;span class="z-string"&gt; u+x&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/data/ssh/dialhome&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;chown&lt;/span&gt;&lt;span class="z-string"&gt; 2000:2000&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/data/ssh/dialhome&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;umount&lt;/span&gt;&lt;span class="z-string"&gt; /var/lib/android/data&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;rc-update&lt;/span&gt;&lt;span class="z-string"&gt; add&lt;/span&gt;&lt;span class="z-string"&gt; sshd&lt;/span&gt;&lt;span class="z-string"&gt; default&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We are done with Gentoo now, exit it and unmount its pseudofs&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;exit&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt;# Now back in Android's Shell&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;umount&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;f&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu/proc&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;umount&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;l&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu/sys&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;umount&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt; -&lt;/span&gt;&lt;span class="z-constant z-other z-option"&gt;l&lt;/span&gt;&lt;span class="z-string"&gt; /data/gnu/dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="final-steps"&gt;Final Steps&lt;/h2&gt;
&lt;p&gt;We are almost done now.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reboot to your Recovery and flash the &lt;code&gt;boot-mod.img&lt;/code&gt; to the &lt;code&gt;boot&lt;/code&gt; partition.
Fastboot users could also flash it via&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;fastboot&lt;/span&gt;&lt;span class="z-string"&gt; flash&lt;/span&gt;&lt;span class="z-string"&gt; boot&lt;/span&gt;&lt;span class="z-string"&gt; boot-mod.img&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;While you're in the Recovery mode, fire up adb again and patch the &lt;code&gt;init.rc&lt;/code&gt; present in &lt;code&gt;/system&lt;/code&gt; according to the patch &lt;a href="https://gitlab.com/sharkbaitOS/bootstrap/setup/-/blob/master/devices/angler/patches/init.rc.patch" rel="external"&gt;here&lt;/a&gt;. Keep in mind that we &lt;strong&gt;&lt;em&gt;do not&lt;/em&gt;&lt;/strong&gt; need to patch Android's &lt;code&gt;fstab&lt;/code&gt; if you're following this setup.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And then finally cross your fingers and reboot. If Android boots, congrats, you just joined the SharkBait party. But it gets even better.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="final-thoughts-and-scopes-of-improvement"&gt;Final Thoughts and Scopes of Improvement&lt;/h2&gt;
&lt;p&gt;If Android does not boot, check the logs at &lt;code&gt;/data/gnu/var/logs&lt;/code&gt;. Check &lt;code&gt;dmesg&lt;/code&gt; for kernel logs, &lt;code&gt;rc.log&lt;/code&gt;, &lt;code&gt;messages&lt;/code&gt; for Gentoo's logs, &lt;code&gt;lxc/hellalxc.log&lt;/code&gt; and &lt;code&gt;lxc/android.log&lt;/code&gt; for LXC logs.&lt;/p&gt;
&lt;p&gt;Currently SharkBait is at a very young stage. Encryption and SELinux are not supported right now. But this is subject to change once SharkBait matures.&lt;/p&gt;
&lt;p&gt;Also if this entire process seems a bit lengthy, I should inform that when the &lt;strong&gt;bootstrap-init&lt;/strong&gt; and &lt;strong&gt;sar-preinit&lt;/strong&gt; merges into the official SharkBait workflow, this install will take significantly lower efforts and would be a breeze to the porters as well as the users of SharkBait.&lt;/p&gt;
&lt;p&gt;Lastly I should give credits to the official &lt;a href="https://wiki.gentoo.org/wiki/Android/SharkBait/Starting_Android_in_LXC" rel="external"&gt;guide&lt;/a&gt; on which this install guide is based on. Please have a look at it as well as my other blogs to understand how this works under-the-hood.&lt;/p&gt;
&lt;hr /&gt;
&lt;div class="imageClass"&gt;
    &lt;figure class="center"&gt;
        &lt;img alt="neofetch" class="center" src="https://wantguns.dev/blog/starting-android-in-gentoo/neofetch.jpg" /&gt;
        
            &lt;figcaption class="center"&gt;
                Obligatory Neofetch
            &lt;/figcaption&gt;
        
    &lt;/figure&gt;
&lt;/div&gt;</description><author>Gunwant Jain - @wantguns</author><pubDate>Tue, 23 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://wantguns.dev/blog/starting-android-in-gentoo/</guid></item><item><title>About</title><link>https://adropincalm.com/about/</link><description>&lt;div&gt;	
	&lt;p class="lead mb-5"&gt;
		I'm a passionate problem solver that use code, design and empathy to help people through their digital challenges.
	&lt;/p&gt;
	&lt;p&gt;
	Hi, my name is Marco and this is where I collect my thoughts, intuitions and ideas on the IT industry (and more).  
	&lt;/p&gt;
	&lt;p&gt;
		Occasionally, I do contribute to &lt;a href="https://github.com/borracciaBlu"&gt;open-source projects&lt;/a&gt; and &lt;a href="https://speakerdeck.com/borracciablu"&gt;share some ideas with my fellows&lt;/a&gt;. &lt;br /&gt;
		If you are more into philosophy you should give a try to the &lt;a href="https://adropincalm.com/manifesto"&gt;manifesto&lt;/a&gt;. 
	&lt;/p&gt;
	&lt;p&gt;
		Online you can find me on &lt;a href="https://twitter.com/borracciaBlu_u" rel="me"&gt;twitter&lt;/a&gt;, &lt;a href="https://github.com/borracciaBlu" rel="me"&gt;github&lt;/a&gt; and &lt;a href="https://stackoverflow.com/users/4472048/borracciablu" rel="me"&gt;stackoverflow&lt;/a&gt;. 
	&lt;/p&gt;
	&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
&lt;/div&gt;</description><author>A Drop In Calm</author><pubDate>Tue, 23 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://adropincalm.com/about/</guid></item><item><title>Resources</title><link>https://adropincalm.com/resources/</link><description>&lt;p class="lead mb-5 pb-4"&gt;
Here a collection of articles and videos I found interesting on the internet!
&lt;/p&gt;
&lt;h2 id="articles"&gt;Articles&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://benmccormick.org/2023/01/13/pillars-for-effective.html"&gt;3 Pillars For Effective Work - Herding Lions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="videos"&gt;Videos&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=uElc4ZUE6qo"&gt;Ariya Hidayat: Next-Generation JavaScript Language Tooling&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=nzbV0YgSBuo"&gt;Ryan Carniato - Facing Frontend&amp;rsquo;s Existential Crisis, React Summit 2024&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://youtu.be/3YDiloj8_d0?si=L60o2vjWMNPJ-V0O"&gt;Jest Architecture&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.infoq.com/presentations/Events-Are-Not-Just-for-Notifications/"&gt;Events Are Not Just for Notifications&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=1fZTOjd_bOQ"&gt;Are we stuck with the same Desktop UX forever? | Ubuntu Summit 25.10&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description><author>A Drop In Calm</author><pubDate>Tue, 23 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://adropincalm.com/resources/</guid></item><item><title>Power Query - The M Language</title><link>https://daniellittle.dev/power-query-the-m-language</link><description>Recently I had the opportunity to write a Custom Connector for Power BI and come across something I didn't expect. To build a Connector you…</description><author>Daniel Little Dev</author><pubDate>Mon, 22 Jun 2020 13:40:00 GMT</pubDate><guid isPermaLink="true">https://daniellittle.dev/power-query-the-m-language</guid></item><item><title>On Australia and others defunding humanities</title><link>https://stop.zona-m.net/2020/06/on-australia-and-others-defunding-humanities/</link><description>&lt;p&gt;What happens when citizens cannot think and speak clearly?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 22 Jun 2020 12:15:26 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/on-australia-and-others-defunding-humanities/</guid></item><item><title>Top 6 Tips for Planning a Successful Azure Migration</title><link>https://blog.adnansiddiqi.me/top-6-tips-for-planning-a-successful-azure-migration/</link><description>&lt;p&gt;Migrating your workloads to Azure can help you leverage the benefits of cloud computing. This includes agility, scalability, lower costs, and easier management. However, the process of migration can sometimes be complicated. You have to select the proper service model for every workload and establish a migration strategy for all workloads. A well-planned migration strategy can help you make the move without impacting your business. The following tips will ensure that your Azure migration goes smoothly. Reasons for Migrating to the Cloud Cloud migration can be risky and expensive, but also rewarding. Here are some of the common drivers for moving workloads and applications to the cloud:  Reducing operating costs—the cloud eliminates the need for in-house IT management and hardware support. Faster time to market—cloud platforms can help you get new features to market faster, by simplifying and automating development and deployment cycles. Scalability and utilization—on-premise systems are designed for peak loads. Most of the time they utilize less than 20% of their capacity. Cloud computing enables you to consume the resources you need in each time period. Reducing upfront costs—cloud providers usually charge you only for the resources you use. There is no need for upfront license costs and investment in hardware. Application modernization—the cloud can help you become more agile and efficient during development, and provide more value to users. Why Do Organizations Choose Azure? Cloud computing vendors like Azure, AWS, and Google Cloud have their strengths and weaknesses. Organizations that prefer Azure, usually do it because of the following reasons. Platform as a Service (PaaS) and Infrastructure as a Service (IaaS) capabilities Azure combines both PaaS and IaaS services. PaaS enables you to create web apps and solutions without having to buy and maintain the underlying infrastructure. IaaS enables you to outsource your Azure infrastructure and pay only for what you use. Organizations leverage Azure IaaS and PaaS solutions to build enterprise-grade apps on the Cloud for accelerated business growth. Security offerings Azure is designed on the Security Development Lifecycle (SDL) industry security process. SDL provides core security for private data and services hosted on Azure Cloud. In addition, Azure provides over 50 compliance offerings, and supports the new international standard for cloud privacy ISO 27018. For these reasons, the U.S. government institutions and many more leading organizations choose Azure as their cloud platform. Integration with other Microsoft tools Organizations that use tools like Outlook, SharePoint, and Office 365 should invest in a cloud platform that integrates with other Microsoft offerings. Azure simplifies operations by using the same virtual on-premise machines like Linux and Windows for all tools. Hybrid capabilities Azure provides a reliable consistent communication, and easy mobility between on-premise and public cloud. Azure also offers multiple hybrid connections including Content Delivery Networks (CDNs), Virtual Private Networks (VPNs), caches, and ExpressRoute connections to improve performance and usability. Azure Migration Tips and Best Practices A successful cloud migration requires hard work and thorough planning. The following tips can help you simplify your migration process.  &amp;#160; 1. A phased migration approach A step-by-step migration approach can ensure a successful transition to the cloud and reduce the risk of failures. However, cloud migration requires a well-planned strategy. First, you need to identify every workload you want to migrate to the cloud and decide which service model is the best fit.  Then, you need to test every system to ensure the performance meets your original objectives and then establish a migration plan. Make sure to define and implement the relevant practices and processes you want to follow after migration. Lastly, include the configuring a monitoring solution you want to use in your migration plan. 2. Azure migration tools There are many Azure migration tools that can simplify, and in many cases fully automate, the migration of workloads to the cloud: Azure Migrate tool—enables you to determine whether your on-premises workload is suitable for Azure. You can determine the size of your cloud resources, and estimate your future cloud expenses.  Assessment and Planning Toolkit—enables you to assess whether your on-premises workloads are suitable for Azure. You can build an inventory of resources by discovering your applications and servers. Then, you can generate a report that indicates whether Azure can support your servers. Database Migration Service—supports the migration of SQL Server to Azure. You can also migrate additional database sources into Azure SQL Server.  3. Compliance and security Your Azure environment must be compliant and provide the necessary security to protect all your data, workloads, and users. For instance, if your organization’s security policy requires the encryption of data, then your migration plan must follow this guideline. Always, make sure to implement organizational procedures and policies during and after the migration. 4. Test every workload before migration You have to formulate and test every process during the migration phase of your project. There are several solutions that can help you automate and document this task. Azure Migrate is one set of tools that can help you automate the migration of on-premises Virtual Machines (VMs) to Azure. Azure Migrate also enables you to assess the current state of your on-premises VMs. This tool maps their dependencies and provides recommendations on the appropriate Azure services you need to configure. No matter which set of tools you use, you have to test and retest every workload before migration. 5. Manage your costs The migration of workloads to Azure sometimes requires you to change your own business model. Therefore, you have to set up a cost management tool for usage tracking. Proper cost management of Azure infrastructure helps to reduce costs.  For example, if you spin up a VM that costs $30,000 a month using Windows Server and SQL Server, the cost can go up to $60,000 a month for one VM. Therefore, a good subscription structure, a good tagging policy, and a good role-based access control can help you to manage costs better. 6. Include your users Users are the most important part of any organization. Make sure to inform your users when you migrate servers or the entire on-premise infrastructure to the cloud. Keeping users in the dark can cause problems like a sudden absence of local cache in cloud-based Customer Relationship Management (CRM) systems.  Conclusion Azure Cloud supports a wide range of private, public, and hybrid cloud infrastructure. Azure also offers many IaaS and PaaS solutions, security features, and integration with other Microsoft tools. The process of migrating your application to Azure can be complicated. Make sure to use a phased migration approach, monitor your costs, test every workload before migration, and involve your users in the process. About the Author Eddie Segal an electronics engineer with a Master’s Degree from Be’er Sheva University, a big data and web analytics specialist, and also a technology writer. In my writing, I cover subjects ranging from cloud computing to agile development to cybersecurity and deep learning.&lt;/p&gt;
The post &lt;a href="https://blog.adnansiddiqi.me/top-6-tips-for-planning-a-successful-azure-migration/"&gt;Top 6 Tips for Planning a Successful Azure Migration&lt;/a&gt; first appeared on &lt;a href="https://blog.adnansiddiqi.me"&gt;Adnan's Random bytes&lt;/a&gt;.</description><author>Adnan's Random bytes</author><pubDate>Mon, 22 Jun 2020 11:57:14 GMT</pubDate><guid isPermaLink="true">https://blog.adnansiddiqi.me/top-6-tips-for-planning-a-successful-azure-migration/</guid></item><item><title>arnorhs.dev launches</title><link>https://arnorhs.dev/posts/2020-06-22/arnorhs-dev-launches/</link><description>Open for orders</description><author>arnorhs blog - arnorhs.dev</author><pubDate>Mon, 22 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://arnorhs.dev/posts/2020-06-22/arnorhs-dev-launches/</guid></item><item><title>Not Everything That Is Faced Can Be Changed by James Baldwin</title><link>https://ho.dges.online/words/commonplace/not-everything-that-is-faced-can-be-changed-by-james-baldwin/</link><description>&lt;p&gt;![[2022-03-16.jpg]]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Not everything that is faced can be changed. But nothing can be changed until it is faced&amp;hellip; Most of us are about as eager to change as we were to be born, and go through our changes in a similar state of shock&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;</description><author>ho.dges.online</author><pubDate>Mon, 22 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/words/commonplace/not-everything-that-is-faced-can-be-changed-by-james-baldwin/</guid></item><item><title>A survey of OneCardToRuleThemAll companies</title><link>https://captnemo.in/one-card-to-rule-them-all/</link><description>&lt;p&gt;A lot of companies have come up with the idea for reducing all your cards into a single piece of plastic. Here’s a summary of all the ones I could find, and their fate.
Beware: this field is very much a startup graveyard. The only remaining survivor seems to be Curve&lt;sup id="fnref:1"&gt;&lt;a class="footnote" href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt; but it’s also the first one that’s attempting this outside of US.&lt;/p&gt;

&lt;p&gt;There seem to be a lot of challenges (regulatory, financial, and technical) before such a thing becomes reality. And there’s Apple/Samsung Pay as well. Here’s a summary of all the companies I could find in this space.
If I’ve missed any, please let me know, and I’ll add them here.&lt;/p&gt;

&lt;p&gt;&lt;img alt="A photo of a hand holding a blank card" src="/img/card.jpg" /&gt;&lt;/p&gt;

&lt;h2 id="curve-2015-"&gt;&lt;a href="https://www.curve.com/"&gt;Curve&lt;/a&gt; (2015-)&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Curve allows you to spend from any of your accounts using just one card, clearing the clutter from your wallet and simplifying your finances.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;Curve has raised a total of $74M at a valuation north of $250M, out of which £6M were from a crowdfunding campaign in 2019.&lt;/li&gt;
  &lt;li&gt;Their waitlist is at 800,000+ users.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.businessinsider.com/curve-fintech-startup-leaked-active-users-crowdfunding-2019-11"&gt;Curve faced flak for failing to disclose its usage numbers&lt;/a&gt; (&amp;lt;100,000 monthly active users out of total 500,000) to crowdfund investors.&lt;/li&gt;
  &lt;li&gt;Only works with Visa/MasterCard. Used to work with Amex, but Curve has a history of working and being blocked by Amex repeatedly.&lt;/li&gt;
  &lt;li&gt;See &lt;a href="https://www.curve.com/en-gb/how-it-works"&gt;this page&lt;/a&gt; for some details on how it works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="coin-yc-w13-2012-2017"&gt;Coin (YC W13) (2012-2017)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Coin raised a total of $15.6M.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://techcrunch.com/2015/04/17/coin-the-one-credit-card-to-rule-them-all-is-finally-shipping/"&gt;Shipped in 2015 April&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://investor.fitbit.com/press/press-releases/press-release-details/2016/Fitbit-Inc-Acquires-Wearable-Payments-Assets-From-Financial-Technology-Company-Coin/default.aspx"&gt;Acquired by Fitbit in May 2016&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://techcrunch.com/2017/01/31/coin-shut-down/"&gt;Shutdown by Fitbit in Feb 2017&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Related: &lt;a href="https://techcrunch.com/2019/11/01/google-is-acquiring-fitbit/"&gt;Google acquired FitBit in 2019 Nov&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="plastc-2014-2017"&gt;Plastc (2014-2017)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Single dynamic card with e-Ink touchscreen. See obligatory &lt;a href="https://www.youtube.com/watch?v=8QrI3lntq3g"&gt;launch video&lt;/a&gt; with fancy AR.&lt;/li&gt;
  &lt;li&gt;Crowdfunded $9M on pre-orders in October 2014.&lt;/li&gt;
  &lt;li&gt;Delayed launch to April 2016, and then again to September 2016.&lt;/li&gt;
  &lt;li&gt;Shut down and declared bankruptcy in April 2017.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://digg.com/2017/plastc-smart-card-bankruptcy-what-happened"&gt;Complete story via digg.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="stratos-2015-2015"&gt;Stratos (2015-2015)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Was supposed to cost $95/year.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://techcrunch.com/2015/05/26/the-stratos-all-in-one-credit-card-isnt-perfect-enough/"&gt;Announced May 2015&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Raised $6.63 million over three rounds of financing.&lt;/li&gt;
  &lt;li&gt;Ran out of money by &lt;a href="https://techcrunch.com/2015/12/21/stratos-card-to-shut-down-just-six-months-after-launching/"&gt;December 2015&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Sold to &lt;a href="https://techcrunch.com/2015/12/22/stratos-sells-to-ciright-one-to-avoid-collapse/"&gt;Ciright One&lt;/a&gt; to avoid collapse.&lt;/li&gt;
  &lt;li&gt;Seems to be dead now.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="swyp-2014-2017"&gt;Swyp (2014-2017)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Had a pre-order campaign in 2014.&lt;/li&gt;
  &lt;li&gt;Raised $5M from Khosla Ventures in 2017.&lt;/li&gt;
  &lt;li&gt;Tried to pivot in 2017, failed.&lt;/li&gt;
  &lt;li&gt;Offered customers a &lt;a href="https://web.archive.org/web/20200225225658/http://blog.swypcard.com/blog/swyp-card-july-update"&gt;debit card with an app called Hoot&lt;/a&gt; in 2017 as an alternative to refunds. I don’t think the Hoot card ever materialized.&lt;/li&gt;
  &lt;li&gt;Tilt (Swyp’s payment processor) also ceased operations in 2017, due to unrelated reasons.&lt;/li&gt;
  &lt;li&gt;Swyp &lt;a href="https://web.archive.org/web/20200224230053/http://blog.swypcard.com/blog/swyp-card-update"&gt;finally shut down in December 2017&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="final-yc-w15-2014-2017"&gt;&lt;a href="https://www.getfinal.com/"&gt;Final&lt;/a&gt; (YC W15) (2014-2017)&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Final was with a credit card with a different number for every website. As a independent card, Final doesn’t exactly fit in this list, but it’s a very relevant and loved product.&lt;/li&gt;
  &lt;li&gt;Announced itself &lt;a href="https://www.youtube.com/watch?v=8ZtG5DX5FR0"&gt;with a snazzy video&lt;/a&gt; in mid 2014&lt;/li&gt;
  &lt;li&gt;Raised $4M and launched in August 2016, but remained invite-only till the very end.&lt;/li&gt;
  &lt;li&gt;Final’s blog has some interesting content: A &lt;a href="https://www.getfinal.com/company-news/2017/08/21/rfcc/"&gt;Request for Credit Cards&lt;/a&gt; program to build card-issuance backed businesses and the &lt;a href="https://www.getfinal.com/company-news/2017/03/30/2017-payment-card-landscape/"&gt;Payment card landscape&lt;/a&gt; for 2017.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://www.getfinal.com/company-news/2017/12/06/a-final-farewell/"&gt;Shut down in december 2017&lt;/a&gt; and acquired &lt;a href="https://www.fastcompany.com/40523758/goldman-sachs-buys-credit-card-startup-final"&gt;by Goldman Sachs&lt;/a&gt; in an acqui-hire.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="indian-landscape"&gt;Indian Landscape&lt;/h1&gt;

&lt;p&gt;India hasn’t seen a true single-card app yet, but there have been lots of related attempts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="https://getinfino.com/"&gt;Infino promises a single-card&lt;/a&gt;, but it hasn’t launched yet. It had a &lt;a href="https://trello.com/b/2h9S100Z/the-infino-roadmap"&gt;public roadmap&lt;/a&gt;, but never launched and ultimately pivoted to a Coupon Aggregator called Meet Donut, which shut down.&lt;/li&gt;
  &lt;li&gt;IndusInd bank has &lt;a href="https://www.businesstoday.in/sectors/banks/indusind-launches-credit-cum-debit-card-confuse-customers/story/284912.html"&gt;tried a dual-chip debit+credit&lt;/a&gt; card. Union Bank has &lt;a href="https://www.unionbankofindia.co.in/english/debit-cum-credit-card.aspx"&gt;a similar card&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;IndusInd has also &lt;a href="https://www.businesstoday.in/top-story/new-credit-card-with-buttons-gives-users-emi-options-helps-redeem-reward-points/story/290763.html"&gt;tried an interactive credit card&lt;/a&gt; with 3 buttons.&lt;/li&gt;
  &lt;li&gt;&lt;a href="https://fampay.in/"&gt;FamPay&lt;/a&gt;, &lt;a href="https://fold.money/"&gt;Fold&lt;/a&gt;, &lt;a href="https://www.goniyo.com/"&gt;Niyo&lt;/a&gt;, &lt;a href="https://www.getonecard.app/"&gt;OneCard&lt;/a&gt;, &lt;a href="https://meetdonut.com/"&gt;Donut&lt;/a&gt;🪦, &lt;a href="https://vcard.ai/"&gt;vCard&lt;/a&gt;🪦, &lt;a href="https://sliceit.com/"&gt;Slice&lt;/a&gt; &lt;sup id="fnref:2"&gt;&lt;a class="footnote" href="#fn:2" rel="footnote"&gt;2&lt;/a&gt;&lt;/sup&gt; and lots of other startups are doing co-branded issuance, but that’s not the same thing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the emergence of UPI, and low penetration rate of credit cards, I don’t see a market in India - but I’d love to be proven wrong.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Did I miss anything? &lt;a href="/contact/"&gt;Reach out&lt;/a&gt; and let me know.&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://twitter.com/thatharmansingh"&gt;Harman&lt;/a&gt; for reviewing drafts of this, and PRL for getting me interested enough to document this.&lt;/p&gt;

&lt;div class="footnotes"&gt;
  &lt;ol&gt;
    &lt;li id="fn:1"&gt;
      &lt;p&gt;Curve used to live on &lt;code class="language-plaintext highlighter-rouge"&gt;imaginecurve.com&lt;/code&gt;, then switched to &lt;code class="language-plaintext highlighter-rouge"&gt;curve.app&lt;/code&gt; and now to &lt;code class="language-plaintext highlighter-rouge"&gt;curve.com&lt;/code&gt;, which must have cost them millions. &lt;a class="reversefootnote" href="#fnref:1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id="fn:2"&gt;
      &lt;p&gt;Unlike others on the list, vCard is entirely a virtual card, and supports UPI transfers from your credit limit. &lt;a class="reversefootnote" href="#fnref:2"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;</description><author>Nemo's Home</author><pubDate>Mon, 22 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://captnemo.in/one-card-to-rule-them-all/</guid></item><item><title>Separating Spam from Ham with the shell</title><link>https://jiby.tech/post/image-list-separate-spam-ham-with-shell/</link><description>&lt;p&gt;Here&amp;rsquo;s how attempting to export images off a Word Document
led to a quest for data deduplication and classification using the
shell.&lt;/p&gt;
&lt;p&gt;The images I wanted to export were MS Word diagrams drawn in Word,
rather than PNG files&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;.
Because those doodle-shapes do not export to PNG well, I first
copy-pasted them into Powerpoint to get the familiar &amp;ldquo;save as picture&amp;rdquo;
context menu. But a couple of images were still deformed beyond
recognition.&lt;/p&gt;</description><author>Jiby's toolbox</author><pubDate>Mon, 22 Jun 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://jiby.tech/post/image-list-separate-spam-ham-with-shell/</guid></item><item><title>A DIY USB Mouse Jiggler</title><link>https://www.anmolsarma.in/post/mouse-jiggler/</link><description>&lt;p&gt;The Great Pandemic Lockdown of 2020 forced companies to adopt remote work. With no existing provisions for WFH, bizarre ad-hoc setups emerged. A case in point, my roommate was issued two laptops: One for development and a second locked down machine to connect to production servers. The second laptop was configured with a very aggressive lock screen timeout with no way to change or disable it. This made keeping an eye on prod rather annoying.&lt;/p&gt;
&lt;p&gt;One way to prevent Windows from locking the screen is by simulating user activity: say moving the mouse. This would have been trivial to accomplish in software if it wasn&amp;rsquo;t for the administrative policy restricting which applications could be run.&lt;/p&gt;
&lt;p&gt;This seems to be a common enough occurrence in corporate environments that there are companies that &lt;a href="https://www.cru-inc.com/products/wiebetech/mouse_jiggler_mj-3/"&gt;sell&lt;/a&gt; purpose-built &lt;a href="http://www.keelog.com/mouse-jiggler/"&gt;hardware&lt;/a&gt; to mitigate the situation. Basically, these devices pretend to be a USB mouse or keyboard and periodically send random mouse events or keystrokes to the connected host computer. Getting hold of one of these seems unlikely in the current situation. Building one was the only option. Fortunately, I had a &lt;a href="https://www.ti.com/tool/EK-LM4F120XL"&gt;Stellaris Launchpad&lt;/a&gt; lying around, (literally) gathering dust that was perfect for this.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Stellaris LM4F120 LaunchPad Evaluation Kit" src="https://www.anmolsarma.in/images/launchpad.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;The board has a USB capable ARM Cortex microcontroller onboard and can be used with a &lt;a href="https://www.ti.com/licreg/docs/swlicexportcontrol.tsp?form_type=2&amp;amp;prod_no=SW-TM4C-USBL-2.2.0.295.exe"&gt;USB stack that TI provides&lt;/a&gt; royalty-free. All I had to do was to figure out how to configure the USB stack to emulate a USB HID mouse. The &lt;a href="https://www.ti.com/lit/pdf/spmu297"&gt;documentation&lt;/a&gt; refers to a &lt;code&gt;usb_dev_mouse&lt;/code&gt; example application but I for one was unable to find it in the TivaWare package. The TivaWare USB Library is fairly straightforward to use. Apart from the minimal boiler-plate, it is almost as simple as &lt;a href="https://www.arduino.cc/reference/en/language/functions/usb/mouse/"&gt;Arduino&amp;rsquo;s Mouse library&lt;/a&gt;. Coupled with the &lt;a href="https://www.ti.com/licreg/docs/swlicexportcontrol.tsp?form_type=2&amp;amp;prod_no=SW-TM4C-DRL-2.2.0.295.exe"&gt;Driverlib&lt;/a&gt; HAL to configure the timer, I was able to get a mouse jiggler working in short order. The USB string descriptors took up more lines of code than the actual application:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="language-C"&gt;&lt;span style="color: #0b0; font-weight: bold;"&gt;void&lt;/span&gt;
&lt;span style="color: #00a000;"&gt;timerISR&lt;/span&gt; (&lt;span style="color: #0b0; font-weight: bold;"&gt;void&lt;/span&gt;)
{
  &lt;span style="color: #080; font-style: italic;"&gt;// Clear the timer interrupt source to avoid being triggered again 
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  &lt;span style="color: #080; font-style: italic;"&gt;// immediately on exit
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  TimerIntClear (TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  &lt;span style="color: #080; font-style: italic;"&gt;// Disable interrupts so we can get some work done
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  IntMasterDisable ();

  &lt;span style="color: #080; font-style: italic;"&gt;// Move the cursor by a pixel along each axis in a random direction
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  int8_t x &lt;span style="color: #666;"&gt;=&lt;/span&gt; (rand () &lt;span style="color: #666;"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color: #666;"&gt;1&lt;/span&gt;) &lt;span style="color: #666;"&gt;?&lt;/span&gt; &lt;span style="color: #666;"&gt;1&lt;/span&gt; &lt;span style="color: #666;"&gt;:&lt;/span&gt; &lt;span style="color: #666;"&gt;-&lt;/span&gt;&lt;span style="color: #666;"&gt;1&lt;/span&gt;;
  int8_t y &lt;span style="color: #666;"&gt;=&lt;/span&gt; (rand () &lt;span style="color: #666;"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color: #666;"&gt;1&lt;/span&gt;) &lt;span style="color: #666;"&gt;?&lt;/span&gt; &lt;span style="color: #666;"&gt;1&lt;/span&gt; &lt;span style="color: #666;"&gt;:&lt;/span&gt; &lt;span style="color: #666;"&gt;-&lt;/span&gt;&lt;span style="color: #666;"&gt;1&lt;/span&gt;;
  USBDHIDMouseStateChange ((&lt;span style="color: #0b0; font-weight: bold;"&gt;void&lt;/span&gt; &lt;span style="color: #666;"&gt;*&lt;/span&gt;) &lt;span style="color: #666;"&gt;&amp;amp;&lt;/span&gt;g_jiggler, x, y, &lt;span style="color: #666;"&gt;0&lt;/span&gt;);

  IntMasterEnable ();

}

&lt;span style="color: #0b0; font-weight: bold;"&gt;int&lt;/span&gt;
&lt;span style="color: #00a000;"&gt;main&lt;/span&gt; (&lt;span style="color: #0b0; font-weight: bold;"&gt;void&lt;/span&gt;)
{

  &lt;span style="color: #080; font-style: italic;"&gt;// Configure the clock to directly run from the crysal oscillator
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  SysCtlClockSet (SYSCTL_SYSDIV_1 &lt;span style="color: #666;"&gt;|&lt;/span&gt; SYSCTL_USE_OSC &lt;span style="color: #666;"&gt;|&lt;/span&gt; SYSCTL_OSC_MAIN &lt;span style="color: #666;"&gt;|&lt;/span&gt;
                  SYSCTL_XTAL_16MHZ);

  SysCtlPeripheralEnable (SYSCTL_PERIPH_TIMER0);

  &lt;span style="color: #080; font-style: italic;"&gt;// Enable the USB peripheral 
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOD);
  GPIOPinTypeUSBAnalog (GPIO_PORTD_BASE, GPIO_PIN_4 &lt;span style="color: #666;"&gt;|&lt;/span&gt; GPIO_PIN_5);

  &lt;span style="color: #080; font-style: italic;"&gt;// Configure the Timer to fire every 30 seconds
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  TimerConfigure (TIMER0_BASE, TIMER_CFG_PERIODIC);
  TimerLoadSet (TIMER0_BASE, TIMER_A, SysCtlClockGet () &lt;span style="color: #666;"&gt;*&lt;/span&gt; &lt;span style="color: #666;"&gt;30&lt;/span&gt;);

  IntEnable (INT_TIMER0A);
  TimerIntEnable (TIMER0_BASE, TIMER_TIMA_TIMEOUT);
  TimerEnable (TIMER0_BASE, TIMER_A);

  USBStackModeSet (&lt;span style="color: #666;"&gt;0&lt;/span&gt;, USB_MODE_DEVICE, &lt;span style="color: #666;"&gt;0&lt;/span&gt;);
  &lt;span style="color: #080; font-style: italic;"&gt;// Initialize the USB controller and attach the mouse jiggler
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  &lt;span style="color: #080; font-style: italic;"&gt;// device to the USB bus
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  USBDHIDMouseInit (&lt;span style="color: #666;"&gt;0&lt;/span&gt;, (tUSBDHIDMouseDevice &lt;span style="color: #666;"&gt;*&lt;/span&gt;) &lt;span style="color: #666;"&gt;&amp;amp;&lt;/span&gt;g_jiggler );

  &lt;span style="color: #080; font-style: italic;"&gt;// Enable processor interrupts
&lt;/span&gt;&lt;span style="color: #080; font-style: italic;"&gt;&lt;/span&gt;  IntMasterEnable ();

  &lt;span style="color: #a2f; font-weight: bold;"&gt;while&lt;/span&gt; (&lt;span style="color: #666;"&gt;1&lt;/span&gt;);

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So, with the jiggler attached and the laptop hooked up to a TV screen, my roommate can monitor prod and continue to lose sleep in peace.&lt;/p&gt;</description><author>Anmol Sarma</author><pubDate>Sun, 21 Jun 2020 18:54:50 GMT</pubDate><guid isPermaLink="true">https://www.anmolsarma.in/post/mouse-jiggler/</guid></item><item><title>This blog is now Google free</title><link>https://muffinman.io/blog/this-blog-is-now-google-free/</link><description>&lt;article class="article"&gt;&lt;p&gt;Earlier today I removed Google Analytics script from my website. Long time ago I switched to self hosted fonts instead of Google Fonts. That means, as of today, my blog is completely Google free.&lt;/p&gt;
&lt;p&gt;Google Analytics is a great product, but I probably used up to five percent of it&amp;#x27;s features. Still I had a fear of missing out. That&amp;#x27;s why I delayed pulling the plug for so many months.&lt;/p&gt;
&lt;p&gt;I&amp;#x27;ve tried a lot of other solutions, but they all felt either too complex or too simplistic. In the end, I did find the replacement.&lt;/p&gt;
&lt;h2 id="goatcounter"&gt;GoatCounter &lt;a class="anchor-link" href="#goatcounter"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It has a funky name, &lt;a href="https://www.goatcounter.com/"&gt;GoatCounter&lt;/a&gt;. It is open source and privacy respecting. There isn&amp;#x27;t nearly as much data, but it is all the data I need. You should check it out. It has a generous free tier for non-commercial websites - but please consider donating or contributing as it is a work of a single developer. And he is doing a great job, every time I open the dashboard, there is something new or polished.&lt;/p&gt;
&lt;figure class="image__figure wide image__figure--wide"&gt;&lt;img alt="GoatCounter dashboard for my website" height="1426" src="./goatcounter.png" width="2178" /&gt;&lt;/figure&gt;
&lt;h2 id="why"&gt;Why? &lt;a class="anchor-link" href="#why"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is simple: &amp;quot;If you don&amp;#x27;t pay for it, you are the product&amp;quot;.&lt;/p&gt;
&lt;p&gt;All these Google services are free because they are collecting data on every visitor. It is one thing to use their email service for my personal needs, but having it on my website, enforcing it on my readers just doesn&amp;#x27;t feel right.&lt;/p&gt;&lt;/article&gt;</description><author>Muffin Man</author><pubDate>Sun, 21 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://muffinman.io/blog/this-blog-is-now-google-free/</guid></item><item><title>As Above, So Below - Our Inner &amp;amp; Outer Worlds</title><link>http://spirals.blog/articles/internal-external/</link><description>&lt;h2&gt;The Inside &amp;amp; the Outside&lt;/h2&gt;
&lt;p&gt;There are two worlds for all of us. Every single human being on the planet, every sentient creature experiences two realities; the inner and the outer. Inside of us lives our thoughts, our feelings, our ideas, and our beliefs. The other expands out around us, the chaotic plane of existence in which we all live. Sometimes these two worlds are at odds, and other times they live in harmony. The choice is often ours.&lt;/p&gt;
&lt;p&gt;Where I come from, one asked, &amp;quot;Does the internal match the external?&amp;quot; In other words, does the world around you agree with who you are, and do you agree with the world?&lt;/p&gt;
&lt;p&gt;Do &lt;em&gt;&lt;strong&gt;you&lt;/strong&gt;&lt;/em&gt; agree with the same way of solving life as the people around you? Or not? For some, they live in absolute, content, accordance with everything that's going on around them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Purple stay-at-home-mother of 7, living on a small island of the Philippines&lt;/li&gt;
&lt;li&gt;A Purple/Red college-dropout bar-tender, hopping from job to job in the South American jungle and beaches.&lt;/li&gt;
&lt;li&gt;It could be a Blue, living in a heavily Blue country like modern Iran or Australia, adhering to all laws and customs.&lt;/li&gt;
&lt;li&gt;An Orange/Red, living large in Wall Street, and loving it.&lt;/li&gt;
&lt;li&gt;Or, a Green, post-punk, vegan, nude painter living in a small art studio in Berlin.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For others, they are NOT content with the world around them, and either move somewhere else that agrees with them, turn it upside down, or, in some incredibly sad cases, give up.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Blue/Green protesting on the streets of Seattle, feeling a sense of justice was finally served to the police.&lt;/li&gt;
&lt;li&gt;A union of workers teaming up together to fight &amp;quot;The Man&amp;quot; for more equal wages.&lt;/li&gt;
&lt;li&gt;Teenage kids rebelling in school because &amp;quot;Fuck the teachers; that's why.&amp;quot;&lt;/li&gt;
&lt;li&gt;An entrepreneur leaving the small town in India to pursue his ideas in Silicon Valley.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What can we do about it?&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Protestors" src="http://spirals.blog/articles/internal-external/protestors.jpg" /&gt;
&lt;em&gt;Photo by Sasan Rashtipour @srashtipour&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Perhaps you may find yourself in a similar position to one of the above. Maybe it's not all of your life, but just one area. Have you ever felt out of place at your job or in a relationship? Traveled to a country that REALLY didn't agree with you or your values? Before we go assuming that we &lt;em&gt;&lt;strong&gt;should&lt;/strong&gt;&lt;/em&gt; leave because &lt;em&gt;&amp;quot;OUR perspective is correct&amp;quot;&lt;/em&gt;, we should stop – and consider the idea that perhaps we are running from something.&lt;/p&gt;
&lt;p&gt;This was the case in my own life. Around 18 years old, I &amp;quot;woke up&amp;quot; to what I thought the Blue narrative was. Blue meant, &amp;quot;Growing into an adult, getting a good education, a job, a mortgage, kids, fat, then divorcing only to die&amp;quot; Nope, not for me, thanks. I quit everything, left my fancy dual degree in Business Management and IT, resigned from the industry job that I'd &amp;quot;proudly started right out of high school,&amp;quot; and said goodbye to my girlfriend at the time. Simply put, I was running the hell away from Blue.&lt;/p&gt;
&lt;p&gt;I decided that a good thing to do would be &lt;em&gt;anything&lt;/em&gt; that wasn't what was before, so I booked a ticket to Spain to volunteer in meditation centers, with $4000 to my name and not a whiff of a plan. I told everyone I had no idea when I was coming back. I'd convinced myself that I could somehow solve the world's problems by meditating and giving my time to a worthy cause. I was out of perspective; big time.&lt;/p&gt;
&lt;h2&gt;Get into perspective before making ANY changes&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You might be wrong.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's hard for us to admit, but we often are, and we need to accept it. It does not have to be confronting, however, and this is where &lt;a href="https://spirals.blog/articles/building-environment/"&gt;our environment comes in&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bring people you trust and who know you well into your circle. Get them up to speed, and identify any filters that THEY might have in the moment as well. Explain your circumstance, where and who you feel you are, and the context. Listen intently to their responses, and study the intentions of what each person says, and what they think. If they know colors (which makes things MUCH more straightforward), we might choose to communicate certain aspects through this lens and focus on &lt;a href="https://spirals.blog/articles/building-environment/"&gt;the structure, not the content&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Getting into perspective" src="http://spirals.blog/articles/internal-external/chess.jpg" /&gt;
&lt;em&gt;Photo by Egor Myznik @vonshnauzer&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;More often than not, you'll see something else, something in what someone said, or felt, or the light in which they saw the conditions, and a part of how you see things… changes. A new piece of information you didn't see before. For some, this novel perspective poses such a threat to our current way of viewing life or the situation, that we reject it, attack it, or deny it entirely. We feel the pain of changing &amp;quot;everything else&amp;quot; is larger than the pain of ignoring it or fighting it – &lt;strong&gt;a cause of much unnecessary suffering.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;But if we are &lt;a href="https://spirals.blog/articles/open-arrested-closed/"&gt;Open, not arrested or closed&lt;/a&gt;, practice taking other perspectives often (as an art form), and we listened attentively enough, we might decide to shift, perhaps &amp;quot;integrate&amp;quot; this perspective into our own. If we feel safe to do so, we'll take on the contrary idea if we think it truly is a beneficial decision (so we should ensure our environment is ALSO in perspective).&lt;/p&gt;
&lt;h2&gt;What if there &lt;em&gt;genuinely&lt;/em&gt; is a mismatch? Should I change or just accept where I am?&lt;/h2&gt;
&lt;p&gt;The answer is, as always, it depends. Which has healthier colors? Do you possess a &amp;quot;moving away from Blue&amp;quot; (like in my situation)? Is there an aversion to Purple, Red, or any color? Look into why.&lt;/p&gt;
&lt;p&gt;Is it due to pushing away that &amp;quot;old&amp;quot; way of solving things? Or do you acknowledge/understand how some parts of it work but need some new tools for addressing those new problems you've started experiencing?
These are two very different cases. One is rejecting part of ourselves or the world's perspective, and the other is integrating it, but moving onto other things.&lt;/p&gt;
&lt;p&gt;Determining this distinction is often impossible to do alone, so enlisting the perspective of your environment can dramatically aid this process. &lt;em&gt;&lt;strong&gt;Be vulnerable, ask questions, and be honest&lt;/strong&gt;&lt;/em&gt;. Fail fast and fail often; this puts us in a healthier perspective to know ourselves, what we &lt;em&gt;&lt;strong&gt;really&lt;/strong&gt;&lt;/em&gt; want in life, and who we want with us on the journey.&lt;/p&gt;
&lt;h3&gt;If you can; change it slowly.&lt;/h3&gt;
&lt;p&gt;&lt;img alt="Acceptance" src="http://spirals.blog/articles/internal-external/acceptance.jpg" /&gt;
&lt;em&gt;Photo by Cristian Newman @cristian_newman&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Sometimes this is not possible (such as jumping into a new country), but often it can be.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of just &amp;quot;quitting your job&amp;quot; for that business idea (because you're sick of being told what to do), &amp;quot;grind it as a side hustle&amp;quot; until it makes enough to live on &lt;em&gt;(Stay in Blue and integrate it before jumping into Orange)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Rather than leaving the relationship because you're scared of getting too close because you were hurt before, hold on for just a little longer to explore the feeling and where it might lead. &lt;em&gt;(Healing our Purple, explore being vulnerable; instead of &amp;quot;defending ourselves&amp;quot; in unhealthy Red)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Do you need to leave your company of 20 years, overburdened with the stress, pressures, criticisms, and pain you might be feeling, to buy that sports car you've always wanted? Or could you possibly take up a few hobbies, go to a Meetup or two, and spend more time outside? (Not shifting too dramatically into Red after a long stint of Blue - a typical midlife crisis)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are just a few examples of the millions that happen every day. Taking time to slow down and think about what's going on for us and around us can prevent some big mistakes.&lt;/p&gt;
&lt;h2&gt;What if I feel great where I am? Do I/We &lt;em&gt;need&lt;/em&gt; to change?&lt;/h2&gt;
&lt;p&gt;No. Not unless you want to introduce more complexity into your life, which is not as glamorous as it sounds. Sometimes this is necessary, such as an invading country that is bringing a new perspective. Or a novel technology like the internet, which dramatically changes everything around it without our choice in the matter.&lt;/p&gt;
&lt;p&gt;Seeking out a deliberate change can be a dangerous endeavor. Especially if we don't have the supporting environment to guide us to the &amp;quot;new world&amp;quot; we are seeking. It can be useful if done correctly (not running from our shadows) and for the right reasons (solving a new type of problem), but we must apply the utmost care and precision to the transition.&lt;/p&gt;
&lt;h2&gt;As Above, So Below&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://spirals.blog/articles/getting-to-know-your-own-perspective-part-1/"&gt;So where are you at?&lt;/a&gt; Does your internal match your external? Do you feel a sense of peace and balance when you think about the immediate world you're living in, or do you feel resistance (internally or externally)?&lt;/p&gt;
&lt;p&gt;If you do feel friction, from where does the disagreement arise? Is it driven by fear, rejection, or &amp;quot;blindness to other perspectives&amp;quot;? Or is it more systemic, something genuinely unhealthy in the world around you?&lt;/p&gt;
&lt;p&gt;Whatever we &lt;em&gt;&lt;strong&gt;think&lt;/strong&gt;&lt;/em&gt; the answer might be, we should always get this checked by someone not in the same position before making big moves. As much as you might want to break free and change it all, hold on just a bit longer until you're coming from a broader perspective.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Life is a mirror and will reflect back to the thinker what he thinks into it.&amp;quot; — Ernest Holmes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Are the problems we feel so strongly about &lt;em&gt;actually&lt;/em&gt; a problem? Or is it just how we're currently viewing them? There are, of course, legitimate, systemic issues in this world, that's not lost on us. However, are the day to day issues in our relationships, careers, and families undoubtedly related to them? How else could we view the situation?&lt;/p&gt;
&lt;h2&gt;A path of least resistance&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Peace" src="http://spirals.blog/articles/internal-external/peace.jpg" /&gt;
&lt;em&gt;Photo by Colton Duke @csoref&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Changing our inner world is always easier than changing our external world. Yet, for the majority of us, we spend all of our time and energy worrying. We allow the disconnection of &amp;quot;where we are&amp;quot; and &amp;quot;where we want to be&amp;quot; to drive us to states of anger, sadness, or fear. These thoughts and feelings propagate out to everything else we do in our lives, polluting our minds and our hearts, and creating more issues than are realistically there. A vexing mirage.&lt;/p&gt;
&lt;p&gt;While inaction and blind acceptance of our reality is also not the solution, we could assuredly practice more empathy, forgiveness, and love as a species. Next time we feel separated from our outer world, let's stop and ask ourselves, &amp;quot;How else could this be viewed? Is there something that &lt;em&gt;&lt;strong&gt;I&lt;/strong&gt;&lt;/em&gt; am not accepting that perhaps I should?&amp;quot;.&lt;/p&gt;
&lt;p&gt;Everyone has a unique perspective, each with beautiful truths, and terrible deceptions. Let us open our hearts to the beauty in others, and help heal the shadows in ourselves, our people, and our ideas.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cover photo by NICO BHLR @nicobhlr&lt;/em&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 21 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/internal-external/</guid></item><item><title>What went wrong with the internet (and how can it be fixed)?</title><link>https://michael-lewis.com/posts/what-went-wrong-with-the-internet-and-how-to-fix-it/</link><description>&lt;h2 id="then-and-now"&gt;
  Then and now
  &lt;a class="heading-link" href="#then-and-now"&gt;
    &lt;i class="fa-solid fa-link" title="Link to heading"&gt;&lt;/i&gt;
    &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
  &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I remember when the internet, or more specifically the web, was new. There was so much hope and optimism. Early adopters talked excitedly of the seemingly endless ways in which it would revolutionise so many aspects of society in positive ways. There was the idea that &amp;ldquo;information wants to be free&amp;rdquo;, where free, at least how I understood it, was free as in &amp;ldquo;libre&amp;rdquo; (freedom) rather than &amp;ldquo;gratis&amp;rdquo; (zero cost). There were so many eclectic sites about hobbies and interests driven by the author&amp;rsquo;s passions, and an immense sense of wonder, excitement and discovery when exploring them. Even when people started selling things on the internet, there was the idea that commerce would be transformed by &amp;ldquo;disintermediation&amp;rdquo;, i.e. opened up to lots of small sellers without the middle-person taking their cut. I know it wasn&amp;rsquo;t all positive, with a minority concerned by its uncontrolled growth and the ease with which questionable material could be made readily available, but it was overwhelmingly positive. It seemed like we were fortunate enough to be on the cusp of a once-in-every-few-generations technology-driven paradigm shift, like the invention of the printing press or the electric telegraph.&lt;/p&gt;</description><author>Michael Ian Lewis</author><pubDate>Sun, 21 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://michael-lewis.com/posts/what-went-wrong-with-the-internet-and-how-to-fix-it/</guid></item><item><title>Writing a curriculum vitæ</title><link>https://bastian.rieck.me/blog/2020/cv/</link><description>&lt;p&gt;I have been giving a lot of feedback about how to write a better
curriculum vitæ (CV) recently. This post is a way of structuring
and disseminating my thoughts on this matter. As a start, let me briefly
delineate what this post is &lt;em&gt;not&lt;/em&gt; about: I am not discussing how to
write a &lt;em&gt;resume&lt;/em&gt;. A resume is typically only a single page long and
should provide all information pertinent to a very specific job. A CV,
by contrast, can be any length and usually contains &lt;em&gt;all&lt;/em&gt; details
pertinent to your professional life.&lt;/p&gt;
&lt;h1 id="why-you-need-a-cv"&gt;Why you need a CV&lt;/h1&gt;
&lt;p&gt;Having a CV handy is useful in a variety of situations. Even if you are
not actively looking for a job, recruiters might find your CV and use
it to contact you about an opportunity&amp;mdash;and who of us does not like it
when opportunity comes a-knocking? Moreover, since &lt;em&gt;you&lt;/em&gt; control what
you put in the CV, you can associate yourself with certain key words for
your research, your special skills, and so on. Last, it provides
a single point of entry to collect your professional activities. There
is no other document or platform that provides you the same opportunity
to describe &lt;em&gt;your&lt;/em&gt; work on &lt;em&gt;your&lt;/em&gt; terms.&lt;/p&gt;
&lt;h1 id="the-structure"&gt;The structure&lt;/h1&gt;
&lt;p&gt;The basic structure of a good CV is always the same. Make sure that the
first page contains the following information:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Your name and some points of contact. These could include your office
address, an e-mail address, any social media handles you &lt;em&gt;want&lt;/em&gt;
a potential employer to see&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;, and links to services such as &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt;
or &lt;a href="https://bitbucket.org"&gt;Bitbucket&lt;/a&gt;. This section is relevant
because it will tie all the account handles to &lt;em&gt;you&lt;/em&gt; as a person, but
also give &lt;em&gt;me&lt;/em&gt;&amp;mdash;the reader of your CV&amp;mdash;an opportunity to check
whether I got the right person. Plus, it is an excellent way to
enable recruiters to find more proofs of your work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The most relevant details concerning your education or your most
recent professional experience (in reverse chronological order,
i.e. the most recent piece of information should be shown
first). Some examples: if you are doing your master&amp;rsquo;s thesis, write
that first, provide a tentative title, and your adviser. If you just
started your Ph.D., write something about your topic, your school,
etc. All of these details tell readers at which point you are in your
career&amp;mdash;and this might decide how the CV is being received, what
kind of offers you might be getting, and so on.&lt;/p&gt;
&lt;p&gt;This section is also useful when you are applying for a job or
a fellowship, as it gives readers details about your field of
specialisation, and it also provides important information for
potential contacts. Some of my friends, who did not go down the
academic route, even mention that their thesis topic came up in
a job interview&amp;mdash;this is the interviewer basically handing you
a freebie by picking a topic you know a lot about.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A brief description of your research interests, or specialisation, or
personality. Admittedly, this is not crucial, but it helps to add
a few lines here. Be brief, as in &lt;em&gt;My research deals with
representation learning and the incorporation of domain-specific
knowledge&lt;/em&gt;, or &lt;em&gt;I am a back-end software developer with a focus on
cryptographic protocols&lt;/em&gt;, or &lt;em&gt;I am a lawyer focussing on
international affairs&lt;/em&gt;&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;. You do not have to add all kinds of
details here; a reader should just get the general gist of what
kind of career you are having or planning to have.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is the first page only. Now, my advice becomes more tailored
towards academic careers. Having mentioned who you are and how to
contact you, you now have to add the daily bread of your research. The
most important items are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Grants&lt;/strong&gt; or independent funding that you secured. This is mostly relevant
when you are approaching the end of one chapter of your career, such
as the transition from master&amp;rsquo;s student to Ph.D. student, or the
transition from Ph.D. to postdoctoral researcher. It is rare
to have any entries in such a section early on, but as you mature, it
becomes increasingly important to demonstrate that you can develop
your own ideas &lt;em&gt;and&lt;/em&gt; get the funding to work on them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Publications&lt;/strong&gt;! Again, add them in reverse chronological order so that
one can immediately see the most recent ones. Depending on where you
are in your career, you might want to further partition them
according to the relevance of a venue. For example, you might want to
put highly-competitive journal or conference publications first,
followed by an individual section for workshop papers, which in turn
might be followed by a preprint section. Notice that I am not saying
that preprints are inherently worth &lt;em&gt;less&lt;/em&gt; than accepted
publications; you should just make it clear to your readers whether
a given item was peer-reviewed or not. If you do not have a lot of
publications, do not despair, and just list &lt;em&gt;all&lt;/em&gt; of them in the same
section!&lt;/p&gt;
&lt;p&gt;Some general tips about this part:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Make sure that each item is formatted correctly and gives proper
credit to things like joint authorship, joint supervision etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provide sufficient details for readers to &lt;em&gt;find&lt;/em&gt; or &lt;em&gt;identify&lt;/em&gt; the publication.
Use the proper title, the proper venue, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you are one of multiple authors, highlight your own name. While
typically frowned upon in professional typography, &lt;strong&gt;bold&lt;/strong&gt; has
become the standard way of doing this. As you advance in your career,
you do not necessarily need this any more, as people will trust your
publication prowess more, but in the beginning, it is really
important. The same goes for highlighting any supervision you did for
a paper. I &lt;u&gt;underline&lt;/u&gt; the students I have been supervising.
Again, as you mature in your career, this may not be necessary any
more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Refrain from providing information about the acceptance rate of
a conference. Readers should either be familiar with this type of
information (for example, when you are applying for a new
position) or they do not care. I think mentioning these numbers is
the wrong thing to do; in the worst case, it might make you look like
a &amp;lsquo;bean-counter&amp;rsquo; that is confused about the true purpose of doing
science, i.e. disseminating knowledge and attacking the
boundaries of human ignorance. Same goes for counting your
publications. I do not see the appeal of stating that you have $n_c$
conference papers, $n_w$ workshop papers, etc. Zachary Lipton
formulated this nicely in a &lt;a href="https://twitter.com/zacharylipton/status/1167859710168485889"&gt;witty tweet&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;However, &lt;em&gt;do&lt;/em&gt; put additional information about the grant acceptance
rates or special mentions about your paper in the list. For
example, if your paper receives a coveted spotlight presentation
in a conference, mention it! There is a time and place for modesty,
but you should not make your life a lot harder than it has to be.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Talks&lt;/strong&gt;. Again, feel free to further separate them into &lt;em&gt;Invited
Talks&lt;/em&gt;&amp;mdash;where someone specifically invited &lt;em&gt;you&lt;/em&gt; to speak to
them&amp;mdash;and &lt;em&gt;Conference Talks&lt;/em&gt; etc. if you have a sufficient number of
them. For each talk, mention the title and the venue or location.
This is particularly useful when you give a similar talk multiple
times in &lt;em&gt;different&lt;/em&gt; labs, as it demonstrates that your research is
well-received by the community.&lt;/p&gt;
&lt;p&gt;Such talks can also be useful to discuss in a job interview; I myself
have been asked about some of my earlier talks, in particular the
ones that have been prepared for a non-academic audience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Teaching and supervision&lt;/strong&gt;. Provide some details about your
teaching activities. For example, did you support a professor in
their lectures by organising exercises? Did you maybe even give a few
lectures on your own? Be specific here and add &lt;em&gt;everything&lt;/em&gt; that
demonstrates that you are capable of standing&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; in front of students
and talking to them about something.&lt;/p&gt;
&lt;p&gt;As for the supervision part: if you ever supervised or helped
supervise a thesis, list it here. In this case, you were &lt;em&gt;advising&lt;/em&gt;
another person; even if that form of supervision might not be
officially recognised by your home institution, it should be
mentioned in your CV if it happened&amp;mdash;remember, you are not claiming
to have been the one who signs off on the thesis, but you &lt;em&gt;are&lt;/em&gt;
claiming that you are capable of supporting students in finishing
a project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Service to the community&lt;/strong&gt;. If you have been reviewing things for
journals or conferences, list them. The same goes for organising
a workshop, assisting in running a conference, and so on. Anything
that is useful to other researchers belongs in this category.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Special skills&lt;/strong&gt;. Here you can showcase your ability to, say, operate
mass spectrometry machines, or write code in &lt;code&gt;Python&lt;/code&gt; using certain
machine learning frameworks etc. Make this section as &lt;em&gt;strong&lt;/em&gt; and
&lt;em&gt;specific&lt;/em&gt; as possible. For example, when mentioning your knowledge
of a specific programming language, provide some links or some
details. Do &lt;em&gt;not&lt;/em&gt; list all programming languages you have ever heard
of without at least briefly qualifying what your knowledge is here.
Are you a beginner user in JavaScript? Or do you already have decades
of experience under your belt?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Miscellanea and references&lt;/strong&gt;. Everything else that does not fit
easily into the pre-defined categories could be listed here. If you
have a blog&amp;mdash;such as yours truly&amp;mdash;you might want to mention it, for
example. Some people also mention hobbies; I have no special
preference here and leave them out most of the time.&lt;/p&gt;
&lt;p&gt;Last, but certainly not least, add the contact details of some
references. Whom could I contact if I wanted to learn more about you?
This is particularly relevant if you are just starting out in your
career. You can get people to be your referees if you just ask
them&amp;mdash;no specific reason is required, and most people I know are
happy to support their former students and employees.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modification date&lt;/strong&gt;. Close your CV by mentioning when it was last
updated. This makes it easier to see whether we are looking at
something that is recent or something that is more than four years
old. Some people also include the modification date in the header. If
you are using LaTeX&amp;mdash;and you &lt;em&gt;should&lt;/em&gt;, but that is a different
story&amp;mdash;just use the &lt;code&gt;\today&lt;/code&gt; command here.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="the-looks"&gt;The looks&lt;/h1&gt;
&lt;p&gt;How you format the CV is really not all that important. While I like
minimalist styles, the CV should express &lt;em&gt;your&lt;/em&gt; personal preferences. If
you want to throw a lot of colour at readers, go forth and have fun!
Same goes fro using a pre-made template. The important this is to fill
the CV with quality content. You can always update and improve it, but
having a CV that is done with the default settings of the &lt;a href="https://ctan.org/tex-archive/macros/latex/contrib/moderncv"&gt;&lt;code&gt;moderncv&lt;/code&gt;&lt;/a&gt;
package is better than not having a CV at all!&lt;/p&gt;
&lt;h1 id="some-questions"&gt;Some questions&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Should I include a photo or not?&lt;/em&gt; It depends on your geographical
location. In Europe, pictures are increasingly frowned upon, and, in
some cases, asking for one in the CV might even be illegal. Since I,
and probably anyone else, has a lot of pictures on their accounts, I
figure that it does not really matter&amp;mdash;if someone wants to see your
inherent beauty, they can do so themselves. I would rather use my CV
space to list my achievements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Should I include volunteer work?&lt;/em&gt; Sure, why not! Bear in mind that
some employers might look less charitably on some organisations than
on others. However, in the spirit of this very apt &lt;a href="https://xkcd.com/137"&gt;xkcd comic&lt;/a&gt;, I would rather include them than
exclude them. Not getting interviewed because your prospective employer dislikes the
causes you yourself find important is probably a boon in disguise.
Would you really be happy with working for such an employer anyway?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Should I include links?&lt;/em&gt; Yes, please do! As many as you can. If
I can find your great paper easily, that&amp;rsquo;s superb.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Should I include software projects?&lt;/em&gt; Yes, of course. Anything that
is useful. Even if you think your code is not good enough, trust me:
no one&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt; is going to negatively comment on your code. Instead, the
standard reaction is &amp;lsquo;Thanks for sharing that&amp;rsquo;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Should I include my grades?&lt;/em&gt; Yes, if they are good or required for
a certain position. If you always graduated top of your class etc.,
please &lt;em&gt;do&lt;/em&gt; include them! If your grades are mediocre, for whatever
reason, and they are not specifically required, I would leave them
out, probably.&lt;/p&gt;
&lt;p&gt;By the way: if you are worried about your grades and what they mean for your
future, maybe &lt;a href="https://3dpancakes.typepad.com/ernie/2005/03/re_phd_with_low.html"&gt;this post&lt;/a&gt;
by the inimitably awesome &lt;a href="https://jeffe.cs.illinois.edu"&gt;Jeff Erickson&lt;/a&gt;
will be helpful.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I hope that these tips were useful and wish you good luck in your
careers, wherever they may take you. Until next time!&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;The discussion of whether it is useful to have any account
associated with your proper name has been raging for multiple years
now. I am firmly in the &amp;lsquo;Take control&amp;rsquo; camp, by which I mean that &lt;em&gt;if&lt;/em&gt;
I create any account with my proper name, I assume that the general
public is capable of reading it and associating it to me as a person.
This is in particular relevant for services such as Twitter, where the
private and the public often commingle and interact in unexpected
ways.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;I am making this up as a I go along, but it sounds like a cool job
title.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;In the current situation, this could also mean that you are
prepared to talk into a microphone for prolonged periods of time. All
the more power to you!&amp;#160;&lt;a class="footnote-backref" href="#fnref:3"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;Except for the meanest and loneliest individuals on this planet,
that is.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Ecce Homology on Bastian Grossenbacher Rieck's personal homepage</author><pubDate>Sat, 20 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://bastian.rieck.me/blog/2020/cv/</guid></item><item><title>A Future is a Suspending Scheduler</title><link>https://nikhilism.com/post/2020/futures-suspending-scheduler/</link><description>Introduction This is another blog post related to the Build Systems à la Carte paper. See Using type-classes to model the expressivity of build systems for the first one.
The paper proposes splitting build systems into two components:
Rebuilders decide when to rebuild a particular key (file). Schedulers decide how to rebuild multiple keys - handling dependencies while maintaining correctness and efficiency. Schedulers come in 3 flavors (see Section 4):</description><author>Nikhil's blog</author><pubDate>Sat, 20 Jun 2020 18:57:42 GMT</pubDate><guid isPermaLink="true">https://nikhilism.com/post/2020/futures-suspending-scheduler/</guid></item><item><title>Save forests, not tigers... 2020 edition!</title><link>https://stop.zona-m.net/2020/06/save-forests-not-tigers...-2020-edition/</link><description>&lt;p&gt;Some animals are important because they are termometers.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 20 Jun 2020 14:28:14 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/save-forests-not-tigers...-2020-edition/</guid></item><item><title>Docs as Code</title><link>https://blog.herlein.com/post/docs-as-code/</link><description>&lt;p&gt;One of the core principles of modern &amp;ldquo;DevOps&amp;rdquo; development is to treat your documentation as code, just like code.  My team at Cisco open sourced how we do that.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 20 Jun 2020 14:10:43 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/docs-as-code/</guid></item><item><title>Headless Setup for a Raspberry Pi Zero-W</title><link>https://www.mikekasberg.com/blog/2020/06/19/headless-setup-for-a-raspberry-pi-zero-w.html</link><description>&lt;p&gt;&lt;strong&gt;No keyboard, mouse, or monitor required!&lt;/strong&gt; In this tutorial, I’ll show you how
to ssh to a Raspberry Pi Zero W without ever using a keyboard, mouse, or monitor
on the device itself. We’ll prepare the device to connect to your wireless
network (even with a password) when it’s turned on for the first time – this
process is known as “headless setup”.&lt;/p&gt;

&lt;p&gt;When you buy a Raspberry Pi, the cost of all the little accessories you might
need (like a way to connect a keyboard, mouse, and monitor to the micro-USB and
micro-HDMI ports) can add up quickly. But do you really need all that? &lt;strong&gt;You
don’t!&lt;/strong&gt; It isn’t too hard to configure a Raspberry Pi Zero W to connect to a
wireless network automatically when it boots, and then you can interact with it
via SSH without ever connecting a monitor, keyboard, or mouse!  (You’ll need
another computer, of course.) To accomplish this, we’ll modify a couple things
on the SD card after we’ve written the image but before putting it in the Pi.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Prepare your SD card with Raspberry Pi OS (AKA Raspbian), as described
&lt;a href="https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system"&gt;here&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Open the “boot” partition of the SD card. This should show up as a removable
drive when you insert the card – you might need to remove and re-insert the SD
card after writing the image.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;On the boot partition, create a text file named &lt;code class="language-plaintext highlighter-rouge"&gt;wpa_supplicant.conf&lt;/code&gt; (no
&lt;code class="language-plaintext highlighter-rouge"&gt;.txt&lt;/code&gt;!) with the following contents. This will configure the wifi when the
device boots.  (Change the ssid and psk to your network name and password.)&lt;/p&gt;

    &lt;div class="language-plaintext highlighter-rouge"&gt;&lt;div class="highlight"&gt;&lt;pre class="highlight"&gt;&lt;code&gt;country=US
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="MyWiFiNetwork"
    psk="aVeryStrongPassword"
    key_mgmt=WPA-PSK
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class="warning"&gt;
  &lt;p&gt;&lt;b&gt;Warning!&lt;/b&gt;&lt;/p&gt;
  &lt;p&gt;The Pi Zero W doesn't support 5GHz networks. You'll need to use a 2.4GHz
  network with your Pi.&lt;/p&gt;
&lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Even if the Pi connects to wifi automatically, ssh access will be disabled by
default. To change this, make an empty text file named &lt;code class="language-plaintext highlighter-rouge"&gt;ssh&lt;/code&gt; (no file
extension!) on the boot partition. As long as this file exists, ssh will
be enabled when the device boots for the first time.&lt;/li&gt;
  &lt;li&gt;Now we’re ready! Put the SD card in the Pi, plug in the Pi, and give it a
minute to boot up and connect to the wifi. This is where the magic happens,
where the Pi &lt;strong&gt;boots, connects to your network, and enables SSH access without
any interaction&lt;/strong&gt;. At this point, we’re basically
&lt;strong&gt;done&lt;/strong&gt; with setup, but we still need to connect to the Pi.&lt;/li&gt;
  &lt;li&gt;Find the IP address of the Pi on your local network. There are a variety of
ways to do this depending on your network configuration. Read the instructions
&lt;a href="https://www.raspberrypi.com/documentation/computers/remote-access.html#ip-address"&gt;here&lt;/a&gt;
and pick a method that works for you. The Pi’s IP will probably be something
like &lt;code class="language-plaintext highlighter-rouge"&gt;192.168.0.10&lt;/code&gt;, but it could be different.&lt;/li&gt;
  &lt;li&gt;SSH to the Pi.
    &lt;ul&gt;
      &lt;li&gt;If you’re on &lt;strong&gt;macOS&lt;/strong&gt; or &lt;strong&gt;Linux&lt;/strong&gt;, the ssh tool should already be installed. Open
the Terminal app (in the Utilities folder in Applications) and type &lt;code class="language-plaintext highlighter-rouge"&gt;ssh
pi@192.168.x.x&lt;/code&gt; (using the IP you found in the previous step). &lt;code class="language-plaintext highlighter-rouge"&gt;pi&lt;/code&gt; is the
username and &lt;code class="language-plaintext highlighter-rouge"&gt;raspberry&lt;/code&gt; is the default password.&lt;/li&gt;
      &lt;li&gt;If you’re on &lt;strong&gt;Windows&lt;/strong&gt;, you’ll need to install an SSH tool. I recommend
&lt;a href="https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html"&gt;PuTTY&lt;/a&gt;.
(You probably want the 64-bit MSI installer version from that website.)
Enter the IP you found in the previous step and connect using &lt;code class="language-plaintext highlighter-rouge"&gt;pi&lt;/code&gt; as the
username and &lt;code class="language-plaintext highlighter-rouge"&gt;raspberry&lt;/code&gt; as the password.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Done!&lt;/strong&gt; Now that you’re connected to the Pi via SSH, you can run any commands
you want to. You might start with &lt;code class="language-plaintext highlighter-rouge"&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get upgrade&lt;/code&gt;
to make sure the system’s up to date. From there, you can play around as much as
you want in the Raspbian Linux environment (based on Debian/Ubuntu), or you can
install any additional software needed for your project.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Terminal SSH animation" src="https://www.mikekasberg.com/images/headless-pi-zero-w/ssh.gif" /&gt;&lt;/p&gt;

&lt;p&gt;I hope this helped you get started with your Raspberry Pi, and maybe saved you a
few dollars on accessories you don’t need to buy!&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;This is part 1 of a 2-part series exploring the Raspberry-Pi Zero.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Part 1:&lt;/strong&gt; Headless Setup for a Raspberry Pi Zero-W&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Part 2:&lt;/strong&gt; &lt;a href="https://www.mikekasberg.com/blog/2020/06/22/vnc-for-headless-raspberry-pi.html"&gt;Can You VNC to a Desktop on a Headless Raspberry Pi?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Sat, 20 Jun 2020 06:00:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/06/19/headless-setup-for-a-raspberry-pi-zero-w.html</guid></item><item><title>Mataroa webring integration</title><link>https://nutcroft.mataroa.blog/blog/mataroa-webring-integration/</link><description>&lt;p&gt;Extremely excited to announce that &lt;a href="https://mataroa.blog"&gt;mataroa.blog&lt;/a&gt; now has a &lt;a href="https://en.wikipedia.org/wiki/Webring"&gt;webring&lt;/a&gt; integration!&lt;/p&gt;
&lt;p&gt;One can add two URLs: "next" and "previous", and become part of the arcane technique of decentralised content discovery.&lt;/p&gt;
&lt;h2 id="start-your-ring"&gt;Start your ring&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Update May 2021: This tool no longer works due to the new referrer policies by &lt;a href="https://developers.google.com/web/updates/2020/07/referrer-policy-new-chrome-default"&gt;Chrome&lt;/a&gt; and &lt;a href="https://blog.mozilla.org/security/2021/03/22/firefox-87-trims-http-referrers-by-default-to-protect-user-privacy/"&gt;Firefox&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mxb.dev/"&gt;Max Böck&lt;/a&gt; made a nice &lt;a href="https://mxb.dev/blog/webring-kit/"&gt;Webring Kit&lt;/a&gt; that enables dynamic next/previous webring links, so that one does not have to manually edit those on their website. Adds a bit of centralisation but makes it much easier to manage.&lt;/p&gt;
&lt;p&gt;The kit uses the &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt; static site generator and is configured to deploy on Netlify. Get started &lt;a href="https://github.com/maxboeck/webring"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="revival"&gt;Revival&lt;/h2&gt;
&lt;p&gt;The need for webrings stemmed during the 90s when there was no Google and search engines were inefficient in helping people discover web content.&lt;/p&gt;
&lt;p&gt;The need re-arises in 2020, when search engines are influenced by SEO techniques and content platforms have become silos. These days, an indie web revival would be incredible.&lt;/p&gt;
&lt;p&gt;A webring has a specific theme, and the links that comprise it are curated. Manually curating a webring's content means that it has been agreed that the website's content is relevant to the webring's theme. The modern web approach would be to add a neural network to figure out the website's theme, but that would be totally not fly!&lt;/p&gt;
&lt;h2 id="see-also"&gt;See also&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sonniesedge.net/posts/webrings/"&gt;https://www.sonniesedge.net/posts/webrings/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bryanlrobinson.com/blog/bring-fansites-back-to-the-web/"&gt;https://bryanlrobinson.com/blog/bring-fansites-back-to-the-web/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://indieweb.org/"&gt;https://indieweb.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://indieweb.org/Webmention"&gt;https://indieweb.org/Webmention&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://awesomeblog.club/"&gt;https://awesomeblog.club/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blogs.sirodoht.com/"&gt;https://blogs.sirodoht.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.sr.ht/~sircmpwn/openring"&gt;https://git.sr.ht/~sircmpwn/openring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://neocities.org/"&gt;https://neocities.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://href.cool/"&gt;https://href.cool/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://weirdwidewebring.net/"&gt;https://weirdwidewebring.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webring.xxiivv.com/"&gt;https://webring.xxiivv.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>nutcroft</author><pubDate>Sat, 20 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/mataroa-webring-integration/</guid></item><item><title>Dialogue Tags: An Empirical Study</title><link>/2020/06/dialogue-tags</link><description>Dialogue tags (“he said”, “she said”) seem simple, but can be surprisingly subtle. There are also a lot of variations that aren’t covered in common guides. I’ve had trouble finding good information about dialogue tags online, so I decided to put together this guide, mostly for my own use. Hopefully it might be useful for others as well.</description><author>Elliott Slaughter</author><pubDate>Sat, 20 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/2020/06/dialogue-tags</guid></item><item><title>Notes on RSI for Developers</title><link>https://www.swyx.io/rsi-tips</link><description>I'm starting to feel some RSI in my left hand. It's a matter of time. I decided to collect some information about it to make improvements now rather than later.</description><author>swyx's site RSS Feed</author><pubDate>Fri, 19 Jun 2020 21:45:25 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/rsi-tips</guid></item><item><title>Italian lawmakers still don't know how the Internet works</title><link>https://stop.zona-m.net/2020/06/italian-lawmakers-still-dont-know-how-the-internet-works/</link><description>&lt;p&gt;Some things just never change.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 19 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/italian-lawmakers-still-dont-know-how-the-internet-works/</guid></item><item><title>[Quora] Transparency in distributed systems UX</title><link>https://blog.separateconcerns.com/2020-06-19-quora-transparency-distributed.html</link><description>&lt;p&gt;Yet another &lt;a href="https://blog.separateconcerns.com/2020-04-09-quora-lua-call.html"&gt;Quora answer&lt;/a&gt;, this time to with &lt;a href="https://www.quora.com/Why-is-Transparency-a-major-issue-in-distributed-databases"&gt;this question&lt;/a&gt; which I answered on August 24, 2016:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why is Transparency a major issue in distributed databases?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;First, a few words about what “transparency” is. Transparency is a &lt;a href="https://en.wikipedia.org/wiki/Transparency_%28human%E2%80%93computer_interaction%29"&gt;UX term&lt;/a&gt; about the user not noticing that they are using a distributed system. We actually talk about transparencies in the plural, because there are several kinds of transparencies: fault transparency, location transparency, concurrency transparency, access transparency, etc. In my opinion, the choice of wording is not so good: when we talk about “transparency” we actually mean we hide things from the user, so “opacity” would be more logical. (The name comes from the fact that, if we replace a single node system by a distributed system, it will be transparent for the user, i.e. then will not notice it.)&lt;/p&gt;
&lt;p&gt;The reason why transparency is important is usability. The more transparencies our system has, the less cognitive burden there is on the user. In other words: &lt;strong&gt;transparencies simplify the API of the system&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;However, what transparencies we implement or not is a trade-off between that simplicity of API and things like flexibility, performance, and sometimes correctness. Years ago (when Object Oriented programming à la Java was booming) it was fashionable to abstract everything and make the user forget that they were using an actual distributed system. For instance, we had RPC everywhere, which kind of hid the network from the user. Since then we learnt that &lt;a href="http://www.rgoarchitects.com/Files/fallacies.pdf"&gt;abstracting the network entirely is a bad idea&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;On the other hand, exposing too many knobs to the user is dangerous as well: they might turn them without really understanding what they do and set the system on fire.&lt;/p&gt;
&lt;p&gt;So, determining what to expose to the user and what to implement “transparently” is a crucial point in all distributed systems work, not only databases.&lt;/p&gt;
&lt;p&gt;In databases in particular, conflict resolution is a contention point. Do we only provide the user with databases that are consistent, knowing that this severly impacts performance and availability? Do we let them tweak the parameters (the R and W parameters in a quorum system, for instance)? Do we tolerate divergence, detect it, inform the user and let them reconcile (à la CouchDB)? Do we provide the user with constrained datastructures that resolve conflicts by themselves (CRDTs)?&lt;/p&gt;
&lt;p&gt;Some people have gone as far as saying that &lt;a href="https://bravenewgeek.com/distributed-systems-are-a-ux-problem/"&gt;Distributed Systems Are a UX Problem&lt;/a&gt; and I tend to agree with this line of reasoning.&lt;/p&gt;</description><author>Separate Concerns</author><pubDate>Fri, 19 Jun 2020 19:52:00 GMT</pubDate><guid isPermaLink="true">https://blog.separateconcerns.com/2020-06-19-quora-transparency-distributed.html</guid></item><item><title>Lightning Fast ZSH Performance</title><link>/zsh-speed/</link><description>&lt;p&gt;As part of my work to &amp;quot;sharpen the saw&amp;quot;, I decided to spend some time improving the performance of various components in my setup. The first target of my attention was ZSH.&lt;/p&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;I open new shell instances constantly and try to live in the terminal as much as possible (including for writing this blog - in vim to be precise :wave:), so each second spend loading new shell windows or tabs is a second wasted. Additionally, when things take time to load, you're more distracted and/or frustrated with how long it's taking to load rather than the current outcome you were trying to achieve. In my eyes, speed is one of the 3 major pillars of user experience - along with findability and accessibility.
To start on this performance journey, I first needed a quantifiable metric to track my progress as I made changes.&lt;/p&gt;
&lt;p&gt;To do this I ran the following command&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;for i in $(seq 1 10); do /usr/bin/time $SHELL -i -c exit; done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try running it in your shell of choice now, and you'll get a performance breakdown of 10 runs of initiating your shell! For me the response was this&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.5 seconds 0.8 user 0.7 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1.5 seconds may not seem like a lot, but that is more than noticeable to any human. Time perception is a whole other topic for far more intelligent people than I. But after some digging, the consensus seems to be that reaction times are around 150ms (input-to-action) and 13ms for perceptive time (from visual stimuli).
Therefore, our benchmark we were aiming for was 0.13 seconds. This is a number I now seek out across all software I use and consume.&lt;/p&gt;
&lt;p&gt;Ok so, we've got a benchmark of 0.13 seconds meaning we need to reduce the load times by 1.37 seconds - let's get to it!&lt;/p&gt;
&lt;h2&gt;Phase one - the big boys&lt;/h2&gt;
&lt;p&gt;I had a rough idea of what might be taking the time in my zshrc file.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;NVM - this is a node version library that I've (unfortunately) used for years. It allows you to quickly swap between node versions. Handy but performance intensive. It initiates for each shell instance so you have access to the &lt;code&gt;nvm&lt;/code&gt; command. I don't need this all the time, so it can be removed. Note, by removing this, it still allows me to use the &amp;quot;NVM&amp;quot; node install - just not change it.&lt;/li&gt;
&lt;li&gt;ZSH Sourcing - The standard oh-my-zsh config contains the line &lt;code&gt;source $ZSH/oh-my-zsh.sh&lt;/code&gt;. We don't need this as I was using Antigen as a plugin manager, which automatically includes oh-my-zsh, so in reality I was sourcing it twice!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After these changes, I ran the test script from earlier and got the following result&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.61 real 0.32 user 0.27 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's nearly a second removed just by removing NVM and sourcing ZSH! A huge difference so happy about that.&lt;/p&gt;
&lt;p&gt;The next suspect I had on my list was my prompt, I used this heavy emojified Spaceship theme that was installed via NPM. Most of the time, if something looks good, it takes ages to load.
I switched over to the &lt;a href="https://github.com/sindresorhus/pure"&gt;Pure prompt&lt;/a&gt; and remeasured the results&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.54 real 0.29 user 0.24 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, so not a massive change, but the overall experience of loading a new shell felt instantly snappier. It could have been a placebo but it worked for me, so I plowed on ahead for more culprits. But I needed help...&lt;/p&gt;
&lt;h2&gt;Phase two - profiling&lt;/h2&gt;
&lt;p&gt;Now I had removed some &amp;quot;big hitters&amp;quot; to performance, it was time to dive into the nitty gritty. We can do this by profiling our ZSH config so we can see what is taking the time.
We can do this with a tool called &lt;a href="http://zsh.sourceforge.net/Doc/Release/Zsh-Modules.html"&gt;zprof&lt;/a&gt;, which is bundled with ZSH by default.
We can add it by putting &lt;code&gt;zmodload zsh/zprof&lt;/code&gt; at the top of our &lt;code&gt;~/.zshrc&lt;/code&gt; config and then putting &lt;code&gt;zprof&lt;/code&gt; at the very bottom of the config.&lt;/p&gt;
&lt;p&gt;Now we simply need to reload our shell and we get a nice breakdown of the time taken for each part of our config.&lt;/p&gt;
&lt;p&gt;&lt;img alt="zprof profile" src="../../assets/images/zprof.png" /&gt;&lt;/p&gt;
&lt;p&gt;We can clearly see from the above screenshot that a plugin called set_iterm_tab_color is accounting for a lot of our load time. The plugin wasn't really what I wanted it for anyway (I wanted something like peacock for VSCode).
I removed it and a few other Antigen plugins and re-ran the test script again&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.30 real 0.17 user 0.14 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's the load time halved! I was pretty happy to stop at this stage but I kept pursuing that prized 0.13 seconds.&lt;/p&gt;
&lt;h2&gt;Phase Three - Antigen to Antibody&lt;/h2&gt;
&lt;p&gt;Here's where things went wrong. As you could see from the screenshot, my second biggest load time item was Antigen itself. Antigen is known as a bit of a &lt;a href="https://github.com/zsh-users/antigen/issues/116"&gt;big beast&lt;/a&gt;. So I started to look for alternatives.
Antibody was advertised as a answer to Antigen's woeful performance. I spent around 2 hours diligently porting my config over to Antibody.
However, when I &lt;em&gt;eventually&lt;/em&gt; got it working and battled through the lackluster documentation, I found it was actually slower than Antigen! A bit annoying to say the least. I didn't write down the test results from then but they were somewhere in the region of 0.8 seconds.&lt;/p&gt;
&lt;h2&gt;Phrase Four - Remove Pyenv&lt;/h2&gt;
&lt;p&gt;The last phase I did for now was to remove pyenv and compinit. Loading of pyenv is something that had escaped my notice when originally pruning through my config. I barely do any python development nowadays so this got removed hastily.
I reran the tests and...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0.19 real 0.10 user 0.08 sys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, so it's not quite the 0.13 seconds I had hoped for, but not bad.&lt;/p&gt;
&lt;p&gt;By this stage, the main load times for opening new tabs was iTerm2 itself (my terminal application of choice). Going forward I am going to switch over to Linux and most likely use Kitty which is a blazing fast terminal program. This should null and void any performance gains I'd get by reducing it down by that 0.05 seconds.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This was a really good use of a few hours of time. It's going to make me happier and more productive at work, which in my mind, is time well spent. I still have plans to speed up ZSH (asides from Kitty) but they will have to wait (convert over to Zplugin and reduce plugins even more).
For now, I'll move onto other programs I use regularly like VSCode and Chrome for more performance gains there.&lt;/p&gt;
&lt;p&gt;I hope this post helps you speed up your ZSH - let me know the speeds you get on twitter - @joshghent&lt;/p&gt;
&lt;p&gt;Speaking of performance, I'm currently working on a side project called TurboAPI. It's a super simple tool designed to monitor your API and Webhook's performance without installing a thing. I'd love if you could check it out &lt;a href="https://turboapi.dev"&gt;here&lt;/a&gt;&lt;/p&gt;</description><author/><pubDate>Fri, 19 Jun 2020 15:31:03 GMT</pubDate><guid isPermaLink="true">/zsh-speed/</guid></item><item><title>Zoeken binnen WordPress: “Is it me you’re looking for?”</title><link>https://jaimemartinez.nl/blog/2020/06/19/wordcamp-nederland-live-zoeken-binnen-wordpress/</link><description>&lt;p&gt;Video-opname Hieronder de opgenomen live-sessie welke is opgenomen. Dank aan de WordCamp NL organisatie voor de uitnodiging en ik ben erorm blij dat ik op deze manier heb mogen bijdragen aan de WordPress community! Als je deze talk interresant vondt, dan heb ik nog enkele andere talks. Aankondiging Yes! Ik heb er zin in. donderdag [&amp;#8230;]&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https://jaimemartinez.nl/blog/2020/06/19/wordcamp-nederland-live-zoeken-binnen-wordpress/"&gt;Zoeken binnen WordPress: &amp;#8220;Is it me you&amp;#8217;re looking for?&amp;#8221;&lt;/a&gt; appeared first on &lt;a href="https://jaimemartinez.nl"&gt;Jaime Martinez&lt;/a&gt;.&lt;/p&gt;</description><author>Jaime Martinez</author><pubDate>Fri, 19 Jun 2020 14:56:22 GMT</pubDate><guid isPermaLink="true">https://jaimemartinez.nl/blog/2020/06/19/wordcamp-nederland-live-zoeken-binnen-wordpress/</guid></item><item><title>Link to https://mxb.dev/blog/the-return-of-the-90s-web/</title><link>https://qubyte.codes/links/1592562340506</link><description>&lt;p&gt;A nice discussion about how old techniques like server rendering are coming back into fashion, and personal websites and communities. &lt;a href="https://qubyte.codes/links/1592562340506"&gt;The Return of the 90s Web - Max Böck&lt;/a&gt;&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Fri, 19 Jun 2020 13:25:40 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/links/1592562340506</guid></item><item><title>Introducing Headspace</title><link>http://evantravers.com/articles/2020/06/19/hammerspoon-headspace/</link><description>&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/06/headspace_ui.png" /&gt;&lt;/p&gt;&lt;p&gt;I am &lt;em&gt;very&lt;/em&gt; excited about this post... I'm pretty sure that I've been working on it alongside the name-sake tool for a straight month.&lt;/p&gt;
&lt;p&gt;Headspace has been the title of this series, and it's what I call the last automation in this series. Let's jump straight into it with a demo.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls="controls" poster="https://images.evantravers.com/articles/2020/06/headspace_demo.png" src="https://images.evantravers.com/articles/2020/06/headspace_demo.mp4"&gt;&lt;/video&gt;
  &lt;figcaption&gt;If you want to share this video with someone, &lt;a href="https://www.youtube.com/watch?v=cvH3KC7eYUs"&gt;it's on youtube&lt;/a&gt;.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Here's what Headspace offers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fully configurable for you and your work-style.&lt;/li&gt;
&lt;li&gt;Define workspaces for your important work:
&lt;ul&gt;
&lt;li&gt;Launch relevant applications and quit distracting applications based on tags.&lt;/li&gt;
&lt;li&gt;Block distracting &lt;a href="/articles/2020/06/08/hammerspoon-a-better-better-hyper-key/"&gt;hyper.lua&lt;/a&gt; shortcuts to protect focus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Toggl.com tracking presets per space… or a custom input at any time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I've been using Headspace daily for about a month. I &lt;strong&gt;love&lt;/strong&gt; it. I am sure that you could create something very similar using a variety of automation tools. Build your own version or &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/40863179f918c1fa1379b4bc2dde588fb50ebc41/headspace.lua"&gt;clone mine&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#how-headspace-came-to-be" id="how-headspace-came-to-be"&gt;&lt;/a&gt;How Headspace Came to Be&lt;/h2&gt;
&lt;p&gt;After writing &lt;a href="/articles/2020/06/12/hammerspoon-handling-windows-and-layouts/#split-screen-easily"&gt;the &amp;quot;split window&amp;quot; function&lt;/a&gt;, I realized there were window layouts I preferred for specific tasks… starting with my daily review in Things 3, but also my daily standup.&lt;/p&gt;
&lt;p&gt;To have an idea of the complexity of one of these tasks: Every work weekday at 4:30p in order to perform my Daily Review…&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I close all distracting apps by running &amp;quot;quitall&amp;quot; in Alfred.&lt;/li&gt;
&lt;li&gt;I start a timer using Toggl.app, I choose &amp;quot;Planning&amp;quot; as the project and type in &amp;quot;Review&amp;quot; as the description.&lt;/li&gt;
&lt;li&gt;I launch Things and Drafts using hyper.lua hotkeys.&lt;/li&gt;
&lt;li&gt;I setup the first Things window:
&lt;ul&gt;
&lt;li&gt;Move to right 30% (&lt;code&gt;HYPER+M,T&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Hide its sidebar (&lt;code&gt;CMD+/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Go to Today (&lt;code&gt;CMD+F, tod, &amp;lt;return&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I open a second Things window (&lt;code&gt;CMD+OPT+N&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;I setup the work Things window:
&lt;ul&gt;
&lt;li&gt;Move to left 70% (&lt;code&gt;HYPER+M,R&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Show its sidebar (&lt;code&gt;CMD+/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Go to Anytime (&lt;code&gt;CMD+F, any, &amp;lt;return&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I then follow the checklist in the right window to do the work in the left window.&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
  &lt;img alt="screenshot of a sample daily review" src="https://images.evantravers.com/articles/2020/06/daily_review.png" /&gt;
  &lt;figcaption&gt;
    &lt;p&gt;This is how I like to conduct my daily review... I have the To-do with a checklist for the ritual itself on the right, and I work in the pane to the left as I work through the checklist.&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;That's a lot of steps! &lt;em&gt;Every day!&lt;/em&gt; 😰&lt;/p&gt;
&lt;p&gt;In early May, I &lt;a href="https://github.com/evantravers/hammerspoon-config/commit/5119ec73a67a1e6527adac0240a534c050a290c6"&gt;started to write a simple &amp;quot;layout chooser&amp;quot;&lt;/a&gt;. I started with a &lt;code&gt;hs.chooser&lt;/code&gt;, and just had it wired to functions that moved around windows and set up the windows in my workspace the way I wanted it. I realized that since I'm writing a function for a specific task, then I &lt;em&gt;know&lt;/em&gt; the time tracking data for that task. I could automate my time tracking as well! I wrote the first curl-based version of my &lt;a href="/articles/2020/06/13/hammerspoon-toggl-api-calls-and-secret-tokens/"&gt;toggl.lua&lt;/a&gt; script and threw a &lt;code&gt;toggl.start()&lt;/code&gt; call in the setup function.&lt;/p&gt;
&lt;p&gt;Within a couple minutes or hacking, I had a button than when pressed could rearrange my computer into one of two &amp;quot;scenes,&amp;quot; which immediately set up my workspace and &lt;em&gt;started the correct toggl timer&lt;/em&gt;. I pressed one key, chose my task, and &lt;strong&gt;started to work&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="game changer gif" src="https://i.giphy.com/media/tBb19eTTI6Kgj44KtmE/giphy.webp" /&gt;&lt;/p&gt;
&lt;p&gt;I realized that choosing a space was a statement of intentionality. Headspace had become a tool that cleared the space for me to focus on my intent, and automatically removed obstacles.&lt;/p&gt;
&lt;p&gt;I had been really interested in the idea or having different spaces for productivity, since I had seen &lt;a href="https://www.youtube.com/watch?v=snAhsXyO3Ck"&gt;Spaceship You&lt;/a&gt; and heard CGP Grey's additional commentary on the topic in &lt;a href="https://www.relay.fm/cortex/102"&gt;Cortex Ep. 102&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As &lt;a href="/articles/2020/06/13/hammerspoon-toggl-api-calls-and-secret-tokens/"&gt;I already was copying Grey's use of toggl&lt;/a&gt; to track my whole work day, I realized I could build a tool of spatial intentionality. Removing distraction, staying focused, and tracking how much time I spend moving the needle.&lt;/p&gt;
&lt;p&gt;I started adding entries for time tracking every major modality of work that I do daily, even if it didn't require a special window layout. I already had been using projects in Toggl for this, so &lt;a href="https://github.com/evantravers/hammerspoon-config/commit/44b57b34ddfe074adbe65a32f98e3492dbc796c9"&gt;I just copied them into Headspace&lt;/a&gt;. I used it for a week with just the major modalities I had created, occasionally flipping over to the standard toggl.app to enter a custom description for a timer.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#blocking-hyper-distractions" id="blocking-hyper-distractions"&gt;&lt;/a&gt;Blocking Hyper Distractions&lt;/h3&gt;
&lt;figure&gt;
  &lt;img alt="Notification informing user that Slack has been blocked" src="https://images.evantravers.com/articles/2020/06/blocked.png" /&gt;
&lt;/figure&gt;
&lt;p&gt;The ability to open any application with a single keypress is awesomely… distracting.&lt;/p&gt;
&lt;p&gt;I wrote a modification to hyper.lua that blocked applications had had declared should &lt;code&gt;never&lt;/code&gt; be in this space. You can still manually go launch them, but that little nudge helps me stay on task and not open Slack just to tell a friend a cool thing I did in Hammerspoon. 😛&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;allowed&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;blocking_enabled&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;if&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;return&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fnutils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;some&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;only&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;return&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fnutils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;contains&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;if&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;never&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;return&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fnutils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;every&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;never&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;            &lt;span&gt;return&lt;/span&gt; &lt;span&gt;not&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fnutils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;contains&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;tags&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;tag&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;return&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launch&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;allowed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launchOrFocusByBundleID&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;bundleID&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;notify&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Blocked &amp;quot;&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;bundleID&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;You have to switch headspaces&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/hyper.lua#L33-L58"&gt;hyper.lua&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#view-current-timer" id="view-current-timer"&gt;&lt;/a&gt;View Current Timer&lt;/h3&gt;
&lt;figure&gt;
  &lt;img alt="showing the current timer" src="https://images.evantravers.com/articles/2020/06/showing_timer.png" /&gt;
&lt;/figure&gt;
&lt;p&gt;I overloaded the placeholder text for the &lt;code&gt;hs.chooser&lt;/code&gt; so that if there's a currently running timer, I can see what my current intention. This often keeps me on track. Because the &amp;quot;allowed applications&amp;quot; is tied to a space, if I want to freely use Slack or Email, I have to look at my intention in the timer first before I change the headspace. I have found myself starting to stay the course and finish the work. 👌&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;showCallback&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;local&lt;/span&gt; &lt;span&gt;current&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;toggl&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;current_timer&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;current&lt;/span&gt; &lt;span&gt;and&lt;/span&gt; &lt;span&gt;current&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;data&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;timer&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;current&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;str&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;🔴 :&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;timer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;description&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;str&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;str&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;&amp;quot; &amp;quot;&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;timer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;description&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;timer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;local&lt;/span&gt; &lt;span&gt;project&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;toggl&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get_project&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;timer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;pid&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;if&lt;/span&gt; &lt;span&gt;project&lt;/span&gt; &lt;span&gt;and&lt;/span&gt; &lt;span&gt;project&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;data&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;str&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;str&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;&amp;quot; (&amp;quot;&lt;/span&gt;  &lt;span&gt;..&lt;/span&gt; &lt;span&gt;project&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;name&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;&amp;quot;)&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;duration&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;math&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;floor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;timer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secondsSinceEpoch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;+&lt;/span&gt; &lt;span&gt;current&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;duration&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;/&lt;/span&gt; &lt;span&gt;60&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;&amp;quot;m&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;chooser&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;placeholderText&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;str&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;&amp;quot; :: &amp;quot;&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;duration&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/headspace.lua#L107-L124"&gt;headspace.lua&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#custom-timers" id="custom-timers"&gt;&lt;/a&gt;Custom Timers&lt;/h3&gt;
&lt;figure&gt;
  &lt;img alt="showing the custom timer" src="https://images.evantravers.com/articles/2020/06/custom_timer.png" /&gt;
&lt;/figure&gt;
&lt;p&gt;I also rewrote the &lt;code&gt;hs.chooser&lt;/code&gt; callback so that anything you type can be started as a toggl timer. I can now use just Headspace for all time tracking, only running toggl.app for the Timeline feature.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;queryChangedCallback&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;searchQuery&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;local&lt;/span&gt; &lt;span&gt;query&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;string&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lower&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;searchQuery&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;local&lt;/span&gt; &lt;span&gt;results&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;fn&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;spaces&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;space&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;text&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;string&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lower&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;space&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local&lt;/span&gt; &lt;span&gt;subText&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;string&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lower&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;space&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;subText&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;(&lt;/span&gt;&lt;span&gt;string&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;query&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;or&lt;/span&gt; &lt;span&gt;string&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;match&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;subText&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;query&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;results&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;chooser&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;results&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/headspace.lua#L90-L106"&gt;headspace.lua&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Not bouncing back and forth between headspaces.lua for presets and Toggl.app for custom means that my time-tracking has become more consistent and painless.&lt;/p&gt;
&lt;p&gt;It was &lt;em&gt;really&lt;/em&gt; fun to write this. I was working on this while using it… so I was UX lead, developer, and customer all in one. My passion is making tools, and this one has been very satisfying to create.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#daily-usage" id="daily-usage"&gt;&lt;/a&gt;Daily Usage&lt;/h2&gt;
&lt;p&gt;So what is it like to actually use?&lt;/p&gt;
&lt;p&gt;Full disclosure... this is largely solving a problem of my &lt;em&gt;own&lt;/em&gt; making. Automations like the Hyper key, combined with a decade of not valuing the practice of sustained intentionality&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;2&lt;/a&gt;&lt;/sup&gt; means that it's easy for my monkey brain to run away and be distracted.&lt;/p&gt;
&lt;p&gt;That being said, I do not think I'm alone in this. Several thinkers in the space (Shawn Blanc&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-4" id="fnref-4"&gt;3&lt;/a&gt;&lt;/sup&gt;, Mike Hurley and CGP Grey, David Sparks and Mike Schmidt, Rosemary Orchard, etc.) have all talked about how they love using their iPad as a tool of focus, because iPad OS is a &amp;quot;single-tasking&amp;quot; OS. In some ways, I'm attempting to emulate that on a multi-tasking Macbook Pro, but on my terms. I can turn it on and off.&lt;/p&gt;
&lt;p&gt;Blocking my custom hyper-key shortcuts was &lt;em&gt;incredibly&lt;/em&gt; frustrating for the first week or so. I occasionally got physically angry at my computer. &amp;quot;Why won't you do what I tell you!!!! oh. yeah. I said I was focusing.&amp;quot;&lt;/p&gt;
&lt;p&gt;I have found that this effort is slowly re-wiring my brain into putting those distracting urgent messages and &amp;quot;just-checks&amp;quot;&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-3" id="fnref-3"&gt;4&lt;/a&gt;&lt;/sup&gt; into Things.app tasks and Drafts.app. I may even attempt to automate this, where if I try to access an app that is blocked, just open a Drafts.app draft with some context about the time, context, and the app I had just tried to access.&lt;/p&gt;
&lt;p&gt;My time-tracking is &lt;em&gt;much&lt;/em&gt; more consistent, and honest. At the moment, I don't have a &amp;quot;stop&amp;quot; timer setup until the &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/spaces/shutdown.lua"&gt;shutdown routine&lt;/a&gt; space that I run at the end of my day. That means I'm always running a timer. My fallback timer is &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/spaces/communicate.lua"&gt;Communication&lt;/a&gt;. It's accurate enough for now: I enter a &amp;quot;focused space&amp;quot; like &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/spaces/write.lua"&gt;Writing&lt;/a&gt; or &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/spaces/research.lua"&gt;Research&lt;/a&gt; and distractions and communication applications are blocked. When I'm done, I leave the focused space (stopping that timer) and I'm in Communication which everything is allowed, and I'm checking in with my team... it's pretty accurate to what I do now.&lt;/p&gt;
&lt;p&gt;I think in the future I'd like to be &lt;em&gt;more&lt;/em&gt; intentional, spend more time in focus-type blocks and less time in communication/distraction. But I have the flexibility to redesign headspace to nudge me in the right direction.&lt;/p&gt;
&lt;p&gt;Here's a simple &amp;quot;space&amp;quot; definition in &amp;quot;deep.lua&amp;quot; that I show in the demo video.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;table&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;insert&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;spaces&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;text&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Deep&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;subText&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Work deeply on focused work (Deep)&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;image&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;imageFromAppBundle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'com.culturedcode.ThingsMac'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;toggl_proj&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;projects&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;deep&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;never&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'#distraction'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;setup&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'deep'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;setup&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;deep&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;urlevent&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;openURL&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;things:///show?id=anytime&amp;amp;filter=@ProctorU,$High&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a given space, I build a table for the &lt;code&gt;hs.chooser&lt;/code&gt;, passing in information for toggl.com, and tags that I want to block/enable.&lt;/p&gt;
&lt;p&gt;If I want to enable more complex actions, I can define a &amp;quot;setup&amp;quot; function. I can do pretty much &lt;em&gt;anything&lt;/em&gt; in there.&lt;/p&gt;
&lt;p&gt;This tool has me re-thinking my computer usage. Pretty much anytime I find myself doing the same thing over and over I stop and encode it into my system. I keep hiding the UI of Drafts.app for minimalistic writing? &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/spaces/write.lua#L13-L18"&gt;Encode that into Write&lt;/a&gt;. Always open the same windows in the same places each time I run standup? &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/963bf217e6b56c8a74a4ed56ace428eade2f9bd4/spaces/standup.lua#L13-L19"&gt;Encode that into Standup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It may not save me &lt;em&gt;all&lt;/em&gt; that much time, but I have to imagine that every small piece of friction removed is hopefully making the way for useful work. It certainly gives me joy... every time I punch in my standup and it sets itself up for me so that all I do is hit &amp;quot;Join Call?&amp;quot; I grin like a fool &lt;em&gt;every&lt;/em&gt; time.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#where-is-this-headed" id="where-is-this-headed"&gt;&lt;/a&gt;Where is this headed?&lt;/h2&gt;
&lt;p&gt;Well, I can't stop tinkering. It's been changing as I write this blog post. 🤷&lt;/p&gt;
&lt;p&gt;I am still tweaking my toggl project to headspace relationship as I begin to understand my own work and behavior, I am trying to track and encourage spending my time in meaningful ways.&lt;/p&gt;
&lt;p&gt;I'll probably attempt to write a tool to set automatic timers/limits on how much time I spend in certain spaces. I spent &lt;em&gt;way&lt;/em&gt; too much time just in Communication mode, and I like the idea of having measured work blocks where I can trust my system to give me breaks at intervals.&lt;/p&gt;
&lt;p&gt;I think this series is basically done, but it has led me down some neat automation rabbit holes that I'll probably feature in standalone posts. For now, you can peek into my &lt;a href="https://github.com/evantravers/hammerspoon-config/tree/40863179f918c1fa1379b4bc2dde588fb50ebc41/spaces"&gt;spaces folder&lt;/a&gt; and see how I'm classifying my work. Maybe you'll get some ideas for your own automations.&lt;/p&gt;
&lt;p&gt;I don't &lt;em&gt;really&lt;/em&gt; expect anyone else to try this... but if you do: please &lt;a href="/contact"&gt;shoot me an email&lt;/a&gt; or &lt;a href="https://github.com/evantravers/hammerspoon-config/issues"&gt;create a github issue&lt;/a&gt;. If there's enough interest, I'll submodule out headspace to be it's own Spoon or something.&lt;/p&gt;
&lt;p&gt;If you really want to try Headspace and doesn't want to code up some lua, I'll either help you, or try to hack together a control panel using &lt;a href="https://www.hammerspoon.org/docs/hs.dialog.html"&gt;&lt;code&gt;hs.dialog&lt;/code&gt;&lt;/a&gt; so that it is self-configurable with a UI.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;I guess this is a bit of meta for my own process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In order to do information work:
&lt;ul&gt;
&lt;li&gt;Check the calendar. What was my original plan for this time?&lt;/li&gt;
&lt;li&gt;Select task.&lt;/li&gt;
&lt;li&gt;Start a timer, stating intention for this time and recording metrics.&lt;/li&gt;
&lt;li&gt;Close anything unrelated to preserve my focus.
&lt;ul&gt;
&lt;li&gt;Apps I usually don't care about.&lt;/li&gt;
&lt;li&gt;Browser tabs go into Instapaper.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Open any applications or windows required by the work.&lt;/li&gt;
&lt;li&gt;EITHER:
&lt;ul&gt;
&lt;li&gt;set up a single work window full screen (usually)&lt;/li&gt;
&lt;li&gt;set up a consistent layout of windows for the task (occasionally)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Work for the allotted time block.&lt;/li&gt;
&lt;li&gt;Attempt to resist urgent, immediate distractions to accomplish my task.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;This is my current favorite definition of Focus, taken from &lt;a href="https://twitter.com/bobbleheadjoe"&gt;Mike Schmidtz&lt;/a&gt; on &lt;a href="https://www.relay.fm/focused/100"&gt;Focused Episode 100&lt;/a&gt;. &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-4"&gt;
&lt;blockquote&gt;
&lt;p&gt;As for the type of work that my iPad is superior? Writing. iOS is, by nature, a distraction-free work environment. I love that I have to move a little bit slower within iOS, and that apps are almost always in full screen mode. This is a feature to me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(&lt;a href="https://thesweetsetup.com/first-impressions-of-the-new-12-9-ipad-pro-for-writing-and-photography/"&gt;First Impressions of the New 12.9″ iPad Pro for Writing and Photography&lt;/a&gt;) &lt;a class="footnote-backref" href="#fnref-4"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-3"&gt;
&lt;p&gt;&lt;a href="https://shawnblanc.net/2014/11/alternatives-to-the-just-checks/"&gt;Alternatives to the Just Checks - shawnblanc.net&lt;/a&gt; &lt;a class="footnote-backref" href="#fnref-3"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Fri, 19 Jun 2020 12:00:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/06/19/hammerspoon-headspace/</guid></item><item><title>Reach servers behind NAT with WireGuard and a VPS, while preserving source IP</title><link>https://allanrbo.blogspot.com/2020/06/reach-servers-behind-nat-with-wireguard.html</link><description>&lt;p&gt;This post describes an approach to let your Linux machine behind a NAT be reachable from the public internet, using a cheap VPS and Wireguard.&lt;/p&gt;

&lt;p&gt;It's similar to &lt;a href="https://golb.hplar.ch/2019/01/expose-server-vpn.html"&gt;this post in Ralph's Blog&lt;/a&gt;, but with with one distinction: it preserves the source IP of the incoming connection. This may be important depending on your use. For me, I was running a PHP web app for which I needed the $_SERVER["REMOTE_ADDR"] field to be the true and correct IP of the client, and not just the IP of the gateway that forwarded the traffic.&lt;/p&gt;

&lt;p&gt;Values used in this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;192.168.51.0/24 is the private VPN network between the cloud VPS host and the server you want to expose.&lt;/li&gt;
&lt;li&gt;192.168.51.1 is the VPN network IP of the cloud VPS.&lt;/li&gt;
&lt;li&gt;192.168.51.2 is the VPN network IP of the server you want to expose.&lt;/li&gt;
&lt;li&gt;50.40.30.20 is the public IP of the cloud VPS.&lt;/li&gt;
&lt;li&gt;59014 the UDP port number I randomly chose for WireGuard on the VPS.&lt;/li&gt;
&lt;li&gt;80 and 443 are the TCP port numbers I want to forward from my VPS to my local server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the cloud VPS:&lt;/p&gt;
&lt;pre class="code"&gt;
mkdir -p /etc/wireguard
cd /etc/wireguard
wg genkey | tee privatekey | wg pubkey &amp;gt; publickey
chown 600 privatekey
cat privatekey
cat publickey

# Replace the PrivateKey in the [Interface] section with the actual privatekey value generated above.
# Replace the PublicKey in the [Peer] section with the publickey value you generate ON YOUR LOCAL SERVER in the later steps.
cat &amp;gt; /etc/wireguard/wg0.conf &amp;lt;&amp;lt;EOF
[Interface]
Address = 192.168.51.1
PrivateKey = KF+X0SO2lkBFnxTCK4R5PCv/FC6+wgH6rt6wWHkVVHE=
ListenPort = 59014

[Peer]
PublicKey = y700qaTgjDjMrLc9tGF7+PKFrX7uHyIJJ/s2zvadKVY=
AllowedIPs = 192.168.51.2/32
EOF

chmod 600 wg0.conf

# Start the VPN server
wg-quick up wg0

echo 0 &amp;gt; /proc/sys/net/ipv4/ip_forward
iptables -P FORWARD DROP
iptables -A FORWARD -i eth0 -o wg0  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i wg0  -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i wg0  -o eth0 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -i eth0 -o wg0  -p tcp --syn --dport 80  -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -i eth0 -o wg0  -p tcp --syn --dport 443 -m conntrack --ctstate NEW -j ACCEPT
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80  -j DNAT --to-destination 192.168.51.2
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 192.168.51.2
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward
&lt;/pre&gt;

&lt;p&gt;On your local server, instead of using wg-quick, we will set up the interface a bit more manually. This is in order to have finer control over routing. We want connections originating on this server to exit via this server's normal internet connection, and not via the WireGuard VPN connection. However, packets part of TCP connections that got forwarded to us on the VPN from the VPS should be routed back via the VPS.&lt;/p&gt;

&lt;p&gt;On your local server:&lt;/p&gt;
&lt;pre class="code"&gt;
mkdir -p /etc/wireguard
cd /etc/wireguard
wg genkey | tee privatekey | wg pubkey &amp;gt; publickey
chown 600 privatekey
cat privatekey
cat publickey

# Replace the PrivateKey in the [Interface] section with the actual privatekey value generated above.
# Replace the PublicKey in the [Peer] section with the publickey value you generated ON YOUR CLOUD VPS in the earlier steps.
cat &amp;gt; /etc/wireguard/wg0.conf &amp;lt;&amp;lt;EOF
[Interface]
PrivateKey = YIOy80YJdcMqI1WCMROoyUfsfkc6GhP0KqRS3BfcoEs=

[Peer]
PublicKey = i1VQnnODEBbf+P9cyd9XmB9G58qEpM53TbMXn1UAJx8=
Endpoint = 50.40.30.20:59014
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

chmod 600 wg0.conf

# Set up VPN connection
ip link add wg0 type wireguard
wg setconf wg0 /etc/wireguard/wg0.conf
ip address add 192.168.51.2 dev wg0
ip link set mtu 1420 up dev wg0
ip rule add from 192.168.51.2 table 51820
ip rule add iif wg0 table 51820
ip route add 192.168.51.0/24 dev wg0
ip route add 0.0.0.0/0 via 192.168.51.1 dev wg0 table 51820

# Shut down VPN connection (don't run these steps now, but keep them handy)
ip rule delete from 192.168.51.2 table 51820
ip rule delete iif wg0 table 51820
ip link delete dev wg0
&lt;/pre&gt;

&lt;p&gt;You should now be able to receive TCP traffic on port 80 and 443 on your local server, and the src IP address of the actual real client will be preserved all the way to your local server.&lt;/p&gt;</description><author>Allan's Blog</author><pubDate>Fri, 19 Jun 2020 08:57:21 GMT</pubDate><guid isPermaLink="true">https://allanrbo.blogspot.com/2020/06/reach-servers-behind-nat-with-wireguard.html</guid></item><item><title>WireGuard kernel module for Alpine Linux on diskless Raspberry Pi</title><link>https://allanrbo.blogspot.com/2020/06/wireguard-kernel-module-for-alpine.html</link><description>As of writing (Alpine Linux v3.12), the WireGuard kernel module is not part of the Alpine Linux Raspberry Pi kernel by default. There's a community module called wireguard-rpi2, but it doesn't work in a system set up in diskless mode. The reason it doesn't work, is because in diskless mode on a Raspberry Pi, Alpine Linux uses a read-only loopback file system to store its kernel modules. This filesystem is mounted on /.modloop .&lt;br /&gt;
&lt;br /&gt;
The workaround I came up with, is to use an overlay file system to make the kernel modules directory writable.&lt;br /&gt;
&lt;br /&gt;
Here's the workaround:&lt;br /&gt;
&lt;pre name="code"&gt;
# Remount the kernel module directory /.modloop as an overlay, to allow writing
modprobe overlay
mkdir -p /.modloop.lower /.modloop.upper /.modloop.workdir
mount /dev/loop0 /.modloop.lower
umount /.modloop/
mount -t overlay -o lowerdir=/.modloop.lower,upperdir=/.modloop.upper,workdir=/.modloop.workdir none /.modloop
lbu include /.modloop.upper
lbu commit -d

# Manually get the Wireguard kernel module to avoid installing the wireguard-rpi2 which does not work with diskless systems
cd /tmp
pkgname=$(apk list | grep wireguard-rpi2 | cut -d &amp;quot; &amp;quot; -f 1)
wget http://dl-cdn.alpinelinux.org/alpine/v3.12/community/armhf/$pkgname.apk
mkdir /tmp/$pkgname
tar -xzf $pkgname.apk -C /tmp/$pkgname
mkdir -p /lib/modules/$(uname -r)/extra/
cp /tmp/$pkgname/lib/modules/$(uname -r)/extra/wireguard.ko /lib/modules/$(uname -r)/extra/
rm -fr /tmp/$pkgname /tmp/$pkgname.apk
depmod

# Create an init script to remount the /.modloop overlay on next boot
cat &amp;gt; /etc/init.d/modloopoverlay &amp;lt;&amp;lt;EOF
#!/sbin/openrc-run

depend() {
    before networking
    need modules
}

start() {
    ebegin &amp;quot;Starting modloop overlay&amp;quot;
    modprobe overlay
    mkdir -p /.modloop.lower /.modloop.upper /.modloop.workdir
    if [ ! -d /.modloop.lower/modules ]; then
        mount /dev/loop0 /.modloop.lower
    fi
    umount /.modloop
    mount -t overlay -o lowerdir=/.modloop.lower,upperdir=/.modloop.upper,workdir=/.modloop.workdir none /.modloop
    eend 0
}
EOF
chmod +x /etc/init.d/modloopoverlay
/etc/init.d/modloopoverlay restart
rc-update add modloopoverlay boot
lbu include /etc/init.d/modloopoverlay

apk add wireguard-tools

# Create an init script to start wg0
cat &amp;gt; /etc/init.d/wg0 &amp;lt;&amp;lt;EOF
#!/sbin/openrc-run

depend() {
    need networking ntpd modloopoverlay
}

start() {
    ebegin &amp;quot;Starting Wireguard tunnel wg0&amp;quot;
    ntpd -n -q -p pool.ntp.org
    date
    wg-quick up wg0
    eend $?
}

stop() {
    ebegin &amp;quot;Stopping Wireguard tunnel wg0&amp;quot;
    wg-quick down wg0
    eend 0
}
EOF
chmod +x /etc/init.d/wg0
/etc/init.d/wg0 restart
rc-update add wg0 default
lbu include /etc/init.d/wg0

lbu commit -d

# inspect the overlay file
tar -tvf /media/mmcblk0p1/localhost.apkovl.tar.gz
&lt;/pre&gt;</description><author>Allan's Blog</author><pubDate>Fri, 19 Jun 2020 07:20:29 GMT</pubDate><guid isPermaLink="true">https://allanrbo.blogspot.com/2020/06/wireguard-kernel-module-for-alpine.html</guid></item><item><title>Using Vimwiki like a standard desktop application</title><link>https://gist.github.com/74bedf5de1b3ace84d02bb634128193e</link><description>When taking notes I prefer to launch a note-taking application, write a line, or two, then close the application. Having used Vimwiki for a couple of days, I had to create a desktop entry wrapper around it, just to avoid the "Open Terminal first", step.</description><author>personal code attic</author><pubDate>Fri, 19 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://gist.github.com/74bedf5de1b3ace84d02bb634128193e</guid></item><item><title>The old Web was fun</title><link>https://jasoneckert.github.io/myblog/the-old-web-was-fun/</link><description>&lt;p&gt;I was around during the birth of the web in the early 1990s and have enjoyed every twist and turn since then. Even before creating my own personal website and blog (this site) in 1998, I maintained the Department of Science website at UW (originally &lt;a href="http://sciborg.uwaterloo.ca"&gt;http://sciborg.uwaterloo.ca&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;And while I’ve enjoyed watching the evolution of the web, I still think the old web was more fun. In this blog post, I’ll tell you why. But first, let’s cover some background info!&lt;/p&gt;</description><author>Jason Eckert's Website and Blog</author><pubDate>Fri, 19 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://jasoneckert.github.io/myblog/the-old-web-was-fun/</guid></item><item><title>Head Up, Head Down</title><link>https://martinrue.com/head-up-head-down/</link><description>There are few things more enjoyable to me than the mental solitude that hand-delivers interesting shower thoughts, or that let's me sit in a bustling coffee shop contemplating life.</description><author>Martin Rue</author><pubDate>Fri, 19 Jun 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://martinrue.com/head-up-head-down/</guid></item><item><title>#HeyForGood</title><link>https://www.swyx.io/hey-for-good</link><description>Recounting my process of how I started with 2 HEY email invites and ended up raising $2575 in Donations to Support Diversity in Tech!</description><author>swyx's site RSS Feed</author><pubDate>Fri, 19 Jun 2020 00:37:56 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/hey-for-good</guid></item><item><title>Italian Administration collapsing soon, without reforms and people</title><link>https://stop.zona-m.net/2020/06/italian-administration-collapsing-soon-without-reforms-and-people/</link><description>&lt;p&gt;In THAT order, please.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 18 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/italian-administration-collapsing-soon-without-reforms-and-people/</guid></item><item><title>The Making of Mosquito.JS</title><link>https://tholman.com/post/mosquito-js-talk/</link><description>A 10 minute talk about the making of a murderer mosquito.</description><author>The Curious Creations of Tim Holman</author><pubDate>Thu, 18 Jun 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://tholman.com/post/mosquito-js-talk/</guid></item><item><title>Mercury’s Odyssey by The Olympians</title><link>https://nutcroft.mataroa.blog/blog/mercurys-odyssey-by-the-olympians/</link><description>&lt;p&gt;&lt;em&gt;Mercury’s Odyssey&lt;/em&gt; is an instrumental song by &lt;a href="https://theolympians.bandcamp.com/"&gt;The Olympians&lt;/a&gt;. The following commentary is an attempt to make a depiction of its brilliance in English words.&lt;/p&gt;
&lt;p&gt;Recommended way of enjoyment: listen to the music while maintaining a connection to the assigned second of each commentary bit.&lt;/p&gt;
&amp;lt;a href="http://theolympians.bandcamp.com/album/the-olympians"&amp;gt;The Olympians by The Olympians&amp;lt;/a&amp;gt;

&lt;p&gt;0:00&lt;br /&gt;
Starting with a piano and drums combinational dribble while we rapidly ascend into—&lt;/p&gt;
&lt;p&gt;0:02&lt;br /&gt;
A slightly stripped-down quadruple symphony of equal power. The main actors: piano, drums, bass, and—&lt;/p&gt;
&lt;p&gt;0:21&lt;br /&gt;
Welcome, wind instrument. Our previous three-body fellowship continues as if nothing has happened and the whole quartet gives off a feeling of stableness.&lt;/p&gt;
&lt;p&gt;0:40&lt;br /&gt;
Slight sorrow, in four identical stages, gets the upper hand.&lt;/p&gt;
&lt;p&gt;1:01&lt;br /&gt;
Explosion preparation and…&lt;/p&gt;
&lt;p&gt;1:07&lt;br /&gt;
What a blast. The windy protagonist explodes full of bliss and energy. Everything spins around supporting the brass majesty whilst the piano is stealing the performance only by a small bit—an omen of things to come.&lt;/p&gt;
&lt;p&gt;1:26&lt;br /&gt;
Returning into stableness. Heed for the bass's contribution.&lt;/p&gt;
&lt;p&gt;1:45&lt;br /&gt;
With the familiar four-part descent into sadness.&lt;/p&gt;
&lt;p&gt;2:06&lt;br /&gt;
Explosion preparation, but this time—&lt;/p&gt;
&lt;p&gt;2:11&lt;br /&gt;
Anticlimactic. Lack of tension release.&lt;/p&gt;
&lt;p&gt;2:18&lt;br /&gt;
A wobble; latent climax incoming.&lt;/p&gt;
&lt;p&gt;2:21&lt;br /&gt;
Coolness. As if everything is where it’s supposed to be. Universal balance while the keybordial protagonist realises a creative race with no competition.&lt;/p&gt;
&lt;p&gt;2:40&lt;br /&gt;
Brass cry. Fully supported, the piano explores new worlds, unbeknownst to us. Full-blown party around fresh melodies.&lt;/p&gt;
&lt;p&gt;2:45&lt;br /&gt;
Don’t be distracted by the brass voices because you might miss the piano’s sustained majesty.&lt;/p&gt;
&lt;p&gt;2:50&lt;br /&gt;
Shout on the clock.&lt;/p&gt;
&lt;p&gt;2:55&lt;br /&gt;
Final shout just before—&lt;/p&gt;
&lt;p&gt;2:58&lt;br /&gt;
Explosion. Proper this time, as the pianistic transcendentality continues uninterrupted. Pure, infectious celebration.&lt;/p&gt;
&lt;p&gt;3:17&lt;br /&gt;
Back to stableness, this time the final one…&lt;/p&gt;
&lt;p&gt;3:22&lt;br /&gt;
Fading out fast…&lt;/p&gt;
&lt;p&gt;3:30&lt;br /&gt;
…and death!&lt;/p&gt;</description><author>nutcroft</author><pubDate>Thu, 18 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/mercurys-odyssey-by-the-olympians/</guid></item><item><title>Generative art piece: bubbles</title><link>https://qubyte.codes/blog/generative-art-piece-bubbles</link><description>&lt;p&gt;An experiment into generating SVG circles which don't overlap. It was timeboxed to an hour,
so it's a little rough around the edges (but I think that adds to its charm).&lt;/p&gt;</description><author>Qubyte Codes</author><pubDate>Thu, 18 Jun 2020 01:00:00 GMT</pubDate><guid isPermaLink="true">https://qubyte.codes/blog/generative-art-piece-bubbles</guid></item><item><title>The Value of College May Be Negative for the COVID Generation</title><link>https://whoisnnamdi.com/the-value-of-college/</link><description>You might think the value of a college degree has been increasing. You would be wrong.</description><author>Who is Nnamdi?</author><pubDate>Wed, 17 Jun 2020 20:26:43 GMT</pubDate><guid isPermaLink="true">https://whoisnnamdi.com/the-value-of-college/</guid></item><item><title>The 2020 USA elections are safe</title><link>https://stop.zona-m.net/2020/06/the-2020-usa-elections-are-safe/</link><description>&lt;p&gt;Seriously. We can relax now.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 17 Jun 2020 16:50:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/the-2020-usa-elections-are-safe/</guid></item><item><title>The cost of shooting film in 2020 in Canada</title><link>https://honza.pokorny.ca/2020/06/the-cost-of-shooting-film-in-2020-in-canada/</link><description>&lt;figure&gt;&lt;img src="https://honza.pokorny.ca/images/ilfordhp5.jpg" /&gt;
&lt;/figure&gt;

&lt;p&gt;At this point, there is no denying that film photography is enjoying a
widespread revival.&lt;/p&gt;
&lt;p&gt;What I want to do in this article is to go through the costs associated with
shooting film in 2020, and specifically in Canada.  There are many YouTube
videos and articles about film photography in Germany or in the United States
but not much is said about Canada.  If you live in Canada, you know that prices
of goods can sometimes be significantly higher than in the US, and so this
should give you an idea of what you are getting yourself into.&lt;/p&gt;
&lt;p&gt;We will consider black and white photography only.  This is the cheaper option.
We will not discuss the cost of the camera used to capture these images.&lt;/p&gt;
&lt;p&gt;We will talk about two types of film:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;35mm&lt;/li&gt;
&lt;li&gt;120 (6x6 or 12 exposures)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We will compare using a lab to develop your negatives versus doing it yourself.&lt;/p&gt;
&lt;p&gt;We will have two types of photographers in mind: the documentary photographer,
and the obsessed photographer.&lt;/p&gt;
&lt;p&gt;The documentary photographer photographs their family, special occassions, and
vacations.  This photographer shoots one roll of film per month on average. (12
rolls per year, i.e. 432 frames of 35mm, or 144 frames of 120 film)&lt;/p&gt;
&lt;p&gt;The obsessed photographer loves photography.  They shoot almost every day.
Their bookshelf is full of photo books done by the masters.  They have binders
full of negatives.  This photographer shoots three rolls of film per month on
average. (36 rolls per year, i.e. 1296 frames of 35mm, or 432 frames of 120
film)&lt;/p&gt;
&lt;p&gt;The film of choice is going to be &lt;a href="https://www.ilfordphoto.com/hp5-plus-35mm"&gt;Ilford HP5 Plus 400&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All of the costs in this article exclude sales tax.&lt;/p&gt;
&lt;h2 id="sourcing-film"&gt;Sourcing film&lt;/h2&gt;
&lt;p&gt;When I first started looking into this, I assumed the cheapest option would be
some a Chinese seller on eBay.  It turns out that Ilford actually has a
&lt;a href="https://www.ilfordphoto.ca/"&gt;dedicated distributor in Canada&lt;/a&gt;, and their products are readily available at
Canada-friendly prices.&lt;/p&gt;
&lt;p&gt;35mm film:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;36 exposures, $8.67&lt;/li&gt;
&lt;li&gt;24 exposures, $7.32&lt;/li&gt;
&lt;li&gt;100ft of bulk, $110.51&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;120 film:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$7.67&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One hundred feet of bulk film is equivalent to 18 rolls of 36 exposures.  This
is roughly $6.14 per roll, a saving of about 30%.  You will have to purchase a
bulk loader, and some reusable canisters; this is about $100 in total.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Documentary photographer&lt;/strong&gt;: there are two options, a) buy 12 36-exposure rolls
each year, or b) 2 100ft rolls of bulk film over 3 years.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a) 8.67 * 12 * 3 = $312.10 (or $104.03 per year; $0.24 per frame)&lt;/li&gt;
&lt;li&gt;b) 110.51 * 2 = $221.02 (or $73.67 per year; $0.17 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If they decide to go with option b), they will also need to purchase bulk
loading equipment, but as you can see, the break-even point is very close to the
3-year mark.&lt;/p&gt;
&lt;p&gt;If they shoot 120 film: $92.04 per year or $0.64 per frame.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Obsessed photographer&lt;/strong&gt;: bulk loading is certainly the way to go here.  They
will save about $200 every year by loading their own film.  Film cost per year:
$221.02.&lt;/p&gt;
&lt;p&gt;If they shoot 120 film: $276.12 per year or $0.64 per frame.&lt;/p&gt;
&lt;h2 id="developing-film-lab"&gt;Developing film &amp;mdash; lab&lt;/h2&gt;
&lt;p&gt;For our lab numbers, we will use &lt;a href="http://canadianfilmlab.com/pricing-cad/"&gt;Canadian Film Lab&lt;/a&gt;.  For black and white
processing, you can get a roll of 35mm developed, scanned, and edited for $25;
120 film will run you $22 for the same.  Let&amp;rsquo;s add $5 for mailing it in.&lt;/p&gt;
&lt;h3 id="documentary-photographer"&gt;Documentary photographer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;35mm: 12 * $30 = $360 per year ($0.83 per frame)&lt;/li&gt;
&lt;li&gt;120: 12 * $27 = $324 per year ($2.25 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="obsessed-photographer"&gt;Obsessed photographer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;35mm: 36 * $30 = $1,080 per year ($0.83 per frame)&lt;/li&gt;
&lt;li&gt;120: 36 * $27 = $972 per year ($2.25 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="developing-film-at-home"&gt;Developing film &amp;mdash; at home&lt;/h2&gt;
&lt;p&gt;Developing black and white film at home is a relatively simple process.  When
you are finished shooting a roll of film, you place it in a hard bag, remove it
from the canister (or spool), and wind it on a reel.  The reel is then placed
into a light safe tank.  This tank is really in that you can pour chemicals in
and out of it without exposing what&amp;rsquo;s inside to light.  This is called a
Paterson tank, and it can usually fit 2 rolls of 35mm film or 1 roll of 120 film
(there are other sizes, too).  There are three chemicals that you have to pour
in one by one for certain periods of time: the developer, the stop bath, and the
fixer.  Once your film is developed, you need to scan it, and for that you need
a scanner which has a backlight.&lt;/p&gt;
&lt;p&gt;There are two types of purchases here: the one time purchase, and the ongoing
purchases of things that need to be replenished.  While it may seem like a lot
of money up from, it all pays for itself in the long run when compared to using
a lab.&lt;/p&gt;
&lt;h3 id="one-time-cost"&gt;One time cost&lt;/h3&gt;
&lt;h4 id="paterson-tank"&gt;Paterson tank&lt;/h4&gt;
&lt;p&gt;You can purchase one at &lt;a href="https://www.patersonphotographic.ca/product/universal-tank-with-two-reels/"&gt;Paterson Canada&lt;/a&gt; for $39.20.  This one will fit either 2
rolls of 35mm film, or a single roll of 120 film.&lt;/p&gt;
&lt;h4 id="black-bag"&gt;Black bag&lt;/h4&gt;
&lt;p&gt;You can purchase at one at &lt;a href="https://www.patersonphotographic.ca/product/changing-bag-27x30/"&gt;Paterson Canada&lt;/a&gt; for $56.00.  You might be able to
find one cheaper on eBay or Amazon.&lt;/p&gt;
&lt;h4 id="scanner"&gt;Scanner&lt;/h4&gt;
&lt;p&gt;You can find an Epson V660 scanner on &lt;a href="https://www.amazon.ca/EPSON-B11B198011-Epson-Perfection-Scanner/dp/B072WC4QFB/"&gt;Amazon&lt;/a&gt; for $399.  You can find an older
Epson model for possibly half that.&lt;/p&gt;
&lt;h3 id="ongoing-cost"&gt;Ongoing cost&lt;/h3&gt;
&lt;p&gt;After acquiring the necessary equipment, you will need to keep buying the
chemicals.  There are three things you will need: developer, stop bath, and
fixer.  We will buy all three of them from the Ilford Canada website (they offer
free shipping if you order over $100).&lt;/p&gt;
&lt;h4 id="developer"&gt;Developer&lt;/h4&gt;
&lt;p&gt;Our developer of choice is &lt;a href="https://www.ilfordphoto.ca/product/ilfosol-3-500ml-2/"&gt;Ilfosol 3&lt;/a&gt;.  It costs $13.10.  It comes in 500ml
bottles.  The liquid must be diluted before use with a ratio of 1:14.  Our
Paterson tank has a volume of 500ml, and does either 2 rolls of 35mm film or 1
roll of 120 film.  Given the ratio above, 35ml of Ilfosol 3 will yield one
Paterson tank batch.  Thus, the 500ml bottle of developer should yield 14
batches.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cost per 35mm frame: $0.013&lt;/li&gt;
&lt;li&gt;Cost per 120 frame: $0.078&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Documentary photographer&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;35mm: one bottle should last at least two years; cost per year: $6.55&lt;/li&gt;
&lt;li&gt;120: one bottle should last at least one year; cost per year: $13.10&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Obsessed photographer&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;35mm: one and a half bottles: $19.65&lt;/li&gt;
&lt;li&gt;120: three bottles: $39.30&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="stop-bath"&gt;Stop bath&lt;/h4&gt;
&lt;p&gt;Our stop bath of choice is &lt;a href="https://www.ilfordphoto.ca/product/ilfostop-500ml/"&gt;Ilford stop bath&lt;/a&gt;.  It costs $11.40.  It comes in
500ml bottles.  The liquid must be diluted before use with a ratio of 1:19.  One
bottle should yield 20 batches.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cost per 35mm frame: $0.008&lt;/li&gt;
&lt;li&gt;Cost per 120 frame: $0.048&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Documentary photographer&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;35mm: one bottle should last at least three years; cost per year: $3.80&lt;/li&gt;
&lt;li&gt;120: one bottle should last at least one year; cost per year: $11.40&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Obsessed photographer&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;35mm: one bottle: $11.40&lt;/li&gt;
&lt;li&gt;120: one bottle: $11.40&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="fixer"&gt;Fixer&lt;/h4&gt;
&lt;p&gt;Our fixer of choice is &lt;a href="https://www.ilfordphoto.ca/product/rapid-fixer-500ml/"&gt;Ilford Rapid Fixer&lt;/a&gt;.  It costs $10.47.  It comes in 500ml
bottles.  The liquid must be diluted before use with a ratio of 1:4.  One bottle
should yield 5 batches.  The liquid can be reused 24 times.  One bottle will
yield 120 Paterson tank batches.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cost per 35mm frame: $0.001&lt;/li&gt;
&lt;li&gt;Cost per 120 frame: $0.007&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Compared to the other items, the cost of fixer is negligible.&lt;/p&gt;
&lt;h4 id="total-chemicals"&gt;Total chemicals&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Documentary photographer&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;35mm: $10.35 per year&lt;/li&gt;
&lt;li&gt;120: $24.50 per year&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Obsessed photographer&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;35mm: $31.05 per year&lt;/li&gt;
&lt;li&gt;120: $50.70 per year&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="let-s-put-it-all-together"&gt;Let&amp;rsquo;s put it all together&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s put all the numbers together.  Since developing film at home involves some
startup costs, we will indicate how much each photographer spends per year for
the first 5 years, and then we will do some averages.&lt;/p&gt;
&lt;h3 id="lab"&gt;Lab&lt;/h3&gt;
&lt;h4 id="35mm"&gt;35mm&lt;/h4&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Year 1&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $104.03 (film) + $360 (lab) = $463.03 ($1.07 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $221.02 (film) + 100 (loader) + $1,080 (lab) = $1,401.02 ($1.08 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Year 2 - 5&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $104.03 (film) + $360 (lab) = $463.03 ($1.07 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $221.02 (film) + $1,080 (lab) = $1,301.02 ($1 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="120"&gt;120&lt;/h4&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Year 1 - Year 5&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $92.04 (film) + $324 (lab) = $416.04 ($2.89 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $276.12 (film) + $972 (lab) = $1,248.12 ($2.89 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="at-home"&gt;At home&lt;/h3&gt;
&lt;p&gt;Startup cost: $495.20&lt;/p&gt;
&lt;h4 id="35mm"&gt;35mm&lt;/h4&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Year 1&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $104.03 (film) + $495.20 + $10.35 (chems) = $609.58 ($1.41 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $221.02 (film) + $495.20 + $100 (loader) + $31.05 (chems) = $847.27 ($0.65 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Year 2 - 5&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $104.03 (film) + $10.35 (chems) = $114.38 ($0.26 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $221.02 (film) + $31.05 (chems) = $252.07 ($0.19 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Average:&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $213.42 ($0.49 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $371.11 ($0.29 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="120"&gt;120&lt;/h4&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Year 1&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $92.04 (film) + $495.20 + $24.50 (chems) = $611.74 ($4.25 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $276.12 (film) + $495.20 + $50.70 (chems) = $822.02 ($1.90 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Year 2 - 5&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $92.04 (film) + $24.50 (chems) = $116.54 ($0.81 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $276.12 (film) + $50.70 (chems) = $326.82 ($0.76 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Average:&lt;/p&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;DP: $215.58 ($1.50 per frame)&lt;/li&gt;
&lt;/ul&gt;
 &lt;!--list-separator--&gt;
&lt;ul&gt;
&lt;li&gt;OP: $425.86 ($0.99 per frame)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We have seen a lot of numbers.  The biggest take away is that developing film at
home can significantly reduce your costs if you shoot a lot.  However, the
biggest downside to developing your own film is that there is a lot stuff you
need to buy up front.  Some people may not enjoy the developing process, and the
higher cost of having someone else deal with it might be worth it.  Also, bulk
loading your film can save you a ton of money, too.&lt;/p&gt;</description><author>Honza Pokorný</author><pubDate>Wed, 17 Jun 2020 16:00:00 GMT</pubDate><guid isPermaLink="true">https://honza.pokorny.ca/2020/06/the-cost-of-shooting-film-in-2020-in-canada/</guid></item><item><title>Post hoc ergo propter hoc</title><link>https://blog.harterrt.com/notebook/2020-06-17.md.html</link><description>&lt;!---
status: draft
---&gt;

&lt;p&gt;Economists have a handy phrase to describe a fairly common fallacy:
"Post hoc ergo propter hoc" meaning "After, therefore because".&lt;/p&gt;
&lt;p&gt;Wikipedia has an example of how this might look in the wild:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A tenant moves into an apartment
and the building's furnace develops a fault.
The manager blames the tenant's …&lt;/p&gt;&lt;/blockquote&gt;</description><author>blog.harterrt.com</author><pubDate>Wed, 17 Jun 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/notebook/2020-06-17.md.html</guid></item><item><title>ffmpeg bookmarks</title><link>https://xenodium.com/ffmpeg-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=23540704"&gt;FFmpeg 4.3 (Hacker News)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=26370704"&gt;FFMPEG from Zero to Hero | Hacker News&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://el-tramo.be/blog/ken-burns-ffmpeg/"&gt;Ken Burns Effect Slideshows with FFMPeg (mko.re)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ottverse.com/stack-videos-horizontally-vertically-grid-with-ffmpeg/"&gt;Stack Videos Horizontally, Vertically, in a Grid With FFmpeg - OTTVerse&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Wed, 17 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/ffmpeg-bookmarks</guid></item><item><title>Progressing to Purple - An Introduction</title><link>http://spirals.blog/articles/purple-introduction/</link><description>&lt;div class="toc"&gt;
&lt;p&gt;Purple represents the “second stage” of human existence. If you’re new to Spiral, please first read:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/what-is-spiral-dynamics/"&gt;What is Spiral Dynamics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spirals.blog/articles/beige-introduction/"&gt;Beginning in Beige&lt;/a&gt;
This article will provide the necessary context for some of the concepts here.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Entering Purple&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Unlike the person at the first level, who lives a very automatic form of existence, and who has a very limited inner life, [Purple] has a very full inner life, one which is full of indwelling spirits. It doesn’t see self as one with all other human beings. It sees self as something that is animate, and all other things that are alive are also animate. So the tree is alive, and the tree has a spirit, and the panther has a spirit, and all the other animals have a spirit. This is something that is quite different in this level of human existence.&lt;/p&gt;
&lt;p&gt;– Clare Graves - &lt;a href="https://youtu.be/tt3Uk1f3y_U?t=733"&gt;In Conversation with Clare W. Graves. (Youtube)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We could argue that Purple is one of the &lt;strong&gt;most important&lt;/strong&gt; stages/perspectives in the whole Spiral, and indeed for our own personal development. Many who teach Spiral often disregard this magical color as “too primitive” or “basic” for consideration. Some believe it’s already “integrated” into human nature and society. In this article, we’ll explore the tremendous power behind the color underpinning it all, how it applies to us, and what we can do with it.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;In our &lt;a href="https://spirals.blog/articles/beige-introduction/"&gt;last article&lt;/a&gt;, we looked at Beige as the most primitive stage of development of the human condition. As the Spiral theory goes, if we solve the existential problems of where we are, and the necessary Life Conditions present themselves, change &lt;em&gt;may&lt;/em&gt; occur.&lt;/p&gt;
&lt;p&gt;Aptly put by Graves himself, the shift into this tribalistic perspective is driven by a sense of “good and bad”. An individual or culture that’s experienced and “solved” the Beige problem has a reference for things that worked and things that didn’t, but is not yet capable of understanding why. As a result, the world becomes very superstitious for this perspective, as one “develops a belief that things are either for you or against you”. This becomes the precursor and driving force behind Purple, banding humans together in larger tribes, and moving humanity forwards.&lt;/p&gt;
&lt;h2&gt;The Unseen World: Purple’s Belief System&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Shaman" src="http://spirals.blog/articles/purple-introduction/shaman2.jpg" /&gt;
&lt;em&gt;Photo by Vineeth Vinod @sundaestudios&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;“I call upon the power of the Full Moon’s light.&lt;br /&gt;
Heed my call.&lt;br /&gt;
Charge this amulet with your power so that it may protect this land.&lt;br /&gt;
May the power of the moon forever charge this amulet.&lt;br /&gt;
Thank you, oh moon, I am grateful for your energy.&lt;br /&gt;
Protect with this amulet.”&lt;/p&gt;
&lt;p&gt;To this day, Purple remains a core part of our culture. One might say that everything humans have developed culturally evolved from some belief, or way of operating in Purple. So much of our legal systems, ideas around how we work professionally, relationships, political correctness, and way of life, stems from protecting Purple in some fashion (We’ll cover this in other articles).&lt;/p&gt;
&lt;p&gt;Human beings at the core of who we are, place the idea of spirits in many things to make sense of the world. We’ve moved past this in many respects onto other belief systems; however, it still underpins the fabric of every further idea we developed. Purple is the first perspective humans developed that “sacrificed self” for something outside itself (unlike Beige). For the Purples, it was the spirits of the mountains, forests, other tribe members, and their ancestors. Humans would go to great efforts to sacrifice animals, precious food, other humans, and worshiped items in service to the spirits and gods. When reaching Blue, this transforms into something else, and later again in Green, etc., but we’ll cover those in another article too. Back to Thor.&lt;/p&gt;
&lt;h2&gt;You’re safe with us! - The Purple Perspective&lt;/h2&gt;
&lt;p&gt;Purple is all around us. The family dinners, telling your partner you love them, chilling with friends, inviting strangers in for tea (not ordinary in the West, interestingly). &lt;em&gt;They all express a sense of creating safety amongst everyone.&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“You belong with us”&lt;/li&gt;
&lt;li&gt;“Oh don’t worry, just pay me back whenever. I trust you (as a local business owner)”&lt;/li&gt;
&lt;li&gt;Calling your distant family for their birthday to let them know you still care.&lt;/li&gt;
&lt;li&gt;Looking out for your friends when they’re in trouble.&lt;/li&gt;
&lt;li&gt;“Hey, want some of my ice-cream?” (As hard as it can sometimes be)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Healthy Purple, this &lt;em&gt;all&lt;/em&gt; comes from a place of genuinely wanting the best for that person/group/business. They belong to your tribe. The more you look after them, the more they’ll look after you. When we begin to throw other colors/perspectives into the mix, this get’s more complicated, but for now, let’s just stick with Purple.&lt;/p&gt;
&lt;p&gt;Back then, Purple was a paradise compared to Beige. The safety of the group meant that you could sleep in, consume MUCH more food, and you didn’t have to worry about being eaten in the night. Yes, please! People learned to get along with each other in much larger groups. They developed different clothing styles to tell themselves apart from “other Purple tribes” (they were dangerous) – rituals and beliefs that belonged only to them.&lt;/p&gt;
&lt;p&gt;We began to do everything together; eating, sleeping, dancing, hunting, foraging; all done with others. To go out alone would often mean death, so people learned to be in groups. We often developed different languages for each tribe, things we prayed to, and foods we ate. For many of us, this was where we stopped roaming around and started to settle in one place.&lt;/p&gt;
&lt;p&gt;Today, Purple is at the base of almost all our interactions with other humans. Unconsciously, we are &lt;em&gt;continually&lt;/em&gt; observing others to see if they pose a threat to our safety or belong to our tribe. Depending on how “healthy” the Purple expression is (more on this later), it would determine how “sociable” one is towards strangers, if we share our food, how comfortable we are with ourselves (internal Purple), etc.&lt;/p&gt;
&lt;h2&gt;Racism&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Racism" src="http://spirals.blog/articles/purple-introduction/racism.jpg" /&gt;
&lt;em&gt;Photo by Clay Banks @claybanks&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Those who appear “strange” to us are often operating “outside Purple” or in a “different type of Purple”; exhibiting behaviors or beliefs that don’t fit the group. That is &lt;em&gt;&lt;strong&gt;not at all&lt;/strong&gt;&lt;/em&gt; to say they’re “wrong”; just not &lt;em&gt;“our Purple”&lt;/em&gt;. This distinction of Purple may be the root of racism, a fear of other cultures, viewing things that are “different to us” as a threat to our way of life. Of course, as we have evolved into a broader awareness and other colors, this fear becomes unjustified and causes many issues. We can combine the segregation of different Purples into a larger Purple (forming a different color/Perspective, Blue or Green, but that’s another story for another day). We see this in countries like Australia, Canada, and New Zealand, who (even though there are still race issues) are very open and welcoming to refugees and foreigners (although neither started this way).&lt;/p&gt;
&lt;p&gt;In contrast, we can compare this to the fear and uncertainty that countries like America hold (to this day, as the time of writing, 2020) towards minority Purple groups. By &lt;em&gt;integrating&lt;/em&gt; Purple into a way of culture, we can alleviate many of our systemic problems. Racism is a deep-rooted, complex dilemma that to heal requires many more levels of perspective than just Purple, but it &lt;em&gt;starts&lt;/em&gt; here. A great example of this is the Maori culture of New Zealand. The British who landed in Australia nearly wiped out the native Aboriginals, viewing them legally as &lt;em&gt;animals&lt;/em&gt; until 1967! New Zealand, on the other hand, built a much deeper relationship with the natives from the get-go. Today, children of New Zealand, regardless of race, can learn Maori language and history in school, and their culture is celebrated in national pride. This integration of Purple at the beginning of this culture-merge set New Zealand up with a much healthier base to build the rest of the Spiral from, and we see this very evidently today.&lt;/p&gt;
&lt;h2&gt;Internal Purple&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Self Esteem" src="http://spirals.blog/articles/purple-introduction/cozy.jpg" /&gt;
&lt;em&gt;Photo by Taisiia Stupak @taiamint&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The Colors are dynamic ideas that can apply to large groups of people (companies, movements, countries) as well as individuals, and the &lt;em&gt;cycles of life&lt;/em&gt; that we move through as humans. What does Purple look like at an individual level, and why is it so crucial to get this right before moving on to more complex problems?&lt;/p&gt;
&lt;p&gt;If Purple at the macro level represents the safety of the tribe, then at the individual level, it could be described as the relationship we have with ourselves, our acceptance of who we are, and our sense of “Base Safety”. Do we feel like we belong? Are we comfortable in our skin? Do we feel safe? Safe, not just from the lions and natural threats, but also from modern threats of peer acceptance and social pressures. This is massive. An incredible opportunity for almost everyone beginning on their journey into personal growth is looking into their relationship with their own Purple.&lt;/p&gt;
&lt;p&gt;Am I kind to others? Can I let my partner go away for the weekend without feeling scared, alone, or that they’ll cheat on me? Do I have a group of others that I feel I intrinsically belong to; that &lt;em&gt;get&lt;/em&gt; me? Unfortunately, so much of modern culture does not set us up for success in this regard, instead, often forcing us to focus on other colors’ problems that society or the group deems more worthy/important. What we often fail to realize (both as individuals and collectives) is that without a healthy Purple, ALL other expressions of more complex colors will, by nature, be unhealthy. How can we express ourselves healthily in Red if we don’t feel safe? Won’t our Blue become closed and overcomplicated with rules if we’re not addressing the underlying feeling of insecurity? Perhaps you know of an Orange who believes the Ferrari he’s working 16 hours a day for will fill the hole he feels inside. And so on. Without healthy Purple, everything else falls apart.&lt;/p&gt;
&lt;p&gt;For many of us, the “lowest hanging fruits” to living a happier, more joyful life lie in Purple. Treating others more kindly, sharing more, &lt;a href="https://www.ted.com/talks/brene_brown_the_power_of_vulnerability"&gt;becoming more vulnerable&lt;/a&gt;, finding ways in which we’re all part of the same tribe; they all add up. Speaking from personal experience, and having helped and worked with many others in the same boat, healing Purple can provide us with a fulfilling, profound, path to a happier life. We will continue to write about this in many different articles from different perspectives moving forward, as it is such an essential topic to &lt;em&gt;practically&lt;/em&gt; improving our Spirals.&lt;/p&gt;
&lt;h2&gt;Discover what Purple means to you&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Campfire" src="http://spirals.blog/articles/purple-introduction/campfire.jpg" /&gt;
&lt;em&gt;Photo by Ethan Hu @ethanhjy&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you’re looking to explore this side of yourself, your family, and your community, take some time to find your Purple Rituals. You’ll know them from memory; each Purple does it differently. For some, it’s a weekend trip to the woods, swapping stories around a campfire. For others, it’s curling up on the couch with a loved one (or alone!) and watching your favorite film of which you know ALL the words. Maybe it’s going for a long walk along the beach, or taking a bath, or cooking the recipe your grandmother gave to you on her deathbed (RIP grandma, your carrot cake legacy lives on in us).&lt;/p&gt;
&lt;p&gt;The vital aspect of all these is that they share the same &lt;em&gt;intention&lt;/em&gt;; they help us belong and feel safe. They connect us, bringing us closer to ourselves and others. Until this becomes a problem...&lt;/p&gt;
&lt;h3&gt;Leaving Purple&lt;/h3&gt;
&lt;p&gt;The safety of the tribe may start to feel limiting for some. There are those who seek to explore and see beyond the limits of where everyone they know exists. In another article, we'll look into how Red takes a stand. Setting out on a new adventure that would change the course of human history for our ancestors, and exploring our own identities, Red takes the Spiral to a &lt;a href="https://spirals.blog/articles/red-introduction/"&gt;whole new place&lt;/a&gt;.&lt;/p&gt;
&lt;div class="disclaimer"&gt;
&lt;h3&gt;A note from one learner to another&lt;/h3&gt;
&lt;p&gt;The title of this article, “Progressing to Purple - An Introduction” really wants to emphasize the word &lt;em&gt;&lt;strong&gt;“Introduction”&lt;/strong&gt;&lt;/em&gt;. Each color on the Spiral is immensely deep, and complex; one could devote an entire lifetime exploring everyone. Hopefully, today, this article serves as a good place to start this discussion of Purple; however, there is a multitude of concepts and ideas to discover. May you continue to study it, converse with it, and use it for the rest of your life.&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;p&gt;Purple is a magical, beautiful perspective and tool that can bind warring countries together, and heal wounded souls from distant traumas. It’s warm and cozy, a little “cult-y,” and just the thing we need after a long day of solving other color’s problems. Come, meet us by the fire; we have hugs, good vibes, and marshmallows. What else could you want?&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Wed, 17 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/purple-introduction/</guid></item><item><title>Lightweight Google Analytics alternatives</title><link>https://lwn.net/Articles/822568/</link><description>Discusses what Google Analytics tracks, and presents two lightweight alternatives: GoatCounter and Plausible (LWN.net).</description><author>Ben Hoyt's technical writing</author><pubDate>Wed, 17 Jun 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://lwn.net/Articles/822568/</guid></item><item><title>Silence isn't OK: Black Lives Matter</title><link>https://rob.sh/post/difficult-times/</link><description>&lt;p&gt;I haven’t ever used this site to post anything about my political beliefs. I’m
compelled to right now, because of what is happening in my adopted home
country.&lt;/p&gt;
&lt;p&gt;In a time where a great leveller has impacted &lt;em&gt;everyone’s&lt;/em&gt; life, where
circumstances beyond our control have impacted an aspect of &lt;em&gt;everyone’s&lt;/em&gt; plans&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we couldn’t use this time to unite and have compassion for &lt;em&gt;all&lt;/em&gt; humans. The
outrage at events in Minneapolis has spread across the US - and rightly so. In
doing so, it has brought a major issue in our society to the fore. We shouldn’t
need reminding that people should not be treated differently based on the
colour of their skin, but it is something that our society has quietly chosen
to sweep under the carpet, and ignore. It shouldn’t need to be explicitly
stated, but it is essential that we say it out loud, and repeat it: &lt;strong&gt;Black
Lives Matter&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why am I posting this? Here are a few of the things that I believe, that I want
to explicitly state - as food for thought. I do not claim that these are novel
ideas - they’re not. I don’t claim they are ideas that everyone will agree
with. I just ask that you spend a little time thinking about them.&lt;/p&gt;</description><author>rob.sh</author><pubDate>Wed, 17 Jun 2020 00:30:00 GMT</pubDate><guid isPermaLink="true">https://rob.sh/post/difficult-times/</guid></item><item><title>COVID19 is flattening the curve of teaching</title><link>https://stop.zona-m.net/2020/06/covid19-is-flattening-the-curve-of-teaching/</link><description>&lt;p&gt;In Italy, and surely elsewhere.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 16 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/covid19-is-flattening-the-curve-of-teaching/</guid></item><item><title>Personal Infrastructure</title><link>/personal-infra/</link><description>&lt;p&gt;After seeing the amazing posts by both Stephan Wolfram and Jess Frazelle, I wanted to chime in on my &amp;quot;personal infrastructure&amp;quot;. I've always found stories about how people work, their little scripts and hacks they use and the machines they operate on, to be incredibly compelling - &lt;a href="https://usesthis.com/"&gt;usesthis&lt;/a&gt; is a great site dedicated to that very subject.&lt;/p&gt;
&lt;h2&gt;Principles&lt;/h2&gt;
&lt;p&gt;I have two principles that I keep close to mind when looking to change or add to my setup.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Productivity - although I dislike the word (it sort of leaves a plastic taste in my mouth), productivity or rather getting the right things done is something that I'm always cognisant of. Because time is always a constraint, I look for ways to reduce the time &lt;em&gt;I&lt;/em&gt; actually have to be doing something.&lt;/li&gt;
&lt;li&gt;Automation - this sort of links with the above but automation is a guiding principle in my life because the enjoyment I get from having a computer do something I did previously is overwhelming. I am fascinated by small scripts, cron jobs, and simple bots. I utilize all sorts of services to automate tasks. If there is a recurring activity I perform, in all likelihood, I will automate it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Daily Grind&lt;/h2&gt;
&lt;p&gt;Currently, I work as a Senior Software Engineer for &lt;a href="https://www.cappfinity.com/"&gt;Cappfinity&lt;/a&gt;. My role is heading up development on a product called Koru which was purchased as a startup. The job, rather generously, purchased a 2019 Macbook Pro with 32GB Ram for development usage. It works great asides from the occasional sluggishness. I'm fortunate as for personal work, I use a Macbook Pro as well so the context switching between the two devices was minimal.&lt;/p&gt;
&lt;p&gt;I keep this Macbook primarily &lt;a href="https://cdn.osxdaily.com/wp-content/uploads/2012/06/clamshell-macbook-in-bookarc.jpg"&gt;&amp;quot;clamshelled&amp;quot;&lt;/a&gt; on my desk in a &lt;a href="https://www.amazon.co.uk/gp/product/B07HKH2QGD/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1"&gt;black metal stand I got on Amazon&lt;/a&gt;. It is connected via a DisplayLink dock to two 24 Inch Monitors.&lt;/p&gt;
&lt;p&gt;I use a &lt;a href="https://www.logitech.com/en-gb/product/multi-device-keyboard-k380"&gt;Logitech K380&lt;/a&gt; for typing. As much as I would love a mechanical keyboard, my catastrophically frail wrists cannot bear the strain of the key travel. The build quality of the keyboard is not great and is more plastic than an American news presenters face, but it has a great 3 device bluetooth switcher which allows me to toggle between my personal and work laptop's as well as my gaming PC.&lt;/p&gt;
&lt;p&gt;I put an &lt;a href="https://www.logitech.com/en-gb/product/mx-master-3?crid=7"&gt;MX Master 3&lt;/a&gt; on the right hand side of my keyboard - again it has the same great 3 device bluetooth switcher. And a Magic Trackpad on the left. I occasionally swap the two but generally it stays in this configuration. It sounds odd, but it's nice to have the options and reduce the repetitive movements I do.&lt;/p&gt;
&lt;p&gt;During lockdown, my wife was able to spend some time redoing both her art studio and my office. She painted it a subtle green and chose an &amp;quot;urban jungle&amp;quot; theme. I've always loved bringing nature indoors and having lots of plants around really helps me focus and not feel like I'm in an office. Makes it look a more bright and vibrant environment, rather than a dull dreary office.&lt;/p&gt;
&lt;h2&gt;Health&lt;/h2&gt;
&lt;p&gt;My wife, kindly, bought me a &lt;a href="https://www.hermanmiller.com/en_gb/products/seating/office-chairs/aeron-chairs/"&gt;Herman Miller Aeron&lt;/a&gt; for my desk after &amp;quot;relentlessly moaning&amp;quot; (according to her - what does she know) about my previous chair - which was as comfortable as a church pew. The Aeron is like being cradled by 4 angels and has helped my posture and fatigue massively. Yes that's right, fatigue. Sitting down all day can be tiring in a weird way, due to the lack of lower body movement. I've tried to alleviate this by taking regular breaks and working in different environments. It was the best present she's got me to this day and will make a huge difference to my daily life.&lt;/p&gt;
&lt;p&gt;Furthermore, I've found the amount of water I drink to be a big factor in my mood. I know attempt to drink around 4L of Pure water per day as well as a coffee or two. I try to avoid caffeine after midday as I find it affects my sleep quantifiable.&lt;/p&gt;
&lt;h2&gt;Personal Work&lt;/h2&gt;
&lt;p&gt;Asides from my day job, I am working on a SaaS business, &lt;a href="https://turboapi.dev"&gt;TurboAPI&lt;/a&gt;, and a charity, Alex's Wonderland Puzzles (that is still undergoing heavy development).&lt;/p&gt;
&lt;p&gt;In the case of the former, I develop the application using Typescript and host on AWS and DigitalOcean with Docker - because ECS is more hassle than it's worth. The frontend is hosted on Netlify and is built using React. I am looking to dabble a lot more in Golang and Rust, so I can work closer to the metal. Golang in particular introduces some new paradigms that are interested to me, and I believe would benefit me. However, my current spare time is dedicated to TurboAPI and Alex's Puzzles so I have that learning on hold for the time being.&lt;/p&gt;
&lt;p&gt;For the puzzle company, my role is a little different. I'm in charge of sorting manufacturing, marketing, website development/maintenance and design. For this, I take details notes in Notion as it allows me to create tables, lists, charts and anything else I want. The website was built very simply using React and will soon have a store hosted with Shopify. I do designs in whatever notebook I have to had - usually a moleskin.&lt;/p&gt;
&lt;p&gt;On both my work and personal setup, I take notes in a private repo in GitHub. It allows me to jot my thoughts quickly and frictionlessly. I also write post mortems in there from any projects I'm working on. I've never been in an organisation that does public post mortems, but I find them good practise to really nail down the issue that was at the heart of the problem.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I've got tonnes more to talk about here, but I want to keep this post short so I'll bid you all adieu and goodbye. In the next post I'll discuss my personal slack hub and automations I've been working on. Stay Tuned!&lt;/p&gt;</description><author/><pubDate>Tue, 16 Jun 2020 15:01:03 GMT</pubDate><guid isPermaLink="true">/personal-infra/</guid></item><item><title>Daily Writing and the "Notebook" Category</title><link>https://blog.harterrt.com/notebook/2020-06-16.html</link><description>&lt;p&gt;This past weekend I found 
&lt;a href="https://notebook.drmaciver.com/posts/2020-06-08-10:11.html"&gt;drmaciver's post&lt;/a&gt;
on starting a daily writing practice.
I like the idea and I'm going to give it a try.&lt;/p&gt;
&lt;p&gt;The content on this blog has never been all that polished,
but I do expect these daily posts will be less consistent 
in quality and …&lt;/p&gt;</description><author>blog.harterrt.com</author><pubDate>Tue, 16 Jun 2020 10:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.harterrt.com/notebook/2020-06-16.html</guid></item><item><title>Put your bash code in functions</title><link>https://ricardoanderegg.com/posts/wrap-bash-code-functions/</link><description>&lt;p&gt;I wrote my degree dissertation in jupyter notebooks. Then I converted them to markdown and finally to pdf with pandoc. I also had to output an office file so that my tutor could work on it too. The initial code was:&lt;/p&gt;
&lt;div class="highlight" style="background: #f8f8f8;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span style="color: #8F5902; font-style: italic;"&gt;#!/usr/bin/env bash&lt;/span&gt;


&lt;span style="color: #000;"&gt;ProcessName&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;PDF Expert&amp;quot;&lt;/span&gt;
&lt;span style="color: #000;"&gt;number&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;$(&lt;/span&gt;ps&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;aux&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;grep&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;-v&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;grep&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #000; font-weight: bold;"&gt;|&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;grep&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;-ci&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000;"&gt;$ProcessName&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #204A87; font-weight: bold;"&gt;)&lt;/span&gt;
&lt;span style="color: #8F5902; font-style: italic;"&gt;# echo $number&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;if&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;[&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000;"&gt;$number&lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;-le&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #0000CF; font-weight: bold;"&gt;0&lt;/span&gt;&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;]&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;then&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;open&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;-a&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;'PDF Expert'&lt;/span&gt;
&lt;span style="color: #204A87; font-weight: bold;"&gt;fi&lt;/span&gt;
pandoc&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;final.md&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;format.yaml&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--filter&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;pandoc-citeproc&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--table-of-contents&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--number-sections&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--pdf-engine&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;xelatex&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--indented-code-classes&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;python&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--highlight-style&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;pygments&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--template&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;./eisvogel2.tex&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--listings&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;-o&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;final.pdf
pandoc&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;final.md&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;format.yaml&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--filter&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;pandoc-citeproc&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--table-of-contents&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--number-sections&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--indented-code-classes&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;python&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--highlight-style&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;pygments&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;--template&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;./eisvogel.tex&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;-V&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #000;"&gt;lang&lt;/span&gt;&lt;span style="color: #CE5C00; font-weight: bold;"&gt;=&lt;/span&gt;es&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;&lt;span style="color: #4E9A06;"&gt;\&lt;/span&gt;
&lt;span style="color: #F8F8F8;"&gt;    &lt;/span&gt;-o&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;final.docx

open&lt;span style="color: #F8F8F8;"&gt; &lt;/span&gt;final.pdf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This code does the following:&lt;/p&gt;</description><author>Posts on rand[om]</author><pubDate>Tue, 16 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ricardoanderegg.com/posts/wrap-bash-code-functions/</guid></item><item><title>Visual Story Telling: Revisiting Minard’s Map of Napoléon’s Russian Campaign (1812–1813)</title><link>https://www.masswerk.at/nowgobang/2020/minard-revisited</link><description>Another view at Minard's famous flow map.</description><author>mass:werk – Now Go Bang!</author><pubDate>Tue, 16 Jun 2020 02:59:00 GMT</pubDate><guid isPermaLink="true">https://www.masswerk.at/nowgobang/2020/minard-revisited</guid></item><item><title>Talking about Facebook is strictly prohibited</title><link>https://stop.zona-m.net/2020/06/talking-about-facebook-is-strictly-prohibited/</link><description>&lt;p&gt;Relax. It&amp;rsquo;s not what you think. Yet.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 15 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/talking-about-facebook-is-strictly-prohibited/</guid></item><item><title>Levelling up my notes game with Zettelkasten</title><link>https://www.unsungnovelty.org/posts/06/2020/levelling-up-my-notes-game-with-zettelkasten/</link><description>&lt;blockquote&gt;
&lt;p&gt;License: &lt;a href="https://creativecommons.org/licenses/by-nc-nd/4.0/"&gt;Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
_International Public License (CC BY-NC-ND
_4.0)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Notes are a great way to write things down. But as you start writing more notes, the number obviously keeps increasing. This leads to having a large number of notes which are outdated or forgotten. This is mainly because these are seperate notes and not connected with the other notes in anyway. So as humans, we forget about the conncetions as time passes.&lt;/p&gt;
&lt;h2 id="zettelkasten-a-possible-solution"&gt;Zettelkasten, a possible solution!&lt;/h2&gt;
&lt;p&gt;Imagine that you just started working on a web application project. You already have seperate notes on what you know and have learnt about &lt;code&gt;HTML&lt;/code&gt;, &lt;code&gt;CSS&lt;/code&gt; and &lt;code&gt;JavaScript&lt;/code&gt;. And now, a new note called &lt;code&gt;myWebApp&lt;/code&gt;. In it, you wrote features the web application should have, your thoughts on the project etc. You know the ideas and learnings from your notes on &lt;code&gt;HTML&lt;/code&gt;, &lt;code&gt;CSS&lt;/code&gt; and &lt;code&gt;JavaScript&lt;/code&gt; are necessary for creating the web application. But since they are seperate notes, you often forget the connections with &lt;code&gt;myWebapp&lt;/code&gt;. Or how some information are connected.&lt;/p&gt;
&lt;p&gt;This is where Zettelkasten (Slip box in English) comes into play. With the Zettelkasten method, the idea is to link all these notes together. And the output will be like a mindmap of notes which are interconnected. It was invented by Niklas Luhmann who used this method to create 70+ books and 400+ research papers througout his career!&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img alt="An image of 4 rectangles namely HTML notes CSS Notes javascript notes and mywebapp notes connected together by a straight line illustrating how zettelkasten notes can be connected with each other." src="https://www.unsungnovelty.org/images/post-images/linkedNotes.webp" /&gt;
&lt;/figure&gt;

&lt;p class="text-center italic"&gt;An example illustration of how notes will look like when linked together&lt;/p&gt;&lt;/p&gt;
&lt;p&gt;This is an overly simplified explanation of what Zettelkasten is and can be. You can get a better understanding by read any or all the below linked blog posts. They helped me get started with Zettelkasten.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.viktomas.com/posts/slip-box/"&gt;Zettelkasten note-taking in 10 minutes by Tomas Vik&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://eugeneyan.com/2020/04/05/note-taking-zettelkasten/"&gt;Stop Taking Regular Notes; Use a Zettelkasten Instead by Eugene Yan&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://writingcooperative.com/zettelkasten-how-one-german-scholar-was-so-freakishly-productive-997e4e0ca125?gi=242ff7221300"&gt;Zettelkasten — How One German Scholar Was So Freakishly Productive by David B. Clear&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All the small details thought to be insignificant or was a duplication from another note are currently noted. Since all you have to do is link the detail with a note it is related to. This helps me remember exactly why I noted it down.&lt;/p&gt;
&lt;h2 id="so-another-note-taking-app-huh"&gt;So, another note taking app. Huh?&lt;/h2&gt;
&lt;p&gt;&lt;figure&gt;&lt;img alt="Tweet by Kyle Russel which states, productivity hack: not changing note taking apps. This tweet was posted by Kyle Russel on june 11th, 2020 at 8:35pm." src="https://www.unsungnovelty.org/images/post-images/productivity-hack.webp" /&gt;
&lt;/figure&gt;

&lt;p class="text-center italic"&gt;Tweet by Kyle Russel&lt;/p&gt;&lt;/p&gt;
&lt;p&gt;I know! But I don&amp;rsquo;t change my notes application often. And Zettelkasten looks like the next logical step for a better information system for myself. If you are hesitant about transistioning right away, do it step by step. This helps you to see the tech in action and decide if it is really useful for you or not.&lt;/p&gt;
&lt;p&gt;As for the app, I found &lt;a href="https://zettlr.com/"&gt;Zettlr&lt;/a&gt; and &lt;a href="https://obsidian.md/"&gt;Obsidian(Beta)&lt;/a&gt; as the best fit based on my tastes.
No, I haven&amp;rsquo;t tried &lt;a href="https://roamresearch.com/"&gt;Roam Research&lt;/a&gt; because it is a web application.&lt;/p&gt;
&lt;p&gt;Here is a comparison of features I was expecting from my next notes application. This is not a complete list of features these applications provide, just the features expected from a Zettelkasten note application I wanted to use. Both of them are nice, just check them out and choose the one you find fitting.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Features&lt;/th&gt;
&lt;th&gt;Zettlr&lt;/th&gt;
&lt;th&gt;Obsidian (Beta)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Open Source&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✖️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free / Free plan&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Markdown&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pomodoro&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✖️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph View&lt;/td&gt;
&lt;td&gt;✖️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save data locally&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No vendor lock-in&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="what-is-next"&gt;What is next?&lt;/h2&gt;
&lt;p&gt;I am currently in the transition period. Since this could be time consuming if done in bulk, I am taking things slow. But I am enjoying the process of taking notes more than before. Only time will tell whether I will see a connection I wouldn&amp;rsquo;t have seen if it wasn&amp;rsquo;t for my Zettelkasten!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;Found this interesting or found some errors? DM me &lt;a href="https://twitter.com/unsungNovelty"&gt;@unsungnovelty&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</description><author>unsungNovelty</author><pubDate>Mon, 15 Jun 2020 14:26:37 GMT</pubDate><guid isPermaLink="true">https://www.unsungnovelty.org/posts/06/2020/levelling-up-my-notes-game-with-zettelkasten/</guid></item><item><title>Python Module Versioning and Releases</title><link>https://trigonaminima.github.io/2020/06/py-versioning/</link><description>At work, these days, I am building some new Python ML modules to be used within other projects. When I am making modules for myself, I don’t care about the versioning or releases. But working in an environment when others are using your libraries then versioning is required. This is what I know now which I wish I had known before starting.</description><author>Playground</author><pubDate>Mon, 15 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://trigonaminima.github.io/2020/06/py-versioning/</guid></item><item><title>10 semantic HTML tags to better structure your website</title><link>https://hartenfeller.dev/blog/underused-semantic-html-tags</link><description>HTML 5 added a set of new HTML tags known as "semantic" tags to better structure websites. You should use them to avoid sinking in chaos with many levels of nested divs. They also have the benefit to make your website more accessible.</description><author>Philipp Hartenfeller Blog RSS Feed</author><pubDate>Mon, 15 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hartenfeller.dev/blog/underused-semantic-html-tags</guid></item><item><title>Programming Languages and Typography</title><link>https://lambdaland.org/posts/2020-06-15-languages-and-fonts/</link><description>&lt;p&gt;An analogy occurred to me this evening as I was thinking about programming language design:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Choosing good keywords and function names is like picking a good font; the ideas conveyed may be the same, but a change can drastically impact legibility and enjoyment of use.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PHP does a spectacular job of providing a &lt;em&gt;bad&lt;/em&gt; example. It’s like the Comic Sans of programming languages. Now there are &lt;a class="link-external" href="https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/" rel="external"&gt;many reasons why PHP is not a good language&lt;/a&gt;—I’d like to investigate this particular aspect of its design here briefly.&lt;/p&gt;
&lt;p&gt;There are ~55 &lt;a class="link-external" href="https://www.php.net/manual/en/ref.array.php" rel="external"&gt;functions in PHP that start with &lt;code&gt;array_&lt;/code&gt;&lt;/a&gt;. Why? Why would you need to call the &lt;code&gt;map&lt;/code&gt; operator &lt;code&gt;array_map&lt;/code&gt;? Or &lt;code&gt;array_filter&lt;/code&gt;, etc. Most other languages just call it &lt;code&gt;map&lt;/code&gt; and leave it at that.&lt;/p&gt;
&lt;p&gt;You might argue that that is a superficial difference: you are still doing the same thing so the expressive power of PHP is the same as whatever other languages you are comparing it to. I disagree. That extra clutter of the &lt;code&gt;array_&lt;/code&gt; prefix &lt;em&gt;should not&lt;/em&gt; be there and it’s purely clutter.&lt;/p&gt;
&lt;p&gt;A bad font changes the tone and the perception of a body of text. Likewise, shoddy selection of keywords and names in a language changes it’s tone and feel.&lt;/p&gt;
&lt;p&gt;Other examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;PHP’s &lt;code&gt;function&lt;/code&gt; keyword and other similar atrocities&lt;/li&gt;
&lt;li&gt;Common Lisp (the length of its function names are a shortcoming)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ll continue fleshing this iut more, but these are my thoughts at the present&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Mon, 15 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-06-15-languages-and-fonts/</guid></item><item><title>How the Nintendo Switch prevents downgrades by irreparably blowing its own fuses</title><link>https://jonlu.ca/posts/nintendo-switch</link><description>How the Nintendo Switch uses irreversible hardware fuses to prevent firmware downgrades.</description><author>JonLuca's Blog</author><pubDate>Sun, 14 Jun 2020 23:36:09 GMT</pubDate><guid isPermaLink="true">https://jonlu.ca/posts/nintendo-switch</guid></item><item><title>My Life as a Con Man</title><link>https://www.swyx.io/con-man-life</link><description>Confidence is a dual edged sword. I trafficked in confidence when I was in finance, and now I see it everywhere I look.</description><author>swyx's site RSS Feed</author><pubDate>Sun, 14 Jun 2020 22:46:24 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/con-man-life</guid></item><item><title>Create your first Web scraper in Go with goQuery  A beginners tutorial for writing web scrapers in Go language for Yelp.</title><link>https://blog.adnansiddiqi.me/create-your-first-web-scraper-in-go-with-goquery/</link><description>&lt;p&gt;Planning to write a book about Web Scraping in Python. Click here to give your feedback I have been covering web scraping for a long time on this blog for a long time but they were mostly in Python; be it requests, Selenium or Scrapy framework, all were based on Python language but scraping is not limited to a specific language. Any language that provides APIs or libraries for an Http client and HTML parser is able to provide you web scraping facility. Go also provides you the ability to write web scrapers. Go is a compiled and static type language and could be very beneficial to write efficient and quick and scaleable web scrapers. Thanks to Goroutunes that can help you to scrape hundreds of webpages in parallel. In this introductory post, we are going to discuss the Http library provided by Go to access a webpage or a file. We will also discuss goQuery, an Http client, and an HTML parser similar to jQuery. OK, enough talks, let&amp;#8217;s write a basic scraper. Go HTTP library I am writing a simple scraper that will be using Go&amp;#8217;s net/http library to access my home page.  I am writing. I will be using http.Get to access the page. http.Get is the default HTTP client provided by Go with default settings. package main import ( "fmt" "io/ioutil" "net/http" ) func getListing(listingURL string) { response, err := http.Get(listingURL) if err != nil { fmt.Println(err) } defer response.Body.Close() if response.StatusCode == 200 { bodyText, err := ioutil.ReadAll(response.Body) if err != nil { fmt.Println(err) } fmt.Printf("%s\n", bodyText) } } func main() { getListing("http://adnansiddiqi.me") } When you run this program it prints the HTML of my home page. The function getListing access the URL passed. For that we used http.Get method. The exported function, Get , returns the response object which contains details like HTTP status code, response content itself. Later I used ReadAllof ioutuil to return the text of the response. It&amp;#8217;s all good but as I said that Get returns the default settings and you can&amp;#8217;t override things like UserAgent, headers, and timeout. The default UserAgent is Go-http-client/1.1 which is not good for the sites who also check UserAgent of the browser. We should have some options to write a scraper that could override UserAgents, timeouts, and also allow to set proxies. Let&amp;#8217;s write a real-world scraper. Creating Yelp Scraper We are now going to create a Yelp scraper in Go/Golang that will scrape the URL of the listings of Mobile Phone Repair shops in San Francisco. We will set up a client first and create a new request. Goquery will be used for HTML parsing. func getListing(listingURL string) []string { var links []string //HTTP client with timeout client := &amp;#38;http.Client{ Timeout: 30 * time.Second, } request, err := http.NewRequest("GET", listingURL, nil) if err != nil { fmt.Println(err) } //Setting headers request.Header.Set("pragma", "no-cache") request.Header.Set("cache-control", "no-cache") request.Header.Set("dnt", "1") request.Header.Set("upgrade-insecure-requests", "1") request.Header.Set("referer", "https://www.yelp.com/") resp, err := client.Do(request) if resp.StatusCode == 200 { doc, err := goquery.NewDocumentFromReader(resp.Body) if err != nil { fmt.Println(err) } doc.Find(".lemon--ul__373c0__1_cxs a").Each(func(i int, s *goquery.Selection) { link, _ := s.Attr("href") link = "https://yelp.com/" + link // Make sure you we only fetch correct URL with corresponding title if strings.Contains(link, "biz/") { text := s.Text() if text != "" &amp;#38;&amp;#38; text != "more" { //to avoid unecessary links // links = append(links, link) } } }) } return links } First off, we set up a client variable. Since client is  a struct variable, therefore, we are using &amp;#38; to call it by reference. We are setting a timeout to 30 seconds which means it will close the connection after 30 seconds otherwise it will take the default time before getting panic. Next, we create a new request by calling http.NewRequest in which we pass the request method, GET in this case, and the URL. The last parameter is set nil as it is not required in our case. Next, required headers were set, and then the request was made by calling client.Do method. Once the content was received, we make sure by checking the status code that is 200, we now bring goQuery library for parsing HTML. doc, err := goquery.NewDocumentFromReader(resp.Body) Later I use the Find method that accepts a CSS selector and returns elements, if any. The fetched links then appended in an array which is then returned back. In the main print them. Conclusion So this was the introductory tutorial about writing web scrapers in Go. Go produces a compiled program so unlike Python you can distribute it to your customers without any hesitation. There is no need of installing a Go runtime either. As always the code is available on Github. Writing scrapers is an interesting journey but you can hit the wall if the site blocks your IP. As an individual, you can’t afford expensive proxies either. Scraper API provides you an affordable and easy to use API that will let you scrape websites without any hassle. You do not need to worry about getting blocked because Scraper API by default uses proxies to access websites. On top of it, you do not need to worry about Selenium either since Scraper API provides the facility of a headless browser too. I also have written a post about how to use it. Click here to signup with my referral link or enter promo code adnan10, you will get a 10% discount on it. In case you do not get the discount then just let me know via email on my site and I’d sure help you out. &amp;#160; If you like this post then you should subscribe to my blog for future updates. * indicates required Email Address *&lt;/p&gt;
The post &lt;a href="https://blog.adnansiddiqi.me/create-your-first-web-scraper-in-go-with-goquery/"&gt;Create your first Web scraper in Go with goQuery &lt;br /&gt; &lt;span style="color: grey; font-size: 25px; font-weight: 300;"&gt;A beginners tutorial for writing web scrapers in Go language for Yelp.&lt;/span&gt;&lt;/a&gt; first appeared on &lt;a href="https://blog.adnansiddiqi.me"&gt;Adnan's Random bytes&lt;/a&gt;.</description><author>Adnan's Random bytes</author><pubDate>Sun, 14 Jun 2020 19:03:09 GMT</pubDate><guid isPermaLink="true">https://blog.adnansiddiqi.me/create-your-first-web-scraper-in-go-with-goquery/</guid></item><item><title>The Curious Case of Swift&amp;amp;#39;s Adoption of Smalltalk Keyword Syntax</title><link>https://blog.metaobject.com/2020/06/the-curious-case-of-swift-adoption-of.html</link><description>I was really surprised to learn that Swift recently adopted Smalltalk keyword syntax:  &lt;a href="https://forums.swift.org/t/accepted-se-0279-multiple-trailing-closures/36141"&gt;[Accepted] SE-0279: Multiple Trailing Closures&lt;/a&gt;.  That is:  a keyword terminated by a colon, followed by an argument and without
any surrounding braces.&lt;p&gt;

The mind boggles.&lt;p&gt;

A little.&lt;p&gt;

Of course, Swift wouldn't be Swift if this weren't a special case of a special case, specifically
the case of &lt;em&gt;multiple&lt;/em&gt; trailing closures, which is a special case of &lt;em&gt;trailing closures&lt;/em&gt;,
which are weird and special-casey enough by themselves.  Below is an example:&lt;p&gt;


&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
UIView.animate(withDuration: 0.3) {
  self.view.alpha = 0
} completion: { _ in
  self.view.removeFromSuperview()
}
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

Note how the arguments to &lt;code&gt;animate()&lt;/code&gt; would seem to terminate at the closing parenthesis,
but that's actually not the case.  The curly braces after the closing paren start a closure that is
actually also an argument to the method, a so-called trailing closure.  I have a little bit of 
sympathy for this construct, because closures inside of the parentheses look really, really 
awkward.  (Of course, &lt;em&gt;all&lt;/em&gt; params apart from a sole &lt;code&gt;x&lt;/code&gt; inside &lt;code&gt;f(x)&lt;/code&gt;
look awkward, but let's not quibble.  For now.).&lt;p&gt;

Another thing this enables is methods that reasonably resemble control structures, which I heard
is a really great idea.&lt;p&gt;

The problem is that sometimes you have more than one closure argument, and then just stacking them
up behind what appears to be end of the function/method call gets really, really awkward, and
you can't tell which block is which argument, because the trailing closure doesn't get a keyword.&lt;p&gt;

Well, now it does.  And we now have 4 different method syntaxes in one!&lt;p&gt;

&lt;ol&gt;
&lt;li&gt;Traditional C/Pascal/C++/Java function call syntax &lt;code&gt;x.f()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;The already weird-ish addition of Smalltalk/Objective-C keywords inside the &lt;code&gt;f(x)&lt;/code&gt; syntax: &lt;code&gt;f(arg:x)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Original trailing-closure syntax, which is just its own thing, for the first closure&lt;/li&gt;
&lt;li&gt;Smalltalk non-brackted keyword syntax for the 2nd and subsequent closures.&lt;/li&gt;
&lt;/ol&gt;

That is impressive, in a scary kind of way.

&lt;blockquote&gt;
Swift is a crescendo of special cases stopping just short of the general; the result is complexity in the semantics, complexity in the behaviour (i.e. bugs), and complexity in use (i.e. workarounds).
&lt;footer&gt;
— &lt;cite&gt;&lt;a href="https://www.quora.com/Which-features-overcomplicate-Swift-What-should-be-removed?share=1"&gt;Which features overcomplicate Swift, Rob Rix&lt;/a&gt;&lt;/cite&gt;
&lt;/footer&gt;
&lt;/blockquote&gt;

In understand that this proposal was quite controversial, with heated discussion between opponents
and proponents.  I understand and sympathize with both sides.  On the one hand, this &lt;em&gt;is&lt;/em&gt;
markedly better than alternatives.  On the other hand it is a special case of a special case that
is difficult to justify as an addition of all that is already there.&lt;p&gt;

Special cases beget special cases beget special cases.&lt;p&gt;

Of course the answer was always there:  Smalltalk keyword syntax is not just the only reasonable
solution in this case, it also solves all the other cases.  It is the general solution.  Here's
how this could look in Objective-Smalltalk (which uses curly braces instead for closures instead
of Smalltalk-80's square brackets):&lt;p&gt;

&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
UIView animate:{ self.view.alpha ← 0. } withDuration:0.3 completion:{ self view removeFromSuperview. }.
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

No special cases, every argument is labeled, no syntax mush of brackets inside parentheses etc.
And yes, this also handles user-defined control structures, &lt;code&gt;to:do:&lt;/code&gt; is just a 
method on &lt;code&gt;NSNumber&lt;/code&gt;:&lt;p&gt;

&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
1 to:10 do:{:i | stdout println:"I will not introduce {i} special cases willy nilly.".}.
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

And since keywords naturally go between their arguments, there is no need for "operators",
as a very different and special syntax form.  You just allow some "binary" keywords to look
a little different, so instead of &lt;code&gt;2 multiply:3&lt;/code&gt; you can write &lt;code&gt;2 * 3&lt;/code&gt;.
And when you have &lt;code&gt;2 raisedTo:3&lt;/code&gt; instead of &lt;code&gt;pow(2,3)&lt;/code&gt; (with the
signature:  &lt;code&gt;func pow(_ x: Decimal, _ y: Int) -&amp;gt; Decimal&lt;/code&gt;), do you
really neeed to go to the &lt;a href="https://gist.github.com/steakknife/d629fa0c398f75682d00"&gt;trouble&lt;/a&gt; of defining an "operator"?

&lt;p&gt;

Or Swift's &lt;code&gt;a as b&lt;/code&gt;, another special kind of syntax.  How about &lt;code&gt;a as:b&lt;/code&gt;?
(Yes I know there are details, but those are ... details.).  And so on and so forth.&lt;p&gt;

But of course, it's too late now. When I chose Smalltalk as the base syntax for the language
that has turned into Objective-Smalltalk, it wasn't just because I just like it or have gotten
used to it via Objective-C.  Smalltalk's syntax is surprisingly flexible and general, 
Smalltalk APIs look a lot like DSLs, without any of the tooling or other overheads.&lt;p&gt;

And that's the frustrating part: this stuff was and is available and well-known. At least
if you bother to look and/or ask.  But instead, we just choose these things willy-nilly
and everybody has to suffer the consequences.&lt;p&gt;

UPDATE:&lt;p&gt;

I guess what I am trying to get at is that if you'd thought things through just a little bit, you 
could have had almost the entire syntax of your language for the cost (complexity,
implementation size and brittleness, cognitive load, etc.) of this one special case of a special case.
And it would have been overall better to boot.&lt;p&gt;</description><author>metablog</author><pubDate>Sun, 14 Jun 2020 18:13:02 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2020/06/the-curious-case-of-swift-adoption-of.html</guid></item><item><title>Pikler Ladder</title><link>https://andrewferguson.net/2020/06/14/pikler-ladder/</link><description>View model on Fusion360 Preamble Pikler Ladders are expensive. Building one seemed like a good idea. There&amp;#8217;s many different designs out there, but none that I was terribly thrilled with. So I designed my own. Then I roped my friend Charlie into helping me build one (spoiler alert: other friends wanted one too&amp;#8230;so we made&amp;#8230;&amp;#160;&lt;a class="" href="https://andrewferguson.net/2020/06/14/pikler-ladder/" rel="bookmark"&gt;Read More &amp;#187;&lt;span class="screen-reader-text"&gt;Pikler Ladder&lt;/span&gt;&lt;/a&gt;</description><author>Andrew Ferguson dot NET</author><pubDate>Sun, 14 Jun 2020 11:10:20 GMT</pubDate><guid isPermaLink="true">https://andrewferguson.net/2020/06/14/pikler-ladder/</guid></item><item><title>Black lives matter (BLM) bookmarks</title><link>https://xenodium.com/black-lives-matter-blm-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://projects.fivethirtyeight.com/racism-polls/"&gt;Do You Know How Divided White And Black Americans Are On Racism? (FiveThirtyEight)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marker.medium.com/its-time-we-dealt-with-white-supremacy-in-tech-8f7816fe809"&gt;It’s Time We Dealt With White Supremacy in Tech&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.politico.com/magazine/story/2014/05/religious-right-real-origins-107133"&gt;The Real Origins of the Religious Right - POLITICO Magazine&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/black-lives-matter-blm-bookmarks</guid></item><item><title>Dogs bookmarks</title><link>https://xenodium.com/dogs-bookmarks</link><description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://thedogspov.com/need-know-romanian-rescue-dogs/"&gt;All You Need to Know About Romanian Rescue Dogs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/dogs-bookmarks</guid></item><item><title>A year and a half worth of Links</title><link>https://faingezicht.com/links/2020/06/14/links/</link><description>It's been a while since the last one of these, so here I am, dropping ~200 links on you, hoping that at least one or two seem interesting. It's a very non-exhaustive list of interesting stuff I've read/listened to since early 2019, but I tried to focus on evergreen content.</description><author>Avy Faingezicht</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/links/2020/06/14/links/</guid></item><item><title>Ellipsis Split V1</title><link>https://www.csun.io/2020/06/14/ellipsis-split-buildlog.html</link><description>The 2nd iteration of my Ellipsis series of keyboards.</description><author>Cameron Sun</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://www.csun.io/2020/06/14/ellipsis-split-buildlog.html</guid></item><item><title>This is What I Wanted to Sign Off With by Alden Nowlan</title><link>https://ho.dges.online/words/commonplace/this-is-what-i-wanted-to-sign-off-with-by-alden-nowlan/</link><description>&lt;p&gt;You know what I’m&lt;br /&gt;
like when I’m sick: I’d sooner&lt;br /&gt;
curse than cry. And people don’t often&lt;br /&gt;
know what they’re saying in the end.&lt;br /&gt;
Or I could die in my sleep.&lt;/p&gt;
&lt;p&gt;So I’ll say it now. Here it is.&lt;br /&gt;
Don’t pay any attention&lt;br /&gt;
if I don’t get it right&lt;br /&gt;
when it is for real. Blame that&lt;br /&gt;
on terror and pain&lt;br /&gt;
or the stuff they’re shooting&lt;br /&gt;
into my veins. This is what I wanted to&lt;br /&gt;
sign off with. Bend&lt;br /&gt;
closer, listen, I love you.&lt;/p&gt;</description><author>ho.dges.online</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ho.dges.online/words/commonplace/this-is-what-i-wanted-to-sign-off-with-by-alden-nowlan/</guid></item><item><title>Getting to know your own perspective - Part 1</title><link>http://spirals.blog/articles/getting-to-know-your-own-perspective-part-1/</link><description>&lt;div class="toc"&gt;
This article is Part 1 for “Getting to know your own perspective.” You can find &lt;a href="https://spirals.blog/articles/getting-to-know-your-own-perspective-part-2/"&gt;Part 2 here.&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;It was a sweltering mid-summer of late 2016 in Australia as my girlfriend, and I finally managed to close the boot of the car. We looked at each other, the sense of adventure that brought us to this moment surged between us. This was it; we would both finally set out permanently from our childhood homes of Brisbane, with the alluring Melbourne set in our scopes. I was so sure of it! We’d only known each other a month or so, but it &lt;em&gt;felt&lt;/em&gt; so right! Disregarding my friends’ concerns, and the words of caution from those closest to me, we’d both decided to move cities off the back of a short summer’s romance. We sold what we could, packed what was left, and began our 18-hour drive to the bottom of Australia, our new home. What could go wrong?&lt;/p&gt;
&lt;p&gt;I was &lt;em&gt;completely&lt;/em&gt; out of perspective. We both were. An old friend used to say, “Before you truly know if you want to be with someone, go traveling with them first.” We barely made it through a road-trip. As our hometown shrunk into the distance, a fight broke out about goodness-knows-what (You know, the kind that redefines a relationship?), and the reality that maybe this wasn’t the right decision finally sunk in. But it was too late; the six-month lease was signed, I’d accepted a new job, and there was no turning back. I had not listened to those who warned me.&lt;/p&gt;
&lt;p&gt;We broke up a few months later, but neither was in a position to move out; it was too expensive. So we lived together for another four months, sleeping in the same bed, driving each other mad as we grappled with our decision. How could something that seemed so right play out so wrong? Maybe you have had an experience like this? A time where you were so sure of something, or someone, or some idea, only to find out later, you could not have been further from the truth. It’s a part of the human condition it would seem; however, we can take steps to prevent it.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Mirror mirror" src="http://spirals.blog/articles/getting-to-know-your-own-perspective-part-1/mirror.jpg" /&gt;
&lt;em&gt;Photo by Septian simon @septiansimon&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Mirror, mirror on the wall…&lt;/h2&gt;
&lt;p&gt;The best practitioners of Spiral Dynamics have all said the same thing; &lt;strong&gt;it’s next to impossible to see your own perspective.&lt;/strong&gt; By the very nature of trying to see yourself, you’re already filtering through your own lens. For example, an Orange/Red could read something about Yellow and “identify” with some of the principles around it’s level of “intelligence”, egotistically aligning itself with something it &lt;a href="https://spirals.blog/articles/wholearchy/"&gt;perceives to be more powerful&lt;/a&gt;. They would continue this way, deepening their belief, and may even believe their selfish “I” behaviors are operating from an altruistic intention. It goes without saying, this can cause a lot of damage.&lt;/p&gt;
&lt;p&gt;Another, less extreme, example could come from a Blue interpreting their actions as Purple. We often see this in the stereotypical “atomic family” color structure. The man (typically, but not limited to) heads off to work every day to sacrifice his time for the little that he brings back for his family. Day in, day out, he works tirelessly at his job, believing that his wife and children see how hard he’s working as a sign that he cares. “Why would you interpret this as anything else,” he might claim, “It’s obvious!”&lt;/p&gt;
&lt;p&gt;One day, his wife snaps, yelling, “You never make time for the kids or me! It’s like you don’t care about us anymore. Where is the person I married?”. Ouch! Now, if you’ve studied Spiral or related models long enough, you’d recognize in this situation that someone here is out of perspective (quite possibly both parties). We could quite effortlessly resolve this issue if there were a common language like Spiral to communicate different views between everyone involved, but that’s unfortunately not the case in many circumstances.&lt;/p&gt;
&lt;p&gt;If the man here (or whoever is solving the Blue problem for the tribe) were to hear his partner &lt;strong&gt;truly&lt;/strong&gt;, he’d recognize what he “thought” was a Purple intention was, in actuality, an automatic belief. Since before he could walk, he was instructed to do so. Grow up, do well in school, get into a good university, then work for a safe company. If you do all this, you will live a happy life, and your family and society will recognize you for all your hard work, the perfect Blue narrative. Unfortunately, life is more complex than this.&lt;/p&gt;
&lt;p&gt;If whoever is in this position (and we may recognize parts of ourselves upon reading this) was to step outside of themselves and listen to what our partner has told us, we might receive a piece of our puzzle towards understanding where we are. &lt;em&gt;Self-deception is the default state of mind for many of us&lt;/em&gt;, and more often than not, when we’re enlightened to how our behaviors are &lt;strong&gt;actually&lt;/strong&gt; perceived by others, things can get ugly. One would hope in situations like these, that we would sit down with our partner and attempt to understand their point of view. Easier said than done.&lt;/p&gt;
&lt;h2&gt;Better language = better communication&lt;/h2&gt;
&lt;p&gt;Whether you decide to make Spiral an object of study or another tool/framework, learning these models can lead to much happier outcomes for everyone involved. The more words we have to describe something, the more nuanced our perception of the “something” becomes. A great example is emotions. We could very quickly say we feel “good” if we’re not particularly versed in the thousands of subtle expressions for positive feelings. But, this doesn’t communicate much. Instead, we could dig deeper into our current state of awareness, how our body and mind feel, and might reply with, “tranquil”. It is still a positive emotion (many would perceive “tranquil” as a “good” emotion to feel); however, this translates MUCH more information to whomever we’re speaking.&lt;/p&gt;
&lt;p&gt;The same is true when getting feedback from those around you. You may have heard, “You’re the average of the five people you spend most of your time with.” This forms one of the core principles around &lt;a href="https://spirals.blog/articles/building-environment/"&gt;building an environment&lt;/a&gt;. What if a core group understood and used “psycho-technologies” like Spiral, took responsibility for their emotions and actions, and devoted themselves to their growth and yours?&lt;/p&gt;
&lt;p&gt;I learned much of what I know and use today in a large group like this. They were &lt;em&gt;instrumental&lt;/em&gt; in supporting my understanding of myself and growth as an individual. The more people are involved, the more perspectives you can draw from. By sharing a language the enables better communication, one can ask many different types of people profound questions and receive equally considered responses. If all understand the tools, models, and frameworks, you receive more pieces to your jigsaw (provided you’re asking the right questions).&lt;/p&gt;
&lt;h3&gt;Check who you’re asking&lt;/h3&gt;
&lt;p&gt;One caveat with this approach to consider is, “What is this person’s perspective?”. In other words, how are they filtering you through &lt;em&gt;&lt;strong&gt;their&lt;/strong&gt;&lt;/em&gt; filters? Do they have many years studying themselves and others, or are they just beginning their journey of growth? What is the intention of this person in answering questions or giving advice?&lt;/p&gt;
&lt;p&gt;These are critical considerations, as good intentions are &lt;strong&gt;not&lt;/strong&gt; the same as “in-perspective” responses. For example, one might ask their spouse/parent/sibling for advice on how to move forward with a situation at work. This person may have our best interests at heart, however, is not in our industry, and is unaware of the relationship we have with our boss. They’ll attempt to offer &lt;em&gt;something&lt;/em&gt; (as many do), drawing from their own experiences, values, and beliefs, but we must take this advice with a grain of salt. Are you the same person as them? Is your boss? Do you work in the same role, at the same company, experiencing the same problem? Chances are, no.&lt;/p&gt;
&lt;p&gt;A tool like Spiral Dynamics allows us to translate context by looking at the &lt;a href="https://spirals.blog/articles/structure-vs-content/"&gt;structure, NOT the content&lt;/a&gt;. We can break problems spaces down, assessing things like color structures, beliefs, patterns, filters, values, etc. of those involved. When looking at situations from this angle, it enables us to recognize patterns and similarities between different &lt;em&gt;contexts&lt;/em&gt;, even though the &lt;em&gt;content&lt;/em&gt; is different. This is only possible if everyone is speaking the same language.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Your people" src="http://spirals.blog/articles/getting-to-know-your-own-perspective-part-1/people.jpg" /&gt;
&lt;em&gt;Photo by Alexis Brown @alexisrbrown&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Find your people&lt;/h2&gt;
&lt;p&gt;We conclude the first part of this “Getting to know your own perspective” series. In &lt;a href="https://spirals.blog/articles/getting-to-know-your-own-perspective-part-2/"&gt;Part 2&lt;/a&gt;, we’ll look at &lt;em&gt;how&lt;/em&gt; we can go about attempting to piece the puzzle together with some practical exercises and examples.&lt;/p&gt;
&lt;p&gt;For now, we can use this as an opportunity to reflect. Who do we have around us that we talk to about what’s &lt;em&gt;really&lt;/em&gt; going on? Are we speaking the same language? Do we share tools, practices, and models to deepen our communication and level of understanding?&lt;/p&gt;
&lt;p&gt;If not, how could you? Who do you know in your life that would be open to having vulnerable, honest conversations? Is there someone who knows you genuinely and has your best interests at heart? Are there people in your life you could introduce to Spiral or other tools? (Be careful with this) Perhaps there’s someone you haven’t spoken to in a while. If you’re coming up blank for some of these questions, try “leading” a conversation. You never know who may be feeling the same way.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/getting-to-know-your-own-perspective-part-1/</guid></item><item><title>Unicode support. What does that actually mean? 😃</title><link>https://boyter.org/posts/unicode-support-what-does-that-actually-mean/</link><description>&lt;p&gt;Unicode support in my experience seems to be one of those hand wavy things where most people respond to the question of &amp;ldquo;Do you support unicode?&amp;rdquo; with&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yeah we support emojis, so yes we support unicode! 😃😭😈&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which is partially correct&amp;hellip; It&amp;rsquo;s certainly a good start. However unicode is more than emojis.&lt;/p&gt;
&lt;p&gt;So lets take a step back. What is unicode? It&amp;rsquo;s actually easy to explain, here it is taken from the wiki page &amp;ldquo;A standard for representing the worlds text&amp;rdquo;. That means it includes all the languages in the world, such as chinese characters, japanese writing systems, arabic and even nordic runes. As such you get all sorts of interesting things in the standard such as characters that display as white space but actually are not because they represent a nordic rune carved on the &lt;a href="https://www.youtube.com/watch?v=2yWWFLI5kFU"&gt;side of the stone not visible from the front&lt;/a&gt;.&lt;/p&gt;</description><author>Ben E. C. Boyter</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://boyter.org/posts/unicode-support-what-does-that-actually-mean/</guid></item><item><title>wav-nn: Generating wav files with a neural network</title><link>https://michael-lewis.com/posts/wav-nn-generating-wav-files-with-a-neural-network/</link><description>&lt;h2 id="introduction"&gt;
  Introduction
  &lt;a class="heading-link" href="#introduction"&gt;
    &lt;i class="fa-solid fa-link" title="Link to heading"&gt;&lt;/i&gt;
    &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
  &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;This post is about a project to generate wav files with a neural network. These are files with the audio in the waveform domain, i.e. as sound samples such as that which might be converted to mp3 files. I had hoped to be able to generate some form of music, but both training and generation are proving too processor intensive at the moment, so I&amp;rsquo;m going to write up what I have for the time being and perhaps revisit in a few years.&lt;/p&gt;</description><author>Michael Ian Lewis</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://michael-lewis.com/posts/wav-nn-generating-wav-files-with-a-neural-network/</guid></item><item><title>Generating a full-stack application from a database</title><link>http://notes.eatonphil.com/generating-a-full-stack-application-from-a-database.html</link><description>&lt;p&gt;&lt;a href="https://dbcore.org"&gt;DBCore&lt;/a&gt; can now generate a TypeScript/React CRUD
UI that is automatically hooked up to the generated REST API (in Go).&lt;/p&gt;
&lt;p&gt;The UI has full support for login, viewing (and filtering), editing,
and creating database entities.&lt;/p&gt;
&lt;p&gt;PostgreSQL, SQLite and MySQL are supported.&lt;/p&gt;
&lt;h3 id="how-to-use?"&gt;How to use?&lt;/h3&gt;&lt;p&gt;The goal of this project is primarily to provide as much useful
boilerplate as possible for full-stack applications. The system is
probably not sufficient to be an entire application development
platform. It's currently missing hooks, overrides, and
per-row/per-table authorization.&lt;/p&gt;
&lt;p&gt;The UI code generation may be even less useful in the long-term than
the API because UIs are by necessity very diverse. But it is good not
to need to build the same browser-side API, authentication, and
routing logic again now that it's taken care of in code generation.&lt;/p&gt;
&lt;h3 id="screenshots"&gt;Screenshots&lt;/h3&gt;&lt;p&gt;Here are a few screenshots of the examples/todo application. Every
page here is auto-generated after reading the database schema. The
browser application is hooked up to the similarly auto-generated API.&lt;/p&gt;
&lt;div style="padding-bottom: 15px;"&gt;
  &lt;small&gt;Sign in&lt;/small&gt;
  &lt;img src="https://i.imgur.com/1ReEEdf.png" style="border: 1px solid #ddd;" /&gt;
&lt;/div&gt;
&lt;div style="padding-bottom: 15px;"&gt;
  &lt;small&gt;Creating a table entity&lt;/small&gt;
  &lt;img src="https://i.imgur.com/AiryzjX.png" style="border: 1px solid #ddd;" /&gt;
&lt;/div&gt;
&lt;div style="padding-bottom: 15px;"&gt;
  &lt;small&gt;Viewing all table entities&lt;/small&gt;
  &lt;img src="https://i.imgur.com/l9jI0LA.png" style="border: 1px solid #ddd;" /&gt;
&lt;/div&gt;
&lt;div style="padding-bottom: 15px;"&gt;
  &lt;small&gt;Filtering table entities&lt;/small&gt;
  &lt;img src="https://i.imgur.com/J21vQDE.png" style="border: 1px solid #ddd;" /&gt;
&lt;/div&gt;
&lt;div style="padding-bottom: 15px;"&gt;
  &lt;small&gt;Viewing an individual table entity&lt;/small&gt;
  &lt;img src="https://i.imgur.com/T2VhBFt.png" style="border: 1px solid #ddd;" /&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;small&gt;Editing a table entity&lt;/small&gt;
  &lt;img src="https://i.imgur.com/f2sRN1p.png" style="border: 1px solid #ddd;" /&gt;
&lt;/div&gt;&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;What's new in DBCore: a TypeScript/React UI generated from your database schema and hooked up to the similarly generated Go REST API.&lt;br /&gt;&lt;br /&gt;So you can now generate an entire full stack application from your database schema. Screenshots in the post.&lt;a href="https://t.co/BTGRVBsfUR"&gt;https://t.co/BTGRVBsfUR&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1272295312900661250?ref_src=twsrc%5Etfw"&gt;June 14, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sun, 14 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/generating-a-full-stack-application-from-a-database.html</guid></item><item><title>Less responsibilities for algorithm-driven civil servants?</title><link>https://stop.zona-m.net/2020/06/less-responsibilities-for-algorithm-driven-civil-servants/</link><description>&lt;p&gt;Why have such servants, then?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 13 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/less-responsibilities-for-algorithm-driven-civil-servants/</guid></item><item><title>How to Use Garmin's Workouts Feature on your GPS Running Watch</title><link>https://www.mikekasberg.com/blog/2020/06/13/how-to-use-garmin-workouts.html</link><description>&lt;p&gt;I’ve been a runner for most of my life, running track and cross country in both
high school and college. Many years ago now, I got my first GPS running watch
and I came to love all the data it provides for my runs. Recently, I figured out
how to use the “Workouts” feature on my Garmin fēnix watch, and I absolutely
love it! I think more people should know about it, so I decided to write this
blog.&lt;/p&gt;

&lt;h2 id="what-is-it"&gt;What is it?&lt;/h2&gt;

&lt;p&gt;The Workouts feature is a way to program a running workout on one of Garmin’s
GPS running watches. I’m using it on my fēnix 5s, but the feature also exists on
most other Garmin running watches including the new fēnix 6 and the Forerunner
series. It’s great because this feature helps you set up workouts that might
normally need a track (like 400m repeats) – but you don’t need a track. You can
go run a track workout on your favorite trail. And there are options besides
just distance – you can configure most workouts you could think up pretty
easily.&lt;/p&gt;

&lt;h2 id="how-do-you-use-it"&gt;How do you use it?&lt;/h2&gt;

&lt;p&gt;Although it can be hard to find and figure out the Workouts feature, it’s pretty
simple once you know where to look and how it works.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Workouts menu in the app" src="https://www.mikekasberg.com/images/how-to-use-garmin-workouts/workouts-menu.jpg" /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Open the Garmin Connect app on your phone.&lt;/li&gt;
  &lt;li&gt;Go to “Workouts” under the training menu.&lt;/li&gt;
  &lt;li&gt;Hit the button to Create a Workout, and choose “Run” (or whichever other type
of workout you want to create).&lt;/li&gt;
  &lt;li&gt;Add workout steps and repeats. Click on any step to edit it. Long-press and
drag on the move icon to rearrange.&lt;/li&gt;
  &lt;li&gt;When you’re finished, save the workout, and then tap the button in the top
right to sync it to your watch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img alt="Workout designer" src="https://www.mikekasberg.com/images/how-to-use-garmin-workouts/workouts-designer.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;When you’re ready to do the workout, start your watch in run mode like normal.
Once you’re in run mode, but before you start the time, long-press the menu
button on your watch. Select “Training”, then select “My Workouts”. Find the
workout you want and hit “Do Workout”. Your watch will run the workout for you,
using the distance, time, or lap-button settings you chose when designing the
workout in the app. So awesome!&lt;/p&gt;

&lt;p&gt;A few other tips:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You can also design workouts on the &lt;a href="https://connect.garmin.com/"&gt;Garmin
Connect&lt;/a&gt; website and they’ll
appear in your app. This is nice because the website UI is easier to use.&lt;/li&gt;
  &lt;li&gt;You can design workouts for other sport types too, including run, bike, swim,
strength, cardio, yoga, pilates, and custom.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you found this little tutorial useful, and I hope you like the feature as much as I do!&lt;/p&gt;</description><author>Mike Kasberg's Blog</author><pubDate>Sat, 13 Jun 2020 20:45:00 GMT</pubDate><guid isPermaLink="true">https://www.mikekasberg.com/blog/2020/06/13/how-to-use-garmin-workouts.html</guid></item><item><title>Hammerspoon: Toggl API Calls and Secret Tokens</title><link>http://evantravers.com/articles/2020/06/13/hammerspoon-toggl-api-calls-and-secret-tokens/</link><description>&lt;p&gt;Ok… I'm really excited to show you the tool in the &lt;em&gt;next&lt;/em&gt; post, but some context has to be laid first.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#toggl" id="toggl"&gt;&lt;/a&gt;Toggl&lt;/h2&gt;
&lt;p&gt;I've experimented with &lt;a href="https://toggl.com/"&gt;toggl&lt;/a&gt; for time tracking on and off for over a year now. My current methodology is lifted and modified from CGPGrey's comments in &lt;a href="https://overcast.fm/+E7b4QJN1U/1:03:54"&gt;Cortex Ep. 101&lt;/a&gt;. To summarize his thoughts…&lt;/p&gt;
&lt;p&gt;Grey is &lt;em&gt;always&lt;/em&gt; running a timer, usually from &lt;a href="https://timeryapp.com/"&gt;Timery on iOS&lt;/a&gt;. He uses the act of choosing a timer as a &lt;em&gt;moment of intention&lt;/em&gt;: &amp;quot;what am I intending to do?&amp;quot; He retroactively marks time spent unintentionally (e.g. ending up on social media instead of writing) as &amp;quot;bad.&amp;quot; Periodically he will check the reports in Toggl, using the color coding to judge how much time he is spending on what moves the needle.&lt;/p&gt;
&lt;p&gt;I &lt;strong&gt;really&lt;/strong&gt; like the idea of timing as a means of intentionality. I haven't been timing my whole day, but the past month or two I've been experimenting with using time tracking next to my &lt;a href="/articles/2020/05/09/creating-a-focus-budget/"&gt;Focus Budget&lt;/a&gt;. I've isolated a few work activities that I highly value, and I'm attempting to graph how much time per week I spend on those high-value activities.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="a pie graph, showing mostly light blue (shallow) and a little dark blue (deep)" src="https://images.evantravers.com/articles/2020/06/toggl_report.png" /&gt;
  &lt;figcaption&gt;
    &lt;p&gt;Here is last week's report from toggl... light blue is things like meetings and time spent in slack/email. Dark blue is the activities I've decided will "move the needle."&lt;/p&gt;
    &lt;p&gt;I have a lot of room to grow. 🙇&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And of course, this lends itself to automation, so I started writing a toggl.lua. (I was really surprised I couldn't find anything on github!) So it's time to hit some REST APIs with Hammerspoon!&lt;/p&gt;
&lt;p&gt;An &lt;a href="https://github.com/evantravers/hammerspoon-config/commit/0e3170842e63f1c34e89139d3ef3c38d44c51fca#diff-951f5c0c2d38d9d86b671b2860fa3b7a"&gt;earlier version of this module&lt;/a&gt; used the &lt;code&gt;curl&lt;/code&gt; executable, but once again Hammerspoon's handy stdlib has a &lt;code&gt;hs.http&lt;/code&gt; library that works perfectly.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start_timer&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;project_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;description&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;local&lt;/span&gt; &lt;span&gt;key&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;asyncPost&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;https://www.toggl.com/api/v8/time_entries/start&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;encode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'time_entry'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'description'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;description&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'pid'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;project_id&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'created_with'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'hammerspoon'&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;application/json; charset=UTF-8&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;[&lt;/span&gt;&lt;span&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;quot;Basic &amp;quot;&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;base64&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;encode&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;key&lt;/span&gt; &lt;span&gt;..&lt;/span&gt; &lt;span&gt;&amp;quot;:api_token&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;http_number&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;body&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;headers&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;http_number&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;body&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Between &lt;code&gt;hs.json&lt;/code&gt; and &lt;code&gt;hs.base64&lt;/code&gt;, writing a simple toggl client was really fun and easy!&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; I wrote some other functions, but they pretty much all follow the same structure.&lt;/p&gt;
&lt;p&gt;Now I have the ability to start, stop, and view the current timer from within my Hammerspoon setup!&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#handling-secrets-via-json" id="handling-secrets-via-json"&gt;&lt;/a&gt;Handling secrets via json&lt;/h2&gt;
&lt;p&gt;As I got into writing the code for toggl.lua, I realized I needed an easy way to get secrets like API keys into memory. I started with a simple file loading system, then realized that &lt;code&gt;hs.json&lt;/code&gt; is &lt;em&gt;perfect&lt;/em&gt; for this.&lt;/p&gt;
&lt;p&gt;Here is the &lt;strong&gt;entire&lt;/strong&gt; module.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;module&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;secrets&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;read&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;.secrets.json&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;return&lt;/span&gt; &lt;span&gt;module&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yep. Isn't that beautiful? I could add some error handling for when the file doesn't exist and such, but it's simple enough. As it is, it supports inserting a nested table into &lt;code&gt;hs.settings&lt;/code&gt; that you can access from &lt;em&gt;any&lt;/em&gt; module.&lt;/p&gt;
&lt;p&gt;Here's an example of a .secrets.json for my uses...&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-json" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;standupURL&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;http://evantravers.com&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;standupCall&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;https://meet.google.com/respect-op-sec&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;quot;toggl&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;key&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;lt;my key&amp;gt;&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;quot;projects&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;communications&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;meetings&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;planning&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;reading&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;design&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;research&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;play&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;leadership&amp;quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt; &lt;span&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can access any of these keys using dot notation... like:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hs.settings.get('secret').toggl.key&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To wrap that up and add some error handling, I have some small abstractions like this one:&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;key&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;secrets&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toggl&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;key&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;return&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;settings&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;secrets&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toggl&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;key&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;print&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;You need to load a Toggl.com API key in to hs.settings under secrets.toggl.key&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;hs.settings&lt;/code&gt; is a cool little module for some shared state. It's even persistent between sessions if you want.&lt;/p&gt;
&lt;p&gt;Well… we are nearly at the finish line. If you are still reading these posts, thanks. I'm glad there's another person who cares. I have been so excited to share the next idea with y'all…&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;I should say… I &lt;em&gt;really&lt;/em&gt; dislike lua as a language, but the two modules I've written here almost make me like it a little. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Sat, 13 Jun 2020 16:38:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/06/13/hammerspoon-toggl-api-calls-and-secret-tokens/</guid></item><item><title>Quantum mechanics explained</title><link>https://diffxweyl.wordpress.com/2020/06/12/quantum-mechanics-explained/</link><description>After being a strong believer in the many-worlds interpretation of quantum mechanics for years, I have now completely changed my mind. Many-worlds is seriously flawed, and the good old Copenhagen interpretation is not so bad. Specifically, the correct interpretation of quantum mechanics is the Von Neumann-Wigner interpretation, a flavor of Copenhagen that puts the Heisenberg &amp;#8230; &lt;a class="more-link" href="https://diffxweyl.wordpress.com/2020/06/12/quantum-mechanics-explained/"&gt;Continue reading&lt;span class="screen-reader-text"&gt; "Quantum mechanics explained"&lt;/span&gt;&lt;/a&gt;</description><author>diff × weyl</author><pubDate>Sat, 13 Jun 2020 06:46:16 GMT</pubDate><guid isPermaLink="true">https://diffxweyl.wordpress.com/2020/06/12/quantum-mechanics-explained/</guid></item><item><title>I got 99 problems, but that's better than one</title><link>https://faingezicht.com/articles/2020/06/13/chunks/</link><description>&lt;small&gt;&lt;em&gt;Este ensayo también está disponible &lt;a href="/articles/2020/06/14/chunks-es/"&gt;en español&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;

Breaking up big problems into a series of smaller independent tasks is one of the most valuable skills in project management. This is true in many fields, but thanks to the power of abstraction and modularity, it is especially powerful in software engineering, where small components can be built in separate settings and tested piecemeal as they are integrated into a larger whole. 

This past week I found myself pointing out the value of breaking down tasks upfront to several of my coworkers, so I put together a short list of pros and cons. On one hand, organizing big projects with many moving pieces as a sequence of intermediate dependent tasks...

* **Keeps you focused**, reducing the number of things you need to juggle at once. There's no point in keeping a task top of mind today if you know you can't work on it until another piece is done. This is related to the basic concepts of &lt;a href="https://en.wikipedia.org/wiki/Lean_manufacturing"&gt;lean manufacturing&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Kanban"&gt;kanban&lt;/a&gt;, which most software engineers are familiar as precursors to &lt;a href="https://en.wikipedia.org/wiki/Agile_software_development"&gt;agile&lt;/a&gt;.
* **Defines a clear path to the goal**. It's much easier to understand the project as a whole by understanding sub-tasks. This is related to the psychology concept called &lt;a href="https://en.wikipedia.org/wiki/Chunking_(psychology"&gt;chunking&lt;/a&gt;).
* **Provides better effort estimates**. &lt;a href="https://en.wikipedia.org/wiki/Hofstadter%27s_law"&gt;Hofstadter's law&lt;/a&gt; will always be there, but it is easier to identify how much time is required to do each small task, reducing the overall variance of your estimates.
* **Gives you an intrinsic sense of accomplishment** as the project progresses. A single big ominous ticket hangs over your head, not done, but it is easier to stay motivated when you can check items off the to-do list as you go along. 
* **Allows you to show incremental progress externally**. At your next stakeholder meeting, when the other team's manager asks if the project is finished you can point to the list of subtasks, and instead of saying it's not done you can say you are 7/10 of the way there.
* **Enables collaboration**. If you've done the legwork to chunk tasks into self-contained pieces it's easier to hand off bits to peers who have a spare cycle or two. 

On the other:

* It **takes time and effort**. Every minute spent organizing a project into smaller pieces is time spent PMing, not building your product. The smaller the project, and the smaller the team working on it, the less need there is for in-depth project management. Importantly, time spent on this kind of work _feels_ productive and can easily turn into &lt;a href="https://en.wikipedia.org/wiki/Law_of_triviality"&gt;bikeshedding&lt;/a&gt;, so you should err on the side of cutting the task breakdown process short.
* It gives us a **false sense of certainty**. The task list should act as a guide. You don't know what you don't know, and there might be hidden work that you won't see until you hit a roadblock. Some tasks you initially thought would be necessary might become irrelevant later on, and others that you thought were separate are actually tightly coupled. The team must stay flexible, changing tasks from your initial set, expecting them to evolve as the project unfolds.

Identifying self-contained chunks is really hard, but it is a worthwhile skill to hone. It often boils down to gut feeling and pattern matching, so I am not advocating for a specific way of going about the process of breaking down tasks, but instead arguing for the value of front-loading it. Tasks are fuzzy, and often bleed into each other. Whether you dedicate time upfront to organize your project into small tasks, or instead implicitly define tasks on the fly as you chip away at the larger whole, every project requires chunking. Considering you have to do it anyway, why not front load it and get the additional benefits listed above?

&lt;hr /&gt;

&lt;small&gt;&lt;em&gt;Photo: Catan Board, Bad Aussee, Austria, by me. Previously posted on &lt;a href="/photos/2020/01/25/europa-iii/"&gt;Europa III, Bad Aussee MMXX&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;</description><author>Avy Faingezicht</author><pubDate>Sat, 13 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/articles/2020/06/13/chunks/</guid></item><item><title>Reducing Friction: Making products that stick</title><link>https://rajeevnaruka.com/blog/reducing-friction</link><description>As a product designer, you goal is to reduce friction your users experience on every step of using your product. Help them make that decision.</description><author>Rajeev Singh Naruka</author><pubDate>Sat, 13 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://rajeevnaruka.com/blog/reducing-friction</guid></item><item><title>Progress Is Hard</title><link>https://martinrue.com/progress-is-hard/</link><description>Today wasn't a failure because I've not reached those states. It was a success because I've followed the process – a process that accrues results over time. I'll be back tomorrow for my next batch.</description><author>Martin Rue</author><pubDate>Sat, 13 Jun 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://martinrue.com/progress-is-hard/</guid></item><item><title>On real radicals, and polarization</title><link>https://stop.zona-m.net/2020/06/on-real-radicals-and-polarization/</link><description>&lt;p&gt;I &amp;rsquo;ve just come across something I first heard in the mid 90&amp;rsquo;s&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 12 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/on-real-radicals-and-polarization/</guid></item><item><title>Reading Pseudogrammars</title><link>https://peterlyons.com/problog/2020/06/reading-pseudogrammars/</link><description>&lt;p&gt;In my software development work, I encounter new syntaxes truly almost every day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;lt;grumplezone&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It's a gripe for me that our contemporary way of working introduces a huge new ecosystem of commands every 6 months.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We're on AWS, here's the CLI with 3 dozen subcommands you'll need to learn.&lt;/li&gt;
&lt;li&gt;Oops, sorry it's GCP now. A lot of similar stuff but the CLI is completely distinct.&lt;/li&gt;
&lt;li&gt;Oh yeah it's kubernetes so there's a huge YAML grammar.&lt;/li&gt;
&lt;li&gt;Wait, no it's helm charts which have a grammar built on the kubernetes grammar but also golang templating which you should also learn now.&lt;/li&gt;
&lt;li&gt;Oh wait helm is terrible, we're using kustomize instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&amp;lt;/grumplezone&amp;gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is usually command line program arguments, but sometimes it's file syntax or structured data in a common syntax. This means I read a lot of man pages and similar documentation. One thing I struggle with is the pseudogrammar block often found at the top of such documentation. For example, here's the pseudogrammar for the &lt;code&gt;COPY&lt;/code&gt; command in &lt;code&gt;Dockerfile&lt;/code&gt; syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;COPY [--chown=&amp;lt;user&amp;gt;:&amp;lt;group&amp;gt;] &amp;lt;src&amp;gt;... &amp;lt;dest&amp;gt;
COPY [--chown=&amp;lt;user&amp;gt;:&amp;lt;group&amp;gt;] [&amp;quot;&amp;lt;src&amp;gt;&amp;quot;,... &amp;quot;&amp;lt;dest&amp;gt;&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My old habit would be to skip straight past that as noise and look for examples. When I see examples, I can immediately and with no conscious cognitive effort derive what the syntax is. I guess this comes from decades of using command line programs but when I see&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;count-floopers --mode terse projects&amp;#x2f;blog&amp;#x2f;settings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I don't think "Oh dang, it only works on json files at that particular relative path, let me make some directories and move my json file around so the path matches". I also infer there's other possible values for &lt;code&gt;--mode&lt;/code&gt; and it's an enum of string names. Thus I usually reach for examples but I want to get better at actually parsing and grokking the pseudogrammar.&lt;/p&gt;
&lt;p&gt;So for the Dockerfile COPY example above, here's how I'd slowly break it down in my mind.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OK it seems like square brackets are indicating optional stuff and angle brackets mean required
&lt;ul&gt;
&lt;li&gt;This is somewhat conventional but not in a rigorous or consistent way. For example, I'm pretty sure the group identifier is optional but there's not a nested pair of brackets indicating that.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;So there's a long-form option &lt;code&gt;--chown&lt;/code&gt; and it takes user and group separate by colon
&lt;ul&gt;
&lt;li&gt;BUT because there's no example I have no idea if those need to be names or numbers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Then comes a required src argument which I infer must be a filesystem path&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;...&lt;/code&gt; means there can be more than 1 &amp;lt;src&amp;gt; argument and I presume they are space separated and delivered as distinct entries in the underlying&lt;code&gt;argv&lt;/code&gt; array.&lt;/li&gt;
&lt;li&gt;Then comes a required &amp;lt;dest&amp;gt; which I have to infer from context (which I probably don't have if I'm just learning this command) that this is a filesystem path inside the docker image filesystem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I guess I managed to grok this one, but it's pseudogrammar was pretty small. When I start to see pipe symbols. For the next few pseudogrammars I encounter, I'm going to practice reading slowly character-by-character and writing out in long form what I think each element denotes. Hopefully with a little practice I'll become more fluent in grokking these.&lt;/p&gt;</description><author>Pete's Points</author><pubDate>Fri, 12 Jun 2020 18:57:21 GMT</pubDate><guid isPermaLink="true">https://peterlyons.com/problog/2020/06/reading-pseudogrammars/</guid></item><item><title>Hammerspoon: Handling Windows and Layouts</title><link>http://evantravers.com/articles/2020/06/12/hammerspoon-handling-windows-and-layouts/</link><description>&lt;p&gt;One of the main things people do with Hammerspoon is wrangle their window layouts. There is a &lt;em&gt;lot&lt;/em&gt; of awesome Hammerspoon code to help you with that, from &lt;a href="https://github.com/scottwhudson/Lunette/"&gt;clones of popular Mac applications like Spectacle&lt;/a&gt; to &lt;a href="http://www.hammerspoon.org/docs/hs.window.tiling.html"&gt;complex tiling systems&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While ten years ago I would have leapt for the tiling options&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; (I still would like to give i3wm a go one of these days!) I have been making an effort to only have one application in view at any given time. I used to think multitasking was a super power of mine, now I think it's my kryptonite.&lt;/p&gt;
&lt;p&gt;In my configuration, &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/be5c9284b02f2e509d53385a73e778ba7505532b/movewindows.lua"&gt;movewindows.lua&lt;/a&gt; isn't very complex or interesting, and a lot of it was written originally by &lt;a href="https://twitter.com/tbmiller"&gt;Tom Miller&lt;/a&gt;. While much of movewindows.lua is very simple, there are two automations that I'm proud of.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#split-screen-easily" id="split-screen-easily"&gt;&lt;/a&gt;Split screen easily&lt;/h2&gt;
&lt;p&gt;I work on a laptop monitor a lot, and even at my nice setup at my desk I try to keep my main monitor on a single app. One app, one task, single focus.&lt;/p&gt;
&lt;p&gt;There is one use case where I'll commonly have two windows open… one to work on, the other for reference. Sometimes it's &lt;a href="https://kapeli.com/dash"&gt;Dash.app&lt;/a&gt;, some other reference material, or a ticket.&lt;/p&gt;
&lt;p&gt;The process usually goes like this.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Be me, full screened on my work.&lt;/li&gt;
&lt;li&gt;Realize I need some reference material.&lt;/li&gt;
&lt;li&gt;Go find that material, open it up full screen.&lt;/li&gt;
&lt;li&gt;Flip back and forth (efficiently using &lt;a href="/articles/2020/06/08/hammerspoon-a-better-better-hyper-key/"&gt;hyper.lua&lt;/a&gt;!) a few times before realizing that I need them both at the same time.&lt;/li&gt;
&lt;li&gt;Switch to my work, enter move mode, move it to the left. (&lt;code&gt;HYPER+m, h&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Switch to my reference, enter move mode, move it to the right. (&lt;code&gt;HYPER+m, l&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Realizing just how common this particular use case is, and inspired by how easy it is to split a screen in vim using &lt;a href="https://github.com/junegunn/fzf.vim"&gt;fzf.vim&lt;/a&gt;, I wrote a function to make my life easier.&lt;/p&gt;
&lt;p&gt;Here's what it looks like in action.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls="controls" poster="https://images.evantravers.com/articles/2020/06/split.png" src="https://images.evantravers.com/articles/2020/06/split.mov"&gt;&lt;/video&gt;
  &lt;figcaption&gt;
    &lt;p&gt;Hitting &lt;code&gt;HYPER+m&lt;/code&gt; allows me to enter my window movement modal. It is sort of a leader key... I then hit `v` to enter my split window chooser, then I choose the window I want alongside my "work" window and everything is ready to go!&lt;/p&gt;
    &lt;p&gt;It even maintains the focus on my work. I can just keep typing.&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Let's walk though the code... while it's not terribly complex, it's a good example of the powerful tools Hammerspoon gives you to build your own automations.&lt;/p&gt;
&lt;p&gt;First we set up the modal and bind it to our old friend Hyper.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;movewindows&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;hotkey&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;modal&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'m'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;movewindows&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;enter&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we create a specific binding for the movewindows modal for hitting the letter &lt;code&gt;v&lt;/code&gt;. I've considered switching it to the same bindings I'm used to in vim, but this will do.&lt;/p&gt;
&lt;p&gt;I get all the windows open, and build a lua table of them to pass to the &lt;code&gt;hs.chooser&lt;/code&gt; object. I don't include the currently focused window, because it's the &amp;quot;work&amp;quot; window.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;movewindows&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;''&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'v'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; function&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;local&lt;/span&gt; &lt;span&gt;windows&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;fnutils&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;filter&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;getWindows&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;win&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;win&lt;/span&gt; &lt;span&gt;~=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;focusedWindow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;return&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;text&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;win&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;subText&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;win&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;image&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;image&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;imageFromAppBundle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;win&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bundleID&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;id&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;win&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Armed with this table of open windows, I setup up the chooser. &lt;code&gt;hs.chooser&lt;/code&gt; (&lt;a href="https://www.hammerspoon.org/docs/hs.chooser.html"&gt;docs&lt;/a&gt;) provides a simple fuzzy-finder that is really great at filtering to what you want very quickly. If I choose a window, it uses &lt;code&gt;hs.layout&lt;/code&gt; to layout the windows, and raises &lt;code&gt;toRead&lt;/code&gt; to the foreground without focusing it... this is really nice when I'm still trying to type in my &amp;quot;work&amp;quot; window, I don't have to refocus it.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;  &lt;span&gt;local&lt;/span&gt; &lt;span&gt;chooser&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;chooser&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;choice&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;choice&lt;/span&gt; &lt;span&gt;~=&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;local&lt;/span&gt; &lt;span&gt;layout&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;local&lt;/span&gt; &lt;span&gt;focused&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;focusedWindow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;local&lt;/span&gt; &lt;span&gt;toRead&lt;/span&gt;  &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;window&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;choice&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;id&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;if&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventtap&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;checkKeyboardModifiers&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;'alt'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;focused&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;focused&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;left70&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;toRead&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;focused&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;right30&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;focused&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;focused&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;left50&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;          &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;toRead&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;focused&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;right50&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;toRead&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;raise&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing left to do but show the &lt;code&gt;hs.chooser&lt;/code&gt;. I add some placeholder text to remind myself hotkeys for the interface, make sure that I can search the &lt;code&gt;subText&lt;/code&gt; (which in this case is the application name,) and show the chooser, and exit the modal.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;chooser&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;:&lt;/span&gt;&lt;span&gt;placeholderText&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Choose window for 50/50 split. Hold ⎇ for 70/30.&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;:&lt;/span&gt;&lt;span&gt;searchSubText&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;:&lt;/span&gt;&lt;span&gt;choices&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;windows&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;:&lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;movewindows&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;exit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(abridged from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/be5c9284b02f2e509d53385a73e778ba7505532b/movewindows.lua"&gt;movewindows.lua&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;I use this more than I thought I would, it turned out that most of my window moving was simply to bring two things close together for comparison or reference. It's a &lt;em&gt;very&lt;/em&gt; small thing, but it brings me a lot of joy.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#autolayout-on-docking-or-undocking-the-laptop" id="autolayout-on-docking-or-undocking-the-laptop"&gt;&lt;/a&gt;Autolayout on docking or undocking the laptop&lt;/h2&gt;
&lt;p&gt;After using my basic keys for moving windows around, I realized the main use case for me was setting up my windows on my two monitors after docking my laptop.&lt;/p&gt;
&lt;p&gt;If I'm on one screen, I want everything full screened, and I switch between them using hyper shortcuts. If I have two screens, I want work right in front of me, and distraction/calendaring applications off to the side. Inspired by &lt;a href="https://github.com/megalithic/dotfiles/tree/be5c9284b02f2e509d53385a73e778ba7505532b/hammerspoon"&gt;Seth Messer's config&lt;/a&gt;, I wrote a simplified &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/be5c9284b02f2e509d53385a73e778ba7505532b/autolayout.lua"&gt;autolayout.lua&lt;/a&gt; system.&lt;/p&gt;
&lt;p&gt;Once again, we return to my &lt;code&gt;config&lt;/code&gt; variable in init.lua. Using the same &lt;code&gt;applications&lt;/code&gt; table as hyper, we add a new key/value pair for &lt;code&gt;preferred_display&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;applications&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'com.brave.Browser'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;bundleID&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'com.brave.Browser'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;preferred_display&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;1&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that in place, it's pretty simple to iterate over the list in autolayout.lua, getting the windows and moving them to the monitor that I prefer.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;autolayout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;autoLayout&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;for&lt;/span&gt; &lt;span&gt;_&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;app_config&lt;/span&gt; &lt;span&gt;in&lt;/span&gt; &lt;span&gt;pairs&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;applications&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;-- if we have a preferred display&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;app_config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;preferred_display&lt;/span&gt; &lt;span&gt;~=&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;application&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app_config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;bundleID&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;if&lt;/span&gt; &lt;span&gt;application&lt;/span&gt; &lt;span&gt;~=&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt; &lt;span&gt;and&lt;/span&gt; &lt;span&gt;application&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;mainWindow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;~=&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;application&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;:&lt;/span&gt;&lt;span&gt;mainWindow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;:&lt;/span&gt;&lt;span&gt;moveToScreen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;autolayout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;target_display&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app_config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;preferred_display&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;false&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;true&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;:&lt;/span&gt;&lt;span&gt;moveToUnit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;layout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;maximized&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While I can trigger &lt;code&gt;autolayout.autolayout()&lt;/code&gt; manually using a hyper key, I set up a watcher that fires when the number of monitors change. (This brilliant idea is also courtesy of Seth!) This means that when I dock or undock my laptop, instead of spending the next two minutes getting everything set up &lt;em&gt;just&lt;/em&gt; the way I like it, my Hammerspoon butler kindly sweeps away all the windows to their proper place every time.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;autolayout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config_table&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;module&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;config&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;config_table&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;watcher&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;new&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;if&lt;/span&gt; &lt;span&gt;num_of_screens&lt;/span&gt; &lt;span&gt;~=&lt;/span&gt; &lt;span&gt;#&lt;/span&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;allScreens&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;autolayout&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;autoLayout&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;num_of_screens&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;#&lt;/span&gt;&lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;screen&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;allScreens&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of this shows a little bit of what I have been calling meta-automation. Having the power to automate little things like moving a window back and forth gives me the ability to recognize the larger &amp;quot;UX&amp;quot; patterns at play and directly meta-automate them. It's the difference between asking myself &amp;quot;what am I doing right now?&amp;quot; and realizing &amp;quot;what am I trying to accomplish?&amp;quot;&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;love&lt;/em&gt; tinkering with this higher-order automation... it's more thoughtful an exciting, and I can't wait to show you what I've been building up to with these posts. This is all going somewhere... I promise!&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;Some of you may be wondering why I do all this instead of tiling... I have a &lt;em&gt;very&lt;/em&gt; specific use case. I want all windows up and full screened, able to transition without a OS X spaces animation. hyper.lua handles that. If I want to compare, I have my movewindows.lua &lt;code&gt;split&lt;/code&gt; function. I think if I use a tiling function, I'd lose the ability to quickly switch... but maybe not. I may be just reinventing the wheel, but it's &lt;em&gt;my&lt;/em&gt; wheel! &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;Outcomes over outputs... &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Fri, 12 Jun 2020 17:04:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/06/12/hammerspoon-handling-windows-and-layouts/</guid></item><item><title>Random roundup for 2020-06-12</title><link>https://rjp.is/blogging/posts/2020/06/friday-12/</link><description>Various things, links, and excitement.</description><author>infrequent oscillations</author><pubDate>Fri, 12 Jun 2020 11:38:09 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/06/friday-12/</guid></item><item><title>Adding comments system to this website</title><link>https://ciesie.com/post/comments_isso/</link><description>&lt;p&gt;I&amp;rsquo;ve started this website with the &lt;em&gt;Beautiful Hugo&lt;/em&gt; theme. At that point in time I was learning
how &lt;em&gt;Hugo&lt;/em&gt; works. I knew I wanted to design my own theme, only because I like customizing and
designing. The theme I&amp;rsquo;m currently using was designed and written by me. I&amp;rsquo;m not a web developer
so it&amp;rsquo;s not professional quality. It&amp;rsquo;s made by me - that&amp;rsquo;s what matters. I&amp;rsquo;ve never implemented a
comments system in my own theme. That has recently changed! This website doesn&amp;rsquo;t generate, what
people in this lovely place called &amp;ldquo;internet&amp;rdquo; call, traffic. This doesn&amp;rsquo;t change a thing though.
The goal was always to share what I&amp;rsquo;ve learned. Some problems don&amp;rsquo;t deserve to be solved twice.
If I&amp;rsquo;ve struggled with something silly, you shouldn&amp;rsquo;t. What if you struggle with something I didn&amp;rsquo;t
consider to be problematic? Then you should be able to easily ask me about it. That&amp;rsquo;s the reason
why introducing comment system seemed to be worth my time.&lt;/p&gt;</description><author>ciesie.com</author><pubDate>Fri, 12 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://ciesie.com/post/comments_isso/</guid></item><item><title>Quest for the authentic thukpa</title><link>/2020/06/12/quest-for-the-authentic-thukpa.html</link><description>It was a fine September morning as I reached Leh, more than 9 years after my last visit. As most of the establishments in Leh had closed before the onset of winter, I decided to look for accommodation close to the main market. After about an hour of walking around, I found a decent budget hotel (Mehak) to stay at the start of Changspa Road. By the time I checked in, I was feeling hungry and really wanted to have some local food for lunch.</description><author>Over the Hills</author><pubDate>Fri, 12 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">/2020/06/12/quest-for-the-authentic-thukpa.html</guid></item><item><title>4 Q&amp;amp;A's on Blogging for Developers</title><link>https://www.swyx.io/4-q-a-s-on-blogging-for-developers-lc9</link><description>Answering Q&amp;amp;A's</description><author>swyx's site RSS Feed</author><pubDate>Fri, 12 Jun 2020 02:17:37 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/4-q-a-s-on-blogging-for-developers-lc9</guid></item><item><title>Hammerspoon: Automating Airpods and Brave Browser</title><link>http://evantravers.com/articles/2020/06/11/hammerspoon-automating-airpods-and-brave-browser/</link><description>&lt;p&gt;As I continue to document my Hammerspoon configuration, I'm going to expand on &lt;a href="/articles/2020/06/08/hammerspoon-a-better-better-hyper-key/"&gt;hyper.lua&lt;/a&gt; and dive into a couple of modules with simple functionality I access &lt;em&gt;with&lt;/em&gt; hyper: brave.lua and airpods.lua.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#bravelua-automating-my-browser" id="bravelua-automating-my-browser"&gt;&lt;/a&gt;Brave.lua: automating my browser&lt;/h2&gt;
&lt;p&gt;I have been using the Brave Browser for a while… I wanted to not give Google any more information than it already has… I wanted to use Firefox and not give WebKit more market share, but Firefox doesn't have automation hooks.&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; 🤷🏻‍♂️&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/47ed1c909c70ce1100bb7b0da5776de330480dbc/brave.lua"&gt;brave.lua module&lt;/a&gt; is pretty simple, and has two parts: The first, a couple of JXA scripts for manipulating the tabs of the brave browser. The second, some helper methods for accessing parts of the configuration table I provide in init.lua.&lt;/p&gt;
&lt;p&gt;To set up brave.lua, you require it and pass in any configuration you have setup.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;domains&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'twitter.com'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;url&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'twitter.com'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;tags&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'#distraction'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'#socialmedia'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;brave&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'brave'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;brave&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Configuring the domains is optional, but makes using some of the functions easier.&lt;/p&gt;
&lt;p&gt;Now you have access to brave's functions. The original reason I wrote it is because I often end up using Google Meet. Unlike Zoom, Meet usually runs in a browser tab. I had become used to pressing &lt;code&gt;HYPER+z&lt;/code&gt; to focus Zoom to unmute when someone mentioned me, and I wanted the same functionality in Google Meet.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'z'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;brave&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;jump&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;meet.google.com|hangouts.google.com.call&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;figure&gt;
  &lt;video controls="controls" poster="https://images.evantravers.com/articles/2020/06/brave_demo.png" src="https://images.evantravers.com/articles/2020/06/brave_demo.mov"&gt;&lt;/video&gt;
  &lt;figcaption&gt;
    &lt;p&gt;
      My new "jump to video button" in action. &lt;code&gt;F19&lt;/code&gt; here is the hotkey that triggers my Hyper modal. No matter which window, which tab, it always focuses the right window and the right tab. 👍
    &lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This is a cool UX hack… my muscle memory is used to pressing this key to &amp;quot;jump to the video chat,&amp;quot; and now it is consistent no matter which app I'm using.&lt;/p&gt;
&lt;p&gt;In fact, my current iteration supports the same key for either zoom, google meet, or google hangouts…&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;-- Jump to google hangout or zoom&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'z'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'us.zoom.xos'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launchOrFocusByBundleID&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'us.zoom.xos'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;brave&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;jump&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;&amp;quot;meet.google.com|hangouts.google.com.call&amp;quot;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(From &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/a85100b1389b10c83a9e63eb279a2c83561b1784/init.lua#L181-L188"&gt;init.lua&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;One key, and I always focus the video window when someone asks me a question. 👌&lt;/p&gt;
&lt;p&gt;&lt;code&gt;brave.jump()&lt;/code&gt; uses some JXA that I believe I adapted from some AppleScript I found somewhere and rewrote. You can read the whole thing &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/a85100b1389b10c83a9e63eb279a2c83561b1784/brave.lua#L17-L34"&gt;here&lt;/a&gt;. If nothing else, this highlights Hammerspoon's power to run random scripts based on your environment or input.&lt;/p&gt;
&lt;p&gt;I use the exact same technique for a couple other things… I have a key that either focuses Figma.app, the Figma.com website, or Lucidchart (because sometimes I forget I use that.) It's basically a &amp;quot;show me my visual design&amp;quot; button. It's great!&lt;/p&gt;
&lt;p&gt;There are some additional features in brave.lua that will be fleshed out in later posts.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#airpodslua" id="airpodslua"&gt;&lt;/a&gt;airpods.lua&lt;/h2&gt;
&lt;p&gt;This is a small trick but I use it &lt;em&gt;all&lt;/em&gt; the time. When I started on this, there was not a good way to connect your AirPods to your computer with a single keypress. I think there's at least three menubar applications now on the App Store, but &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/47ed1c909c70ce1100bb7b0da5776de330480dbc/airpods.lua"&gt;mine is free&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I found some AppleScript by &lt;a href="https://gist.github.com/daGrevis/"&gt;@daGrevis&lt;/a&gt; that connects AirPods, wired it up in a lua module, require and specify the name of my AirPods, and connected it to my Hyper modal layer described earlier. That simple.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;local&lt;/span&gt; &lt;span&gt;airpods&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;airpods&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'a'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;local&lt;/span&gt; &lt;span&gt;ok&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;output&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;airpods&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;toggle&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'Evan’s AirPods'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;if&lt;/span&gt; &lt;span&gt;ok&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;alert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;output&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;alert&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Couldn't connect to AirPods!&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;a class="anchor" href="#bonus-snip-browser-highlight-to-drafts-as-a-simple-markdown-zettelkasten" id="bonus-snip-browser-highlight-to-drafts-as-a-simple-markdown-zettelkasten"&gt;&lt;/a&gt;Bonus: Snip browser highlight to Drafts as a Simple Markdown Zettelkasten&lt;/h2&gt;
&lt;p&gt;A lot of my &lt;a href="/articles/2020/03/13/simple-markdown-zettelkasten/"&gt;simple markdown zettelkasten&lt;/a&gt; starts as something that I'm reading in a browser. While Drafts.app provides a &lt;em&gt;lovely&lt;/em&gt; integrated share function if you are using Safari, if you are using Brave (for reasons shared above!) you have to do something different.&lt;/p&gt;
&lt;p&gt;When Drafts.app opened up a simple AppleScript api, I could finally do this. This requires enabling an option in Brave: &lt;code&gt;View -&amp;gt; Developer -&amp;gt; Allow Javascript from Apple Events&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;-- Snip current highlight in Brave&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'s'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;osascript&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;applescript&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;[[
&lt;/div&gt;&lt;div class="line"&gt;    -- stolen from: https://gist.github.com/gabeanzelini/1931128eb233b0da8f51a8d165b418fa
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    if (count of theSelectionFromBrave()) is greater than 0 then
&lt;/div&gt;&lt;div class="line"&gt;      set str to &amp;quot;tags: #link\n\n&amp;quot; &amp;amp; theTitleFromBrave() &amp;amp; &amp;quot;\n\n&amp;gt; &amp;quot; &amp;amp; theSelectionFromBrave() &amp;amp; &amp;quot;\n\n[&amp;quot; &amp;amp; theTitleFromBrave() &amp;amp; &amp;quot;](&amp;quot; &amp;amp; theCurrentUrlInBrave() &amp;amp; &amp;quot;)&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;      tell application &amp;quot;Drafts&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;        make new draft with properties &amp;amp;lbracecontent:str, tags: &amp;amp;lbrace&amp;quot;link&amp;quot;&amp;amp;rbrace&amp;amp;rbrace
&lt;/div&gt;&lt;div class="line"&gt;      end tell
&lt;/div&gt;&lt;div class="line"&gt;    end if
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    on theCurrentUrlInBrave()
&lt;/div&gt;&lt;div class="line"&gt;      tell application &amp;quot;Brave Browser&amp;quot; to get the URL of the active tab in the first window
&lt;/div&gt;&lt;div class="line"&gt;    end theCurrentUrlInBrave
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    on theSelectionFromBrave()
&lt;/div&gt;&lt;div class="line"&gt;      tell application &amp;quot;Brave Browser&amp;quot; to execute front window's active tab javascript &amp;quot;getSelection().toString();&amp;quot;
&lt;/div&gt;&lt;div class="line"&gt;    end theSelectionFromBrave
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;    on theTitleFromBrave()
&lt;/div&gt;&lt;div class="line"&gt;      tell application &amp;quot;Brave Browser&amp;quot; to get the title of the active tab in the first window
&lt;/div&gt;&lt;div class="line"&gt;    end theTitleFromBrave
&lt;/div&gt;&lt;div class="line"&gt;  ]]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;notify&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;show&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;quot;Snipped!&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;The snippet has been sent to Drafts&amp;quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/a85100b1389b10c83a9e63eb279a2c83561b1784/init.lua#L199-L226"&gt;init.lua&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Here's what the script builds if I highlight a paragraph in this article.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-markdown" tabindex="0"&gt;&lt;div class="line"&gt;tags: #link
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;Hammerspoon: Automating Airpods and Brave Browser
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;When Drafts.app opened up a simple AppleScript api, I could finally do this. This requires enabling an option in Brave: View -&amp;gt; Developer -&amp;gt; Allow Javascript from Apple Events.
&lt;/div&gt;&lt;div class="line"&gt;&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;[Hammerspoon: Automating Airpods and Brave Browser](http://evantravers.com/articles/2020/06/11/hammerspoon-automating-airpods-and-brave-browser/)
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I keep these in a Workspace in Drafts to process later, either saving to disk or sending to friends.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;That I can find… If you know of any, let me know! &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Thu, 11 Jun 2020 21:38:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/06/11/hammerspoon-automating-airpods-and-brave-browser/</guid></item><item><title>Building Class Data Sharing Archives with Apache Maven</title><link>https://www.morling.dev/blog/building-class-data-sharing-archives-with-apache-maven/</link><description>&lt;div class="toc" id="toc"&gt;
&lt;div id="toctitle"&gt;Table of Contents&lt;/div&gt;
&lt;ul class="sectlevel1"&gt;
&lt;li&gt;&lt;a href="#_manually_creating_cds_archives"&gt;Manually Creating CDS Archives&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_using_the_cds_archive"&gt;Using the CDS Archive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_creating_cds_archives_in_your_maven_build"&gt;Creating CDS Archives in Your Maven Build&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_what_do_you_gain"&gt;What Do You Gain?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#_wrap_up"&gt;Wrap-Up&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;Ahead-of-time compilation (AOT) is &lt;em&gt;the&lt;/em&gt; big topic in the Java ecosystem lately:
by compiling Java code to native binaries, developers and users benefit from vastly improved start-up times and reduced memory usage.
The &lt;a href="https://www.graalvm.org/"&gt;GraalVM&lt;/a&gt; project made huge progress towards AOT-compiled Java applications,
and &lt;a href="https://mail.openjdk.java.net/pipermail/discuss/2020-April/005429.html"&gt;Project Leyden&lt;/a&gt; promises to standardize AOT in a future version of the Java platform.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;This makes it easy to miss out on significant performance improvements which have been made on the JVM in recent Java versions,
in particular when it comes to &lt;a href="https://cl4es.github.io/2019/11/20/OpenJDK-Startup-Update.html"&gt;faster start-up times&lt;/a&gt;.
Besides a range of improvements related to class loading, linking and bytecode verification,
substantial work has been done around &lt;a href="https://docs.oracle.com/en/java/javase/14/vm/class-data-sharing.html"&gt;class data sharing&lt;/a&gt; (CDS).
Faster start-ups are beneficial in many ways:
shorter turnaround times during development,
quicker time-to-first-response for users in coldstart scenarios,
cost savings when billed by CPU time in the cloud.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="paragraph"&gt;
&lt;p&gt;With CDS, class metadata is persisted in an archive file,
which during subsequent application starts is mapped into memory.
This is faster than loading the actual class files, resulting in reduced start-up times.
When starting multiple JVM processes on the same host, read-only archives of class metadata can also be shared between the VMs, so that less memory is consumed overall.&lt;/p&gt;
&lt;/div&gt;</description><author>Gunnar Morling</author><pubDate>Thu, 11 Jun 2020 18:30:00 GMT</pubDate><guid isPermaLink="true">https://www.morling.dev/blog/building-class-data-sharing-archives-with-apache-maven/</guid></item><item><title>Install docker and docker-compose using Ansible</title><link>https://srijan.ch/install-docker-and-docker-compose-using-ansible</link><description>Optimized way to install docker and docker-compose using Ansible</description><author>Srijan Choudhary, all posts</author><pubDate>Thu, 11 Jun 2020 17:30:00 GMT</pubDate><guid isPermaLink="true">https://srijan.ch/install-docker-and-docker-compose-using-ansible</guid></item><item><title>The scam of flying taxis is back</title><link>https://stop.zona-m.net/2020/06/the-scam-of-flying-taxis-is-back/</link><description>&lt;p&gt;Flying to defeat traffic? Really?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 11 Jun 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/the-scam-of-flying-taxis-is-back/</guid></item><item><title>StrongSwan VPN setup</title><link>http://mihai.fm/strongswan-vpn-setup</link><author>mihai.fm</author><pubDate>Thu, 11 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://mihai.fm/strongswan-vpn-setup</guid></item><item><title>Crossing the Bridge</title><link>https://faingezicht.com/photos/2020/06/11/bridge/</link><description>For Memorial Day weekend, we went on a hike that made it up for months of being locked down in our apartment. Hannah and I walked all the way from our apartment in the Mission to Kirby Cove and back, picking up our friend Nikhil a few miles in, near the Haight. Without thinking too much about it, we ended up doing a 21 mile day.

My feet hated me for it.</description><author>Avy Faingezicht</author><pubDate>Thu, 11 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://faingezicht.com/photos/2020/06/11/bridge/</guid></item><item><title>Mobile Device Frames For Excalidraw</title><link>https://francoisbest.com/posts/2020/mobile-device-frames-for-excalidraw?utm_source=rss</link><description>Building mobile UI mockups in Excalidraw is a lot of fun, but eye-balling screen ratios is not great. Here are some free resources to help you get started, and a guide on how to make your own frames.</description><author>Articles by François Best</author><pubDate>Thu, 11 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://francoisbest.com/posts/2020/mobile-device-frames-for-excalidraw?utm_source=rss</guid></item><item><title>Reproducible workspace deployment with Ansible and Vagrant</title><link>https://jiby.tech/post/reproducible-workspace-ansible-vagrant/</link><description>&lt;p&gt;Like many developers, I keep track of my configuration files in
version control, to make moving to new machines is simpler and share
code with others. This process started out for my Emacs config files
at first, but grew to consume other aspects: bash functions, git
aliases&amp;hellip; Since 2016, I have accumulated over &lt;a href="https://github.com/OverkillGuy/jibyconf"&gt;500 git commits&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now the &lt;a href="https://dotfiles.org"&gt;dotfiles&lt;/a&gt; are tracked, the next biggest pain is to install
packages and folder structures and obscure commands required to set up
some subsystems needs which config files. Wouldn&amp;rsquo;t it be nice to have
an all-in-one setup?&lt;/p&gt;</description><author>Jiby's toolbox</author><pubDate>Thu, 11 Jun 2020 02:32:00 GMT</pubDate><guid isPermaLink="true">https://jiby.tech/post/reproducible-workspace-ansible-vagrant/</guid></item><item><title>An intro to Go for non-Go developers</title><link>https://benhoyt.com/writings/go-intro/</link><description>A brief introduction to Go for programmers who haven't used Go before: Why use it? The standard library. And the language itself.</description><author>Ben Hoyt's technical writing</author><pubDate>Wed, 10 Jun 2020 14:38:00 GMT</pubDate><guid isPermaLink="true">https://benhoyt.com/writings/go-intro/</guid></item><item><title>THIS... is Italy (*)</title><link>https://stop.zona-m.net/2020/06/this...-is-italy/</link><description>&lt;p&gt;and not just Italy, of course.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 10 Jun 2020 07:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/this...-is-italy/</guid></item><item><title>Sketch</title><link>https://blog.kaetemi.be/2020/06/10/sketch/</link><description/><author>Kaetemi</author><pubDate>Wed, 10 Jun 2020 03:54:00 GMT</pubDate><guid isPermaLink="true">https://blog.kaetemi.be/2020/06/10/sketch/</guid></item><item><title>Race in CS1</title><link>http://acbart.github.io//2020/06/10/race-in-cs1/</link><description>Last week, I posted on the SIGCSE-Members listserv asking for guidance on supporting black students in CS1. I have been meaning to ask for that guidance for a while, ever since I analyzed the data from my CS1 class last fall and was disappointed to find that I was not doing enough to support this subgroup. Given the current crisis facing America, and spurred by a related post on the listserv, I was motivated to finally ask for help.</description><author>Acbart ePortfolio</author><pubDate>Wed, 10 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://acbart.github.io//2020/06/10/race-in-cs1/</guid></item><item><title>The Individual &amp;amp; The Collective</title><link>http://spirals.blog/articles/i-vs-we/</link><description>&lt;h2&gt;The Great Pendulum&lt;/h2&gt;
&lt;p&gt;If you’ve studied Spiral Dynamics for long enough, you may have noticed that a pattern forms between the colors. Beige looks out for itself, and Purple looks out for the tribe/family/friends. Red looks for glory and significance and Blue looks to sacrifice itself for a higher power (organization, nation, religion, etc.). Orange does whatever it can to be the best and look good doing it, only for Green to forget it all and only looks out for the world. And so on…&lt;/p&gt;
&lt;p&gt;What can we notice in the above? Is there anything that stands out particularly around the intentions of each of these? If you think about it hard enough, you may notice it shifts from thinking about “Me!” vs. thinking about “Us.” It moves back and forth between the expression of the individual and the sacrifice to the collective. Combined with increasing complexity, this oscillation is what creates the “Spiral” in Spiral Dynamics.&lt;/p&gt;
&lt;h2&gt;Warm and Cool&lt;/h2&gt;
&lt;p&gt;Generally speaking, we divide each stage of Spiral into either “cool,” representing the “We/Collective/Sacrifice-self” perspective, or “warm” for the “I/Individual/Express-self” perspective.&lt;/p&gt;
&lt;h3&gt;“Cooler/Feminine” colors&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Purple: Sacrifice self for the tribe&lt;/li&gt;
&lt;li&gt;Blue: Sacrifice self for society/god/ideal&lt;/li&gt;
&lt;li&gt;Green: Sacrifice self for the world/environment&lt;/li&gt;
&lt;li&gt;Turquoise: Sacrifice self for the collective consciousness&lt;/li&gt;
&lt;li&gt;???&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;“Warmer/Masculine” colors&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Beige: Express self to survive&lt;/li&gt;
&lt;li&gt;Red: Express self for power/significance&lt;/li&gt;
&lt;li&gt;Orange: Express self to win&lt;/li&gt;
&lt;li&gt;Yellow: Express self without harming others&lt;/li&gt;
&lt;li&gt;???&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The distinction between these two modes of operating becomes clear when laid out like this. The “I” intentions seek to express themselves, discover new things, shatter barriers set by others, and overcome obstacles. “We” tends to harmonize with the group, creating order and structure, and wholeheartedly attempts to put the group’s interests before its own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which is right or wrong?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For the astute student of Spiral, we know that this question doesn’t apply. Self-expression and Self-sacrifice form two sides of the same coin – Yin and Yang. We cannot live in a society with only self-expression as nobody would collaborate, and nothing would get done. Conversely, a world where everyone self-sacrificed would not last long as nobody would break the status-quo or discover anything new. The “I” and the “We” form a sacred relationship underlying many natural patterns we see in the world around us.&lt;/p&gt;
&lt;h2&gt;Why does this occur?&lt;/h2&gt;
&lt;p&gt;The pendulum pattern emerges from how “I” and “We” solve problems in fundamentally different ways.&lt;/p&gt;
&lt;h3&gt;Shift into “I”&lt;/h3&gt;
&lt;p&gt;“I” individuals and societies are driven by a strong desire to “break-out” of their current reality. They are often the people in an organization trying to find a novel way to approach something. A culture focused on “freedom of expression”. A movement oriented to moving the world forwards. A great example of this is the Purple -&amp;gt; Red transition.&lt;/p&gt;
&lt;p&gt;After living in Purple for a period, some realize (some never do) there is a whole world out there. They discover that the weekly rain dances the shaman involves everyone in are not working, but the tribe down near the river has unlimited water. So, they venture outside of Purple, taking further risks and journeys each time. The “Entering Red” becomes known for their bravery, courage, and sense of adventure. Not to mention they solved the tribe’s water problem. Over time, they find they enjoy this newfound attention, partaking more dangerous/adventurous/bigger things to impress more people around them. The Purple tribe looks up to these new Reds as leaders and protectors (Red protects Purple in many ways), and thus the Chief/Warlord/Shaman/Warrior is born.&lt;/p&gt;
&lt;p&gt;The Red seeks (from sheer boredom, or external conditions like a warring neighbor) to do more. The safety Purple creates frees up mental space for Red to think about other things. Living in a community where everyone is part of a whole is excellent, but an “I” will feel left out if they don’t have room for themselves. This cognitive dissonance creates a mechanic that pushes the individual away from the collective, thus creating a new color.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Shift into “We”&lt;/h3&gt;
&lt;p&gt;How does this process look going the other way? “We” individuals or groups are motivated by the needs of the many. Cooler colors align themselves to ideas/movements/deities larger than themselves and bind others to their cause. We see this manifested in the diligent company worker who works away at whatever task given to him, in the name of the company (Blue). The caring mother who would, without a seconds hesitation, forgo her dinner so that her children might eat (Purple). An activist who &lt;em&gt;refuses&lt;/em&gt; to unchain herself from the tree because, for her, the forest the Orange wants to cut down is home to thousands of animals. Without her, they have no voice.&lt;/p&gt;
&lt;p&gt;Let’s look at an example of a Red -&amp;gt; Blue transition to illustrate a shift from “I” to “We”. A man on a small island in Central America loved snorkeling. He formed a small business, specializing in adventure travel. He would take curious tourists out on boats to go snorkeling. All was well for many years, and his company grew in popularity. What started as a way for the owner to “get paid doing what he loved” soon started getting out of hand. He had no accounting system, no-one at the store to greet customers when he was out on the water and didn’t comprehend the legal implications of what he was doing. After an intimidating letter from the taxman, he decided to enlist the help of his other friends in the business.&lt;/p&gt;
&lt;p&gt;Things got very complicated very quickly. He had to train up his new employees on how to correctly use the snorkeling equipment,  safety instructions, the accountant was asking him for receipts from 2 years ago, and everyone had questions. After a few months, he barely had any time himself to do what he loved; go snorkeling. The business was booming, reviews were rolling in on travel blogs, his employees were working towards his idea, and yet somehow he felt he’d made a mistake.&lt;/p&gt;
&lt;p&gt;Blue is an excellent solution to solving the chaos that Red can create. As we saw in the example above, some are not quite ready for a transition (perhaps you’ve witnessed this in yourself or someone close to you). Cooler colors step in to “organize the mess” that the “I”  ’s create. “We” will standardize, harmonize, and attempt to get everyone and everything on the same page. In “We” all of us sacrifice ourselves for something more meaningful than any one of us individually. We work towards the same goal/idea. Theoretically.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Yin and Yang" src="http://spirals.blog/articles/i-vs-we/yin-yang.png" /&gt;&lt;/p&gt;
&lt;h2&gt;More transitions&lt;/h2&gt;
&lt;p&gt;In this article, we briefly looked at the Purple -&amp;gt; Red (“We” to “I”) and Red -&amp;gt; Blue (“I” to “We”) transitions, but there are many more! Spiral is non-linear, meaning that individuals/groups don’t necessarily move from Purple to Red, then Red to Blue, Blue to Orange, and so on. It is entirely plausible for a Purple to shift into Orange, Green into Purple, and Red into Green. Any shift between colors will create a transition, massively transforming the values, behaviors, beliefs, etc. of anyone involved.&lt;/p&gt;
&lt;p&gt;Knowing all this, perhaps you can view some of your transitions, looking back on your life. Was it a shift from traveling the world to settling down and getting a job (Red -&amp;gt; Blue)? Maybe you grew up in an overly religious family and decided, as soon as you were able, to leave home and move to a fun city (Blue -&amp;gt; Red). For some, it might have looked like quitting your stable job and throwing caution to the wind for an entrepreneurial venture (Blue -&amp;gt; Orange). Whatever the case, studying our personal history can provide valuable insights into our structures and Spiral Dynamics as a whole.&lt;/p&gt;
&lt;p&gt;Next time you experience someone/thing operating a little differently to how YOU would handle the situation, stop, and think. “What’s their intention?”. If you’re more “I”, embracing the power of your group can give you much-needed feedback on how you’re behaving. If you tend to more “We”, the self-expressive perspectives can assist in making you feel more confident, creative, and assertive.&lt;/p&gt;
&lt;p&gt;Like all good things in life, the “I/We” dichotomy is about balance. To simplify, too much I and you’ll piss people off; too much “We” and you’ll get walked over. Striking a balance between these two opposing forces (that live in all of us), will shape you into a well-rounded person, capable of dealing with more situations and people. We naturally tend to one or the other, and working to even these out can have life-changing effects.&lt;/p&gt;
&lt;p&gt;So what are you waiting for? Studying Spiral doesn’t end when the article does. It begins when we apply it to ourselves. What side of the coin do we find ourselves on? How can we balance between self-expression and self-sacrifice even further?&lt;/p&gt;
&lt;p&gt;Where on your Spiral do you need to work?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Cover photo by &lt;a href="http://www.paulwainwrightphotography.com/"&gt;Paul Wainwright&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Wed, 10 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/i-vs-we/</guid></item><item><title>Surprise, surprise: Smart Appliances are a stupid idea</title><link>https://stop.zona-m.net/2020/06/surprise-surprise-smart-appliances-are-a-stupid-idea/</link><description>&lt;p&gt;Really, who could have imagined it?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 09 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/surprise-surprise-smart-appliances-are-a-stupid-idea/</guid></item><item><title>Inaction is a Form of Action</title><link>https://locusmag.com/2020/01/cory-doctorow-inaction-is-a-form-of-action/</link><description>&lt;p&gt;Cory Doctorow, in &lt;a href="https://locusmag.com/2020/01/cory-doctorow-inaction-is-a-form-of-action/"&gt;&lt;em&gt;Inaction is a Form of Action&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;It’s tempting to simply laugh off these &amp;#8216;free market&amp;#8217; fetishists as they get their comeuppance when Alex Jones and the Daily Stormer get kicked off the internet, but that is to miss the wider point: we are now in a speech environment where power is so concentrated that the whims of a half-dozen tech execs determine&amp;#160;&amp;#8212;&amp;#160;for all intents and purposes&amp;#160;&amp;#8212;&amp;#160;who may speak and what they may say. If you think that power will only be wielded against Alex Jones, there’s a bunch of trans activists, indigenous activists, anti-pipeline activists, #BlackLivesMatter activists, and others who’d like to have a word with you.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://zacs.site/blog/lightning-round-04dec19.html"&gt;Back in December&lt;/a&gt;, I applauded Mark Zuckerberg for continuing to push back on demands that Facebook clamp down on its users&amp;#8217; speech. As I said there, &amp;#8220;The idea that [Facebook] should also [, in addition to commanding an unprecedented amount of the world&amp;#8217;s time and attention, ] become the arbiter of truth boggles my mind.&amp;#8221; Cory Doctrow, in &lt;a href="https://locusmag.com/2020/01/cory-doctorow-inaction-is-a-form-of-action/"&gt;&lt;em&gt;Inaction is a Form of Action&lt;/em&gt;&lt;/a&gt;, does a great job explaining why this disturbing trend ought to concern you.&lt;/p&gt;


                &lt;p&gt;&lt;a href="https://locusmag.com/2020/01/cory-doctorow-inaction-is-a-form-of-action/"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Tue, 09 Jun 2020 16:22:39 GMT</pubDate><guid isPermaLink="true">https://locusmag.com/2020/01/cory-doctorow-inaction-is-a-form-of-action/</guid></item><item><title>Devlog #1: fixed timestep</title><link>https://domwillia.ms/devlog1</link><description>I cover the core game loop, why a fixed timestep is required and how it's implemented, topped off with a glorious comparison gif.</description><author>Dom Williams</author><pubDate>Tue, 09 Jun 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://domwillia.ms/devlog1</guid></item><item><title>Building mataroa.blog</title><link>https://nutcroft.mataroa.blog/blog/building-mataroa-blog/</link><description>&lt;p&gt;This article is about building &lt;a href="https://mataroa.blog/"&gt;mataroa.blog&lt;/a&gt;, a minimal blogging platform with export as a first-class feature, built with Python and Django.&lt;/p&gt;
&lt;p&gt;According to git, I started the &lt;a href="https://git.sr.ht/~sirodoht/mataroa/"&gt;mataroa repo&lt;/a&gt; on May 27th, 2020, 20:37 UTC, just a few hours after my friend &lt;a href="https://www.stavros.io/"&gt;Stavros&lt;/a&gt; sent me the link of &lt;a href="https://bearblog.dev/"&gt;Bear Blog&lt;/a&gt;. We thought it was genius —Bear Blog— and I decided to make something similar, mainly because I would enjoy building it. &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id="rss"&gt;RSS&lt;/h2&gt;
&lt;p&gt;After submitting to HN, the first comment I got was that the lack of RSS was a dealbreaker. Heartbreak. Quickly rushed to implement it. It took 47 minutes for the implementation, testing, and UI polishing.&lt;/p&gt;
&lt;p&gt;The reason for this speed lies in Django having an excellent built-in "syndication-feed-generating framework". It's very simple to acquire basic functionality:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/feeds.py&lt;/span&gt;
&lt;span style="color: #CB4B16;"&gt;from&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;django.contrib.syndication.views&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt; &lt;span style="color: #657B83;"&gt;Feed&lt;/span&gt;
&lt;span style="color: #CB4B16;"&gt;from&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;django.http&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt; &lt;span style="color: #657B83;"&gt;Http404&lt;/span&gt;

&lt;span style="color: #CB4B16;"&gt;from&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;main&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;


&lt;span style="color: #859900;"&gt;class&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;RSSBlogFeed&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(Feed):&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;title&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;Blog&amp;quot;&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;link&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;description&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;Cool blog resides here&amp;quot;&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;items&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;Post&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;objects&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;filter()&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;order_by(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;-created_at&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;item_title&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;item):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;item&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;title&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;item_description&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;item):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;item&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;body&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/urls.py&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;urlpatterns&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;[&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;path(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;rss/&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;feeds&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;RSSBlogFeed(),&lt;/span&gt; &lt;span style="color: #657B83;"&gt;name&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;rss_feed&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;),&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But, that didn't work for mataroa as it returns all (across all blogs) posts.
We wanted to get only those that were from the subdomain requested.&lt;/p&gt;
&lt;p&gt;After looking into the &lt;a href="https://github.com/django/django/blob/3a6fa1d962ad9bd5678290bc22dd35bff13eb1f5/django/contrib/syndication/views.py#L29"&gt;extremely readable&lt;/a&gt; Django source code of the &lt;code&gt;Feed&lt;/code&gt; class, the following addition was made in the &lt;code&gt;RSSBlogFeed&lt;/code&gt; class.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;__call__&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;request,&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;*&lt;/span&gt;&lt;span style="color: #657B83;"&gt;args,&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;**&lt;/span&gt;&lt;span style="color: #657B83;"&gt;kwargs):&lt;/span&gt;
    &lt;span style="color: #93A1A1;"&gt;# check that user requests a subdomain (non-bare domain) site&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;if&lt;/span&gt; &lt;span style="color: #859900;"&gt;not&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;hasattr&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(request,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;subdomain&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;raise&lt;/span&gt; &lt;span style="color: #657B83;"&gt;Http404()&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;user&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;User&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;objects&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;get(username&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;subdomain)&lt;/span&gt;
    &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;title&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;user&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;blog_title&lt;/span&gt;
    &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;subdomain&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;subdomain&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;super&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(RSSBlogFeed,&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;__call__&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(request,&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;*&lt;/span&gt;&lt;span style="color: #657B83;"&gt;args,&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;**&lt;/span&gt;&lt;span style="color: #657B83;"&gt;kwargs)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We want the request object, because &lt;code&gt;subdomain&lt;/code&gt; resides in there. Based on that, we have the user (which means we have the blog title too) and finally we can define the queryset:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;items&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;Post&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;objects&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;filter(owner__username&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;subdomain)&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;order_by(&lt;/span&gt;
        &lt;span style="color: #2AA198;"&gt;&amp;quot;-created_at&amp;quot;&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="models"&gt;Models&lt;/h2&gt;
&lt;p&gt;These are mataroa's Django models.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/models.py&lt;/span&gt;
&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;markdown&lt;/span&gt;
&lt;span style="color: #CB4B16;"&gt;from&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;django.conf&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt; &lt;span style="color: #657B83;"&gt;settings&lt;/span&gt;
&lt;span style="color: #CB4B16;"&gt;from&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;django.contrib.auth.models&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt; &lt;span style="color: #657B83;"&gt;AbstractUser&lt;/span&gt;
&lt;span style="color: #CB4B16;"&gt;from&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;django.db&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;
&lt;span style="color: #CB4B16;"&gt;from&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;django.urls&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #CB4B16;"&gt;import&lt;/span&gt; &lt;span style="color: #657B83;"&gt;reverse&lt;/span&gt;


&lt;span style="color: #859900;"&gt;class&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;User&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(AbstractUser):&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;about&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;TextField(blank&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;True&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;null&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;True&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;blog_title&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;CharField(max_length&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;500&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;get_absolute_url&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;reverse(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;user_detail&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;kwargs&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #657B83;"&gt;{&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;pk&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;:&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;pk})&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;__str__&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;username&lt;/span&gt;


&lt;span style="color: #859900;"&gt;class&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;Post&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;Model):&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;title&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;CharField(max_length&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;300&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;slug&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;CharField(max_length&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;300&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;body&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;TextField(blank&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;True&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;null&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;True&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;owner&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;ForeignKey(User,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;on_delete&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;CASCADE)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;created_at&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;DateTimeField(auto_now_add&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;True&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;updated_at&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;DateTimeField(auto_now&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;True&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;class&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;Meta&lt;/span&gt;&lt;span style="color: #657B83;"&gt;:&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;ordering&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;[&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;-created_at&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;]&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;unique_together&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;[[&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;owner&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;]]&lt;/span&gt;

    &lt;span style="color: #268BD2;"&gt;@property&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;as_markdown&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;markdown&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;markdown(&lt;/span&gt;
            &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;body,&lt;/span&gt;
            &lt;span style="color: #657B83;"&gt;extensions&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #657B83;"&gt;[&lt;/span&gt;
                &lt;span style="color: #2AA198;"&gt;&amp;quot;markdown.extensions.fenced_code&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt;
                &lt;span style="color: #2AA198;"&gt;&amp;quot;markdown.extensions.tables&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt;
            &lt;span style="color: #657B83;"&gt;],&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;)&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;get_absolute_url&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;path&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;reverse(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;post_detail&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;kwargs&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #657B83;"&gt;{&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;slug&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;:&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;slug})&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;f&amp;quot;//{&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;owner&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;username&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}.{&lt;/span&gt;&lt;span style="color: #657B83;"&gt;settings&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;CANONICAL_HOST&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}{&lt;/span&gt;&lt;span style="color: #657B83;"&gt;path&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}&amp;quot;&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;__str__&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;title&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;2 models, 46 lines.&lt;/p&gt;
&lt;p&gt;The first idea towards simplicity here was that there's no need for Blog to be a separate model. It was a given that the User model would be overriden, and having multiple blogs under one user would be out of scope. Thus, why not just add &lt;code&gt;blog_title&lt;/code&gt; in the User model.&lt;/p&gt;
&lt;p&gt;Another matter of thought was how to handle &lt;code&gt;get_absolute_url&lt;/code&gt;. Thankfully, we have all parts needed there. We just need to assemble them by using this f-string — of which versions come up numerous times across the app.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;f&amp;quot;//{&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;owner&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;username&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}.{&lt;/span&gt;&lt;span style="color: #657B83;"&gt;settings&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;CANONICAL_HOST&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}{&lt;/span&gt;&lt;span style="color: #657B83;"&gt;path&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="subdomain-middleware"&gt;Subdomain middleware&lt;/h2&gt;
&lt;p&gt;This part is the core of how we handle subdomains using the same app.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/middleware.py&lt;/span&gt;
&lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;subdomain_middleware&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(get_response):&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;middleware&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(request):&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;host&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;META&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;get(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;HTTP_HOST&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;if&lt;/span&gt; &lt;span style="color: #657B83;"&gt;host&lt;/span&gt; &lt;span style="color: #859900;"&gt;and&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;len&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(host&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;split(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;))&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;==&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;3&lt;/span&gt;&lt;span style="color: #657B83;"&gt;:&lt;/span&gt;
            &lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;subdomain&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;host&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;split(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)[&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;0&lt;/span&gt;&lt;span style="color: #657B83;"&gt;]&lt;/span&gt;

        &lt;span style="color: #657B83;"&gt;response&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;get_response(request)&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;response&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;middleware&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# settings.py&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;MIDDLEWARE&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;[&lt;/span&gt;
    &lt;span style="color: #2AA198;"&gt;&amp;quot;main.middleware.subdomain_middleware&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A simple function-based Django middleware that checks the HTTP &lt;code&gt;Host&lt;/code&gt; header. If there are 3 dots, it means we have something like &lt;code&gt;subdomain.mataroa.blog&lt;/code&gt;. If so, we stick it in &lt;code&gt;request.subdomain&lt;/code&gt; and have it there for the rest of the trip!&lt;/p&gt;
&lt;p&gt;For example, (and most important case) when &lt;code&gt;/&lt;/code&gt; is requested, we want to know whether we should serve the landing or a blog:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/views.py&lt;/span&gt;

&lt;span style="color: #93A1A1;"&gt;# check if request has subdomain attr&lt;/span&gt;
&lt;span style="color: #859900;"&gt;if&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;hasattr&lt;span style="color: #93A1A1;"&gt;(&lt;/span&gt;request,&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;subdomain&amp;quot;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;)&lt;/span&gt;:

&lt;span style="color: #657B83;"&gt;    &lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# check if this subdomain is a blog that exists&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;    &lt;/span&gt;&lt;span style="color: #859900;"&gt;if&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;models.User.objects.filter&lt;span style="color: #93A1A1;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;username&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;request.subdomain&lt;span style="color: #93A1A1;"&gt;)&lt;/span&gt;.exists&lt;span style="color: #93A1A1;"&gt;()&lt;/span&gt;:
&lt;span style="color: #657B83;"&gt;        &lt;/span&gt;...&lt;span style="color: #657B83;"&gt;  &lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# render blog index template&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;    &lt;/span&gt;&lt;span style="color: #859900;"&gt;else&lt;/span&gt;:
&lt;span style="color: #657B83;"&gt;        &lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# blog does not exist, redirect to landing&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;        &lt;/span&gt;&lt;span style="color: #859900;"&gt;return&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;redirect&lt;span style="color: #93A1A1;"&gt;(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;//&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;+&lt;span style="color: #657B83;"&gt; &lt;/span&gt;settings.CANONICAL_HOST&lt;span style="color: #657B83;"&gt; &lt;/span&gt;+&lt;span style="color: #657B83;"&gt; &lt;/span&gt;reverse&lt;span style="color: #93A1A1;"&gt;(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="interest-form"&gt;Interest form&lt;/h2&gt;
&lt;p&gt;For the premium plan interest form, we sent an email to the admin letting them know of the submission. A conscious decision to avoid a new model for subscribers was made here.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/forms.py&lt;/span&gt;
&lt;span style="color: #859900;"&gt;class&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;InterestForm&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(forms&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;Form):&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;email&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;forms&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;EmailField()&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;send_email&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;):&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;body&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;There is a person interested in Mataroa premium!&amp;quot;&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;body&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;f&amp;quot;\nThis is their email: {&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;cleaned_data&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;get(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;'email'&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}&amp;quot;&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;body&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;body&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;\nBest,&amp;quot;&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;body&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;\nPython&amp;quot;&lt;/span&gt;

        &lt;span style="color: #657B83;"&gt;mail_admins(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;Interest form response&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;body)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Above is the form. I usually send the mail inside the view but the &lt;a href="https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-editing/#formview"&gt;Generic editing view&lt;/a&gt; Django docs had this exact example of sending email from the form.&lt;/p&gt;
&lt;p&gt;The view method below, only 9 lines, by exploiting the succinct marvel of Django generic views.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/views.py&lt;/span&gt;
&lt;span style="color: #859900;"&gt;class&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;InterestView&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(SuccessMessageMixin,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;FormView):&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;form_class&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;forms&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;InterestForm&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;template_name&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;main/interest.html&amp;quot;&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;success_url&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;reverse_lazy(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;success_message&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;thank you for your interest! we'll be in touch :)&amp;quot;&lt;/span&gt;

    &lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;form_valid&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;form):&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;form&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;send_email()&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;super&lt;/span&gt;&lt;span style="color: #657B83;"&gt;()&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;form_valid(form)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="disallowed-usernames"&gt;Disallowed usernames&lt;/h2&gt;
&lt;p&gt;Since usernames are subdomains, some of them had to be disallowed. I found a rather extensive list online and trimmed it down to 50. Some of the most notable are &lt;code&gt;api&lt;/code&gt;, &lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;cdn&lt;/code&gt;, &lt;code&gt;static&lt;/code&gt;, &lt;code&gt;random&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The implementation includes &lt;code&gt;form.add_error&lt;/code&gt;, which I don't recall ever using in the past.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/views.py&lt;/span&gt;
&lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;form_valid&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;form):&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;if&lt;/span&gt; &lt;span style="color: #657B83;"&gt;helpers&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;is_disallowed(form&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;cleaned_data&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;get(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)):&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;form&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;add_error(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;This username is not available.&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
        &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;render_to_response(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;get_context_data(form&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #657B83;"&gt;form))&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;super&lt;/span&gt;&lt;span style="color: #657B83;"&gt;()&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;form_valid(form)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="export-to-zola"&gt;Export to Zola&lt;/h2&gt;
&lt;p&gt;The feature that makes mataroa an un-platform is that it helps you get off it. It minimizes vendor lock-in by enabling the blog owner, with a single click, to be able to setup a static website with all their posts.&lt;/p&gt;
&lt;p&gt;Exporting to &lt;a href="https://www.getzola.org/"&gt;Zola&lt;/a&gt; was the first feature I wrote because I was too afraid of its implementation. Turns out it was easier than expected. The full view method is around 40 lines.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/views.py&lt;/span&gt;

&lt;span style="color: #93A1A1;"&gt;# get all posts and add them into export_posts encoded&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;posts&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;Post&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;objects&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;all()&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;export_posts&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;[]&lt;/span&gt;
&lt;span style="color: #859900;"&gt;for&lt;/span&gt; &lt;span style="color: #657B83;"&gt;p&lt;/span&gt; &lt;span style="color: #859900;"&gt;in&lt;/span&gt; &lt;span style="color: #657B83;"&gt;posts:&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;title&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;p&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;title&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;replace(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;.md&amp;quot;&lt;/span&gt;  &lt;span style="color: #93A1A1;"&gt;# no colons in filenames&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;export_posts&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;append((title,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;io&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;BytesIO(p&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;body&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;encode())))&lt;/span&gt;

&lt;span style="color: #93A1A1;"&gt;# create zip archive in memory&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;export_name&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;export-&amp;quot;&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;str&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(uuid&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;uuid4())[:&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;8&lt;/span&gt;&lt;span style="color: #657B83;"&gt;]&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;zip_buffer&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;io&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;BytesIO()&lt;/span&gt;
&lt;span style="color: #859900;"&gt;with&lt;/span&gt; &lt;span style="color: #657B83;"&gt;zipfile&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;ZipFile(&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;zip_buffer,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;zipfile&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;ZIP_DEFLATED,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;False&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;)&lt;/span&gt; &lt;span style="color: #859900;"&gt;as&lt;/span&gt; &lt;span style="color: #657B83;"&gt;export_archive:&lt;/span&gt;
    &lt;span style="color: #93A1A1;"&gt;# the directory structure is based on the paths of the name given to writestr&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;export_archive&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;writestr(export_name&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;/config.toml&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;zola_config)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;export_archive&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;writestr(export_name&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;/static/style.css&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;zola_styles)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;export_archive&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;writestr(export_name&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;/templates/index.html&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;zola_index)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;export_archive&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;writestr(export_name&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;/templates/post.html&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;zola_post)&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;for&lt;/span&gt; &lt;span style="color: #657B83;"&gt;file_name,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;data&lt;/span&gt; &lt;span style="color: #859900;"&gt;in&lt;/span&gt; &lt;span style="color: #657B83;"&gt;export_posts:&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;export_archive&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;writestr(&lt;/span&gt;
            &lt;span style="color: #657B83;"&gt;export_name&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;/content/&amp;quot;&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #657B83;"&gt;file_name,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;data&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;getvalue()&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;)&lt;/span&gt;

&lt;span style="color: #93A1A1;"&gt;# respond and make the file directly downloadable&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;response&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;HttpResponse(zip_buffer&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;getvalue(),&lt;/span&gt; &lt;span style="color: #657B83;"&gt;content_type&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;application/zip&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
&lt;span style="color: #657B83;"&gt;response[&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;Content-Disposition&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;]&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;f&amp;quot;attachment; filename={&lt;/span&gt;&lt;span style="color: #657B83;"&gt;export_name&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}.zip&amp;quot;&lt;/span&gt;
&lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;response&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;zola_&lt;/code&gt; prefixed variables are strings (not list of strings) of those files (stored in the code) which are read like this:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/views.py&lt;/span&gt;
&lt;span style="color: #859900;"&gt;with&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;open&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;./zola_export_base/config.toml&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;r&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt; &lt;span style="color: #859900;"&gt;as&lt;/span&gt; &lt;span style="color: #657B83;"&gt;zola_config_file:&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;zola_config&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;(&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;zola_config_file&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;read()&lt;/span&gt;
        &lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;replace(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;example.com&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;f&amp;quot;{&lt;/span&gt;&lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;user&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;username&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;}.mataroa.blog&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
        &lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;replace(&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;&amp;quot;Example blog title&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;f&amp;quot;{&lt;/span&gt;&lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;user&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;username&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;} blog&amp;quot;&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="permissions"&gt;Permissions&lt;/h2&gt;
&lt;p&gt;For permission checking I considered the &lt;a href="https://docs.djangoproject.com/en/3.0/topics/auth/default/#permissions-and-authorization"&gt;native Django solution&lt;/a&gt; but it was an overkill. Except for &lt;code&gt;LoginRequiredMixin&lt;/code&gt; and &lt;code&gt;user.is_authenticated&lt;/code&gt; the following lines are the core of every permission check:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #859900;"&gt;if&lt;/span&gt; &lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;user&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;username&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;!=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;subdomain:&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;raise&lt;/span&gt; &lt;span style="color: #657B83;"&gt;PermissionDenied()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Interesting bit is the preference of raising a &lt;code&gt;PermissionDenied&lt;/code&gt; exception to the return of &lt;code&gt;HttpResponseForbidden&lt;/code&gt;. The latter resulted in an empty page while the former returned a default text of black letters &lt;code&gt;403 Forbidden&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="post-creation"&gt;Post creation&lt;/h2&gt;
&lt;p&gt;On the post creation page we hide the slug field. It declutters the form a bit and lets you focus more on the actual writing than to find the best SEO-wise slug.&lt;/p&gt;
&lt;p&gt;Thus, we generate the slug using yet another brilliant battery of Django: &lt;code&gt;django.utils.text.slugify&lt;/code&gt;. Also, a check in case another identical slug (in the same blog) exists. This solution might be unideal but the number of infinite loops I have created in past projects solving this with &lt;code&gt;while&lt;/code&gt; (countless) in contrast to the times one uuid suffix was not enough (zero) is a good reason.&lt;/p&gt;
&lt;p&gt;We also inject the post owner, preventing any hijacking of users creating posts in others' blogs.&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;# main/views.py&lt;/span&gt;
&lt;span style="color: #859900;"&gt;def&lt;/span&gt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&lt;span style="color: #268BD2;"&gt;form_valid&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #657B83;"&gt;,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;form):&lt;/span&gt;
    &lt;span style="color: #93A1A1;"&gt;# commit=False to decrease SQL writes by one&lt;/span&gt;
    &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;object&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;form&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;save(commit&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;False&lt;/span&gt;&lt;span style="color: #657B83;"&gt;)&lt;/span&gt;

    &lt;span style="color: #93A1A1;"&gt;# slugification&lt;/span&gt;
    &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;object&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;slug&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #657B83;"&gt;slugify(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;object&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;title)&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;if&lt;/span&gt; &lt;span style="color: #657B83;"&gt;models&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;Post&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;objects&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;filter(&lt;/span&gt;
        &lt;span style="color: #657B83;"&gt;owner&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;user,&lt;/span&gt; &lt;span style="color: #657B83;"&gt;slug&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;object&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;slug&lt;/span&gt;
    &lt;span style="color: #657B83;"&gt;)&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;exists():&lt;/span&gt;
        &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;object&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;slug&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+=&lt;/span&gt; &lt;span style="color: #2AA198;"&gt;&amp;quot;-&amp;quot;&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;+&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;str&lt;/span&gt;&lt;span style="color: #657B83;"&gt;(uuid&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;uuid4())[:&lt;/span&gt;&lt;span style="color: #2AA198;"&gt;8&lt;/span&gt;&lt;span style="color: #657B83;"&gt;]&lt;/span&gt;

    &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;object&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;owner&lt;/span&gt; &lt;span style="color: #93A1A1;"&gt;=&lt;/span&gt; &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;request&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;user&lt;/span&gt;
    &lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;object&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;save()&lt;/span&gt;  &lt;span style="color: #93A1A1;"&gt;# sql write happens here&lt;/span&gt;
    &lt;span style="color: #859900;"&gt;return&lt;/span&gt; &lt;span style="color: #657B83;"&gt;HttpResponseRedirect(&lt;/span&gt;&lt;span style="color: #268BD2;"&gt;self&lt;/span&gt;&lt;span style="color: #93A1A1;"&gt;.&lt;/span&gt;&lt;span style="color: #657B83;"&gt;get_success_url())&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="epilogue"&gt;Epilogue&lt;/h2&gt;
&lt;p&gt;It was a really enjoyable project as a whole and the above bits the most amusing to figure out. Undoubtedly, their elegance can be futher improved and I am looking forward to learning how.&lt;/p&gt;
&lt;p&gt;As the project grows the above bits will change. The commit hash the above snippets of code are taken from is &lt;code&gt;48af918dd84a9a579db6dcc95461669e4cbf8d08&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can find the most recent version of the mataroa source code at &lt;a href="https://sr.ht/~sirodoht/mataroa/"&gt;sr.ht/~sirodoht/mataroa/&lt;/a&gt;. Or browse the tree of the above commit hash &lt;a href="https://git.sr.ht/~sirodoht/mataroa/tree/48af918dd84a9a579db6dcc95461669e4cbf8d08"&gt;here&lt;/a&gt;. Also mirrored on &lt;a href="https://github.com/sirodoht/mataroa"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Stavros' inspiration led him to &lt;a href="https://quicksite.stavros.io/"&gt;Quick Site&lt;/a&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>nutcroft</author><pubDate>Tue, 09 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/building-mataroa-blog/</guid></item><item><title>Smart cities "fighting" coronavirus?</title><link>https://stop.zona-m.net/2020/06/smart-cities-fighting-coronavirus/</link><description>&lt;p&gt;Wait a moment&amp;hellip;.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 08 Jun 2020 16:50:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/smart-cities-fighting-coronavirus/</guid></item><item><title>Hammerspoon: A Better, Better Hyper Key</title><link>http://evantravers.com/articles/2020/06/08/hammerspoon-a-better-better-hyper-key/</link><description>&lt;p&gt;This &lt;em&gt;all&lt;/em&gt; started with Hyper. I &lt;a href="/articles/2020/06/08/hammerspoon-history/"&gt;talked in the last post&lt;/a&gt; about my history with the concept, how I learned from &lt;a href="https://stevelosh.com/blog/2012/10/a-modern-space-cadet/"&gt;Steve Losh's post on the topic&lt;/a&gt; and borrowed from &lt;a href="https://brettterpstra.com/2016/09/29/a-better-hyper-key-hack-for-sierra/"&gt;Brett Terpstra&lt;/a&gt;… and I've expanded the idea a bit. At the moment, my hyper implementation is contained in a lua module called &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/38a7d8c0ad2190d1563d681725628e4399dcbe6c/hyper.lua"&gt;hyper.lua&lt;/a&gt;, with some dependencies on Karabiner-Elements.app.&lt;/p&gt;
&lt;p&gt;I'm using hs.hotkey.modal to capture an &lt;code&gt;F19&lt;/code&gt; keystroke, and only sending the &amp;quot;hyper chord&amp;quot; of &lt;code&gt;⌘⌥⇧⌃&lt;/code&gt; if absolutely required. The &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/38a7d8c0ad2190d1563d681725628e4399dcbe6c/hyper.lua"&gt;code isn't that complex&lt;/a&gt; so this post will be focused on the advantages of this approach.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#before-hyper-chord" id="before-hyper-chord"&gt;&lt;/a&gt;Before: hyper chord&lt;/h2&gt;
&lt;p&gt;Traditionally, a Hyper key is implemented by sending to the Operating System &amp;quot;hyper chord&amp;quot; of &lt;code&gt;⌘⌥⇧⌃&lt;/code&gt; by modifying the keyboard firmware or using &lt;a href="https://karabiner-elements.pqrs.org/"&gt;Karabiner-elements.app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/06/traditional.png" /&gt;&lt;/p&gt;
&lt;p&gt;The user would then use some kind of automation software like Alfred or Keyboard Maestro to listen for the &amp;quot;hyper chord&amp;quot; and fire different automations. You can &lt;em&gt;absolutely&lt;/em&gt; do this in Hammerspoon if you want.&lt;/p&gt;
&lt;p&gt;While it works well, it has its limitations. Using the &amp;quot;hyper chord&amp;quot; as the entire &amp;quot;hyper key&amp;quot;, you can't add any more modifiers, because it is already &lt;em&gt;all&lt;/em&gt; the modifiers. Because of this a lot of hyper key setups are limited to &amp;quot;leader key&amp;quot; style interactions.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#after-hshotkeymodal" id="after-hshotkeymodal"&gt;&lt;/a&gt;After: hs.hotkey.modal&lt;/h2&gt;
&lt;p&gt;Using a single keycode as your &amp;quot;hyper&amp;quot; key, and handling the translation at the automation layer is much more expressive. In my case, Hammerspoon becomes a single &amp;quot;router&amp;quot; to all the automation and UI customization on my Mac.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="https://images.evantravers.com/articles/2020/06/hammerspoon.png" /&gt;&lt;/p&gt;
&lt;p&gt;I use a single often-unused key (in my case, &lt;code&gt;F19&lt;/code&gt;) to trigger a &lt;code&gt;hs.hotkey.modal&lt;/code&gt; in Hammerspoon. Instead of having every single application listening to all the keystrokes, I can control it &lt;em&gt;one place&lt;/em&gt;. In this as in all things, I am not the first. Brett Terpstra &lt;a href="https://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/"&gt;first wrote about this in &amp;quot;A Useful Caps Lock Key&amp;quot;&lt;/a&gt; in 2012.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#hyper-shifted" id="hyper-shifted"&gt;&lt;/a&gt;Hyper… shifted?&lt;/h3&gt;
&lt;p&gt;One big advantage to using Hammerspoon as a &amp;quot;man-in-the-middle&amp;quot; is using modifiers with your hyper key. Because your &amp;quot;hyper key&amp;quot; &lt;strong&gt;is not&lt;/strong&gt; a cluster of modifier keys, you can actually use it in conjunction with any normal modifiers.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;-- Press `HYPER+r`, get the Hammerspoon console.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;console&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;hswindow&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;focus&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- Because my `HYPER` is actually F19,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- I can press `HYPER+SHIFT+R`&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;--&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- Press `HYPER+⇧+R`, reload Hammerspoon configuration.&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'shift'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;reload&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/38a7d8c0ad2190d1563d681725628e4399dcbe6c/init.lua#L167-L168"&gt;init.lua&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;I presently only use this in a few bindings, but I'm excited about all kinds of interesting ways to use it: quitting instead of launching an app, automatically choosing a window layout, the options are endless!&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#truly-global-hotkeys-local-bindings" id="truly-global-hotkeys-local-bindings"&gt;&lt;/a&gt;Truly Global Hotkeys: Local Bindings&lt;/h3&gt;
&lt;p&gt;There is one problem… if you want to use your hyper key to bind to an in-app Preference… &lt;code&gt;F19&lt;/code&gt; is not supported by all applications.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt="Preference pane for Things 3, showing the Quick Capture." src="https://images.evantravers.com/articles/2020/06/things-prefs.png" /&gt;
  &lt;figcaption&gt;
    &lt;p&gt;Things will not recognize &lt;code&gt;F19&lt;/code&gt; as a keycode, or a modifier.&lt;/p&gt;
    &lt;p&gt;To handle this, when I press &lt;code&gt;F19+.&lt;/code&gt; Hammerspoon translates &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/38a7d8c0ad2190d1563d681725628e4399dcbe6c/init.lua#L69"&gt;that local binding&lt;/a&gt; as if I'm pressing &lt;code&gt;⌘⇧⌥⌃+.&lt;/code&gt;.&lt;/p&gt;
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Many apps give you the ability to set a hotkey in their preference panes for certain &amp;quot;global&amp;quot; tasks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create to-do's in Things 3.&lt;/li&gt;
&lt;li&gt;Open the Quick Capture in Drafts.app.&lt;/li&gt;
&lt;li&gt;Open the clipboard history, file manager, and main search window of Alfred.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To answer this, I have developed a concept of &amp;quot;local bindings.&amp;quot; If you set any &lt;code&gt;local_binding&lt;/code&gt; key for the configuration, hyper.lua will intercept the &lt;code&gt;F19+&amp;lt;key&amp;gt;&lt;/code&gt; keypress and instead send the traditional &lt;code&gt;⌘⇧⌥⌃+&amp;lt;key&amp;gt;&lt;/code&gt; to the operating system… just like the Traditional model. First, set up the local bindings to the app in Hammerspoon. Then, use your new local bindings in the preference pane of the app of your choice.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;if&lt;/span&gt; &lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;local_bindings&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;-- for key in app.local_bindings&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;for&lt;/span&gt; &lt;span&gt;_&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;key&lt;/span&gt; &lt;span&gt;in&lt;/span&gt; &lt;span&gt;pairs&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;local_bindings&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;do&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;key&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;[&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;-- send hyper chord + key&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventtap&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;keyStroke&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'cmd'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'alt'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'shift'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'ctrl'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;key&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;[&lt;/span&gt;&lt;span&gt;..&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(from &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/38a7d8c0ad2190d1563d681725628e4399dcbe6c/hyper.lua#L79-L94"&gt;hyper.lua&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#even-when-the-app-is-closed" id="even-when-the-app-is-closed"&gt;&lt;/a&gt;Even when the app is closed&lt;/h3&gt;
&lt;p&gt;In addition, I have incorporated an idea from &lt;a href="https://thesweetsetup.com/oopsiethings-applescript-for-things-on-mac/"&gt;Shawn Blanc's OopsieThings applescript&lt;/a&gt;. If the you trigger a local binding and Hammerspoon sees that app isn't open, it'll open it for you and &lt;em&gt;then&lt;/em&gt; send the binding.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;-- if the app is open&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;if&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;bundleID&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;then&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;-- send hyper chord&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventtap&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;keyStroke&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'cmd'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'alt'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'shift'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'ctrl'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;key&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;else&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;-- launch the app&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;launch&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;-- wait for it to launch&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;timer&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;waitWhile&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;return&lt;/span&gt; &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;application&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;find&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;bundleID&lt;/span&gt;&lt;span&gt;)&lt;/span&gt; &lt;span&gt;==&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt; &lt;span&gt;end&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;-- then send hyper chord + key&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;      &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eventtap&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;keyStroke&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'cmd'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'alt'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'shift'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;'ctrl'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;key&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That way my &amp;quot;send a tweet using Tweetbot&amp;quot; or &amp;quot;make a Draft&amp;quot; or especially &amp;quot;make a to-do in Things&amp;quot; buttons &lt;strong&gt;always&lt;/strong&gt; work, regardless of whether the app is accidentally closed. 👍&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#configuration" id="configuration"&gt;&lt;/a&gt;Configuration&lt;/h2&gt;
&lt;p&gt;Hammerspoon loads an &lt;code&gt;init.lua&lt;/code&gt; file by default… so I have a couple of configuration tables declared in there that I pass into the other modules.&lt;/p&gt;
&lt;p&gt;I used to declare &lt;code&gt;config&lt;/code&gt; as a global and just let all the other modules use it, but I wanted to make sure the modules can use whatever anyone wants to use,&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;1&lt;/a&gt;&lt;/sup&gt; so now each module has a &lt;code&gt;.start()&lt;/code&gt; method that takes as an argument a config table. Since lua stores nearly everything as a reference, I'm not worried about blowing out memory.&lt;/p&gt;
&lt;p&gt;Here is a minimalist example of a config for hyper.lua. I've removed some of the other keys and values for some of the other modules for the sake of discussion... just the config to launch Things 3, create local bindings for the capture options, and a quick function to reload the Hammerspoon config file.&lt;/p&gt;
&lt;pre class="lumis"&gt;&lt;code class="language-lua" tabindex="0"&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;applications&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;[&lt;/span&gt;&lt;span&gt;'Things'&lt;/span&gt;&lt;span&gt;]&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;bundleID&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'com.culturedcode.ThingsMac'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;hyper_key&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;'t'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;    &lt;span&gt;local_bindings&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;','&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'.'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;-- load as global, it's going to be used&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt; &lt;span&gt;=&lt;/span&gt; &lt;span&gt;require&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;'hyper'&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;        &lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;hyper&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;bind&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;lbrace&lt;/span&gt;&lt;span&gt;'shift'&lt;/span&gt;&lt;span&gt;&amp;amp;rbrace&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;'r'&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;nil&lt;/span&gt;&lt;span&gt;,&lt;/span&gt; &lt;span&gt;function&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;  &lt;span&gt;hs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;reload&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;div class="line"&gt;&lt;span&gt;end&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It's very straightforward. My most common use of Hyper.lua is to launch an application, so I have a table of applications that I can define a &amp;quot;hyper key&amp;quot; for, and optionally some local bindings that I bind inside that application to use globally.&lt;/p&gt;
&lt;p&gt;I use hyper.lua as the &amp;quot;entry point&amp;quot; for nearly all my Hammerspoon based automation... it's great. All my keybindings are declared in one place, and I &lt;strong&gt;know&lt;/strong&gt; they will never conflict with any new applications that I download. No more discovering that weird app behavior is due to a double-bound keybinding.&lt;/p&gt;
&lt;p&gt;As this series continues, I'll list the examples of how I connect hyper.lua to other automations here.&lt;/p&gt;
&lt;p&gt;If you want to &lt;a href="https://github.com/evantravers/hammerspoon-config/blob/abc945264a4ec1830083c53079b2bfd5c4a4d23d/hyper.lua"&gt;read Hyper.lua at the time of this blog post, it's available on my GitHub&lt;/a&gt;. It's possible it's gone through new versions since this post. There's a few features in there now that I am not covering in this post, but we'll get to them later in this series.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;A lot of the configuration files I've seen for Hammerspoon use a similar pattern. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Mon, 08 Jun 2020 16:07:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/06/08/hammerspoon-a-better-better-hyper-key/</guid></item><item><title>Hammerspoon: History</title><link>http://evantravers.com/articles/2020/06/08/hammerspoon-history/</link><description>&lt;p&gt;In 2012, I read the &lt;a href="https://stevelosh.com/blog/2012/10/a-modern-space-cadet/"&gt;Modern Space Cadet article by Steve Losh&lt;/a&gt;. This was hugely impactful and I've pretty much tried everything on it (the &lt;a href="https://stevelosh.com/blog/2012/10/a-modern-space-cadet/#s16-shift-key-training-wheels"&gt;shift-key training wheels&lt;/a&gt; were frustrating but helped my typing!) and I started playing around with all those tricks, especially the Hyper key.&lt;/p&gt;
&lt;p&gt;Initially, the Hyper key is a &amp;quot;magic&amp;quot; hack for keyboard shortcut lovers where it assigns a single keypress to the unreachable modifier chord of &lt;code&gt;⌘⌥⇧⌃&lt;/code&gt;. No OS X app uses that crazy chord, but most will let you use it as modifiers for a keyboard shortcut. This enables the user to set a custom keyboard shortcut that will not override a standard keyboard shortcut… effectively a layer of shortcuts that's all your own.&lt;/p&gt;
&lt;p&gt;I used Mr. Losh's exact setup for quite a long time: Use KeyRemap4Macbook&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-2" id="fnref-2"&gt;1&lt;/a&gt;&lt;/sup&gt; to map a key to the &amp;quot;hyper&amp;quot;, and use Keyboard Maestro to listen for that chord and fire off automations, primarily switching between applications.&lt;/p&gt;
&lt;p&gt;It's hard to overstate the impact of this hack on my computing style. I haven't used the &lt;code&gt;⌘+TAB&lt;/code&gt; app switcher regularly for nearly eight years now… my fingers just open the browser with &lt;code&gt;HYPER+k&lt;/code&gt;, and that is How Computers Should Work&lt;sup&gt;TM&lt;/sup&gt;. At the time, I was a software developer working mostly on the front-end, so the ability to instantly switch from my editor to the browser shortened my OODA loop and allowed me to iterate &lt;em&gt;very&lt;/em&gt; quickly. If you bounce back and forth between two or three programs on a regular basis, I &lt;strong&gt;highly&lt;/strong&gt; recommend investing in something like this.&lt;/p&gt;
&lt;p&gt;This has gone through several iterations through the years. I moved from Keyboard Maestro to Alfred for this, using their visual workflow builder to define simple app switching rules. Eventually, there was some kind of breaking change that drove me to &lt;a href="http://www.hammerspoon.org/"&gt;Hammerspoon&lt;/a&gt;&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-1" id="fnref-1"&gt;2&lt;/a&gt;&lt;/sup&gt; sometime in 2018. I'm not entirely sure where I found it, I know it was while searching for a solution to my Hyper-key problems.&lt;/p&gt;
&lt;p&gt;I found Hammerspoon's Lua-powered little engine to be powerful and &lt;strong&gt;much faster&lt;/strong&gt; than anything I had used. I was hooked.&lt;/p&gt;
&lt;p&gt;While Keyboard Maestro is &lt;em&gt;very&lt;/em&gt; powerful, and people have been writing applescripts for Automator forever, Hammerspoon snuggled into a sweet spot in my toolchain. I am a programmer, so anything that I can read and maintain in git is a major bonus. Hammerspoon has enough hooks and API libraries to make writing it fairly easy&lt;sup class="footnote-ref"&gt;&lt;a href="#fn-3" id="fnref-3"&gt;3&lt;/a&gt;&lt;/sup&gt;. I &lt;em&gt;frequently&lt;/em&gt; find myself encoding a process or a UI layout into my Hammerspoon repo for repeatability and consistency.&lt;/p&gt;
&lt;p&gt;As my job changed, my uses for Hammerspoon have changed. In some ways, the ability to instantly summon any application is now a bit of a curse to my precious focus rather than a boon to efficiency. I have started restructuring a bit in order to change with me, and it'll probably look totally different in two more years.&lt;/p&gt;
&lt;p&gt;At the moment, I use Hammerspoon to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Focus apps with a hotkey.&lt;/li&gt;
&lt;li&gt;Manage a globally accessible hotkey modal.&lt;/li&gt;
&lt;li&gt;Connect and disconnect my AirPods.&lt;/li&gt;
&lt;li&gt;Automatically close distractions in tabs and in apps.&lt;/li&gt;
&lt;li&gt;Move my windows around.&lt;/li&gt;
&lt;li&gt;Automatically create layouts for common tasks.&lt;/li&gt;
&lt;li&gt;Track time to toggl based on activity.&lt;/li&gt;
&lt;li&gt;Create projects in Things 3.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And more to come... 😈&lt;/p&gt;
&lt;p&gt;I'm going to take a few posts and document some of the modules and methodologies to my OS X desktop automation powered by Hammerspoon. While my configuration is a moving target this feels like a good point to do this, it's stable, I'm using it every day, and there are a few things that I've written that I haven't seen done before, and that I've been planning on writing for &lt;em&gt;years&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If you just love automation, and you do not consider yourselves a programmer, you may be able to just &lt;a href="https://github.com/evantravers/hammerspoon-config/tree/38a7d8c0ad2190d1563d681725628e4399dcbe6c"&gt;clone and tweak my system&lt;/a&gt; or &lt;a href="https://github.com/Hammerspoon/hammerspoon/wiki/Sample-Configurations"&gt;another user's&lt;/a&gt;. You may also want to take the ideas in this series and implement them in Shortcuts on iOS or Keyboard Maestro. The techniques work regardless of implementation.&lt;/p&gt;
&lt;section class="footnotes"&gt;
&lt;ol&gt;
&lt;li id="fn-2"&gt;
&lt;p&gt;Replaced by Karabiner.app, now replaced by Karabiner-elements.app. ¯(°_o)/¯ &lt;a class="footnote-backref" href="#fnref-2"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-1"&gt;
&lt;p&gt;&lt;a href="https://github.com/evantravers/hammerspoon-config/commit/5f669b15b1a6b4ca7b40b7a42d0635f766c6133e"&gt;The original commit&lt;/a&gt;. I wish I could remember &lt;em&gt;exactly&lt;/em&gt; what led me here… it's very likely it was &lt;a href="https://brettterpstra.com/2016/09/29/a-better-hyper-key-hack-for-sierra/"&gt;Brett Terpstra's post&lt;/a&gt; or my friend &lt;a href="http://megalithic.io"&gt;Seth&lt;/a&gt;. &lt;a class="footnote-backref" href="#fnref-1"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn-3"&gt;
&lt;p&gt;There's a &lt;a href="https://www.hammerspoon.org/docs/"&gt;healthy standard lib&lt;/a&gt;, but I can't believe I went so long without noticing &lt;code&gt;hs.inspect&lt;/code&gt;. &lt;a class="footnote-backref" href="#fnref-3"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</description><author>trv.rs</author><pubDate>Mon, 08 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/06/08/hammerspoon-history/</guid></item><item><title>Snap out of it</title><link>https://justingarrison.com/blog/2020-06-08-snap-out-of-it/</link><description>How to uninstall and block snapd on Ubuntu</description><author>Justin Garrison's Homepage</author><pubDate>Mon, 08 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://justingarrison.com/blog/2020-06-08-snap-out-of-it/</guid></item><item><title>APEX: Highlight important values in tables with chips</title><link>https://hartenfeller.dev/blog/apex-highlight-values-chips</link><description>Tables make it hard to give hierarchy to data. To underline the importance of certain values in a table you can use chips that highlight the values with colors.</description><author>Philipp Hartenfeller Blog RSS Feed</author><pubDate>Mon, 08 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hartenfeller.dev/blog/apex-highlight-values-chips</guid></item><item><title>🍳 Adam Ragusea’s Roasted Tomato Sauce</title><link>prashanth.world/squeaky-nail/prashanth.world/roasted-tomato-sauce/</link><description>Adam Ragusea’s Roasted Tomato Sauce is a super simple and quick recipe to make a tomato sauce that takes no effort at all. The only thing to watch out for is burning yourself. As someone who rarely uses a kitchen towel to grasp pans, this one has burned me a couple times (literally).</description><author>Prashanth Sadasivan</author><pubDate>Mon, 08 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">prashanth.world/squeaky-nail/prashanth.world/roasted-tomato-sauce/</guid></item><item><title>The shadow of have to</title><link>http://dimitarsimeonov.com/2020/06/07/the-shadow-of-have-to</link><description>&lt;p&gt;I recently learned about the concept of a “shadow” that Carl Jung defined. According to it, each of us has a psychological shadow - the part of us that we suppress unconsciously. It’s usually a darker side which society makes us hide, such as a side of violence, but it doesn’t have to be negative. It can be different sexuality, or creativity. It is there, even if we aren’t aware if.&lt;/p&gt;

&lt;p&gt;For me personally, on the surface level I’ve struggled with some addictions, anger and procrastination, so I was curious whether these might result from something I’m suppressing in my shadow. So I started probing.&lt;/p&gt;

&lt;p&gt;One thing I realized I was suppressing is that I was thinking of most things I spent my time as things I “have to” do. Not the things I “want to” do. Even for genuinely fun things. I realized also I wasn’t as productive in the “have to” tasks, as the “want to” part of my brain would keep pushing me towards procrastination.&lt;/p&gt;

&lt;p&gt;So I decided to not fight that voice and start thinking about what I “want to” do and spend more time doing it. And to lean towards whatever seems to generate the most genuine fun - do that.&lt;/p&gt;

&lt;p&gt;I realized I want to be active and healthy and tackle physical challenges in the outdoors, to solve math problems and to discover through doing, whether it’s writing an essay, or an app. To spend more time with favorite people, to party, to dance and to travel. To learn new things, to satisfy my curiosity, and to see the product of my work flourish. To help others and to see them succeed.&lt;/p&gt;

&lt;p&gt;The phrase “To do list” started having a different feel, as it was more “want to do list” than “have to do list”.&lt;/p&gt;

&lt;p&gt;The result - my perceived stress decreased, and I am enjoying what I’m doing now a lot more. What is a bit unexpected is that having decided to be a bit more selfish and be more driven by “want” than “have to”, the things I “have to” do haven’t suffered and in fact seem improved, as I struggle less with procrastination.&lt;/p&gt;

&lt;p&gt;This essay’s existence is a result of that.&lt;/p&gt;</description><author>D13V</author><pubDate>Sun, 07 Jun 2020 20:12:59 GMT</pubDate><guid isPermaLink="true">http://dimitarsimeonov.com/2020/06/07/the-shadow-of-have-to</guid></item><item><title>Fehrist – Document Indexing Library in Go  Fehrist is a document indexing library written in Golang which is used to index different kind of text documents</title><link>https://blog.adnansiddiqi.me/fehrist-document-indexing-library-in-go/</link><description>&lt;p&gt;TLDR: Visit Github repo if you are not interested in the internals of the lib. Today I present you another library I made in Go language, called, Fehrist From the Github README: Fehrist is a pure Go library for indexing different types of documents. Currently, it supports only CSV and JSON but flexible architecture gives you the liberty to add more documents. Fehrist(فہرست) is an Urdu word for Index. Similar terminologies used in Arabic(فھرس) and Farsi(فہرست) as well. Fehrist is based on an Inverted Index data structure for indexing purposes. Why did I make it? It seems I have fallen in love with Golang after Python. Go is an opinionated language that does not let you get distracted in various small decisions. The reason for making this particular lib is nothing but learning about indexing; how it works and what algorithms are available. I picked the Inverted Index due to its flexibility and relatively easier implemented than others like B+Trees. I also took inspiration from ElasticSearch for writing and arranging index files on disk. How it Works? As I mentioned that it is based on an inverted index. All files, regardless of their type are tokenized after the first stage where a DOCID is assigned to each record. A record is a single entry in the case of CSV, JSON, or XML file. After the assignment of DOCID, it is then tokenized where each term in the file is mapped corresponding DOCID and the file name. The successful indexed document(s) can then be searched by providing a keyword. The output of the search result is a JSON structure. Golang maps data structure has been used for intermediate data processing and searching. Below is the diagram that might help you to understand the entire process of indexing. &amp;#160; In the first step, the CSV file was fed to the system which was then split record-wise and mapped with a DOCID. In the second step, each record was tokenized into each term in a way that it was mapped with the count of occurrence. For instance, Jhon was found in documents 1.csv and 2.csv, it will create a pipe-delimited structure which is then assigned as an individual entry of the map against its corresponding key. As you can in the diagram above, john was found in DOCIDs docid1 and docid2. Go maps have been used for the purpose. Finally, the data is saved into the disk. I stole the idea from ElasticSearch for the data management on disk: As you can in the picture above, each index file is saved as .idx file. At first it created a folder of the name you had provided. All relevant files are then stored in it(Thanks ElasticSearch for giving me this idea). You are also seeing files with extension .document which is actually originally entries along with their DOCIds. All data is then serialized with the help of MessagePack. Below is the code that is indexing CSV files. The library is flexible. Thanks to polymorphism provided by Go, you can extend this library very easily by implementing a couple of methods. Searching is then easy: The `Search` method takes an index name as a parameter because a folder was created of the same name and all files were stored in it. Init() method was used to pull all the data from documents and indices in maps. As I said it is a flexible lib. All you need to add your own document type struct just like I have done for JSON and CSV. Conclusion I hope you like this post and will use this library in your next projects. There are a few things that it does not cover like full search. It also does not apply stemming and stop words either. For now, it returns data based on the exact keyword found. You are free to enhance it by forking it. You can download this lib from Github. Header Photo by Maksym Kaharlytskyi on Unsplash If you like this post then you should subscribe to my blog for future updates. * indicates required Email Address *&lt;/p&gt;
The post &lt;a href="https://blog.adnansiddiqi.me/fehrist-document-indexing-library-in-go/"&gt;Fehrist – Document Indexing Library in Go &lt;br /&gt; &lt;span style="color: grey; font-size: 25px; font-weight: 300;"&gt;Fehrist is a document indexing library written in Golang which is used to index different kind of text documents&lt;/span&gt;&lt;/a&gt; first appeared on &lt;a href="https://blog.adnansiddiqi.me"&gt;Adnan's Random bytes&lt;/a&gt;.</description><author>Adnan's Random bytes</author><pubDate>Sun, 07 Jun 2020 19:07:14 GMT</pubDate><guid isPermaLink="true">https://blog.adnansiddiqi.me/fehrist-document-indexing-library-in-go/</guid></item><item><title>Debugging issues with libcurl and publickey authentication</title><link>https://www.zufallsheld.de/2020/06/07/debugging-issues-libcurl-pubkey-authentication/</link><description>&lt;p&gt;Curl has support for sftp and scp, among many other protocols. In one of our php-applications we
use libcurl to transfer files via sftp to a remote&amp;nbsp;datacenter.&lt;/p&gt;
&lt;!-- PELICAN_END_SUMMARY --&gt;

&lt;p&gt;We recently migrated this application into a docker-container.
With it we transferred the private key into the container, so the application can …&lt;/p&gt;</description><author>zufallsheld</author><pubDate>Sun, 07 Jun 2020 19:00:00 GMT</pubDate><guid isPermaLink="true">https://www.zufallsheld.de/2020/06/07/debugging-issues-libcurl-pubkey-authentication/</guid></item><item><title>📸San Francisco 2020</title><link>https://bpev.me/notes/travel-san-francisco-2020</link><author>bpev.me</author><pubDate>Sun, 07 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://bpev.me/notes/travel-san-francisco-2020</guid></item><item><title>His Dark Materials Season 1 Readthrough</title><link>https://captnemo.in/blog/2020/06/07/his-dark-materials/</link><description>&lt;p&gt;A long time ago, I tried to &lt;a href="https://captnemo.in/blog/2011/04/19/game-of-thrones/"&gt;do a readthrough&lt;/a&gt; for Game of Thrones (Book 1) alongside the first season. I managed to reach Episode 5, before I sped through the rest of the book, but I tried.&lt;/p&gt;

&lt;p&gt;Trying something similar for His Dark Materials, which is a great series if you’re looking to watch something new. Instead of noting down Chapter/Book equivalence (like I tried last time), going to write down my thoughts here as I’m reading along. &lt;strong&gt;Spoiler Warning&lt;/strong&gt; for the entire first season obviously.&lt;/p&gt;

&lt;h2 id="overall"&gt;Overall&lt;/h2&gt;

&lt;p&gt;The show is very tightly knit with the book with a few over-arching changes from the story-telling perspective:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You get to see other points-of-view, other than just Lyra. Helps establish what else is happening, especially in the other worlds.&lt;/li&gt;
  &lt;li&gt;A lot of infodumps are prevented, or better, broken down into multiple sessions.&lt;/li&gt;
  &lt;li&gt;The major change from the first book is ofcourse showing Will’s PoV and our earth.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="chapter-1"&gt;Chapter 1&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;The opening scene with the great flood sets some context, but isn’t in the books.&lt;/li&gt;
  &lt;li&gt;The Master/Butler chat on the wine poisoining happens much later in the books.&lt;/li&gt;
  &lt;li&gt;There is a lot of foreshadowing around Lyra’s parentage that happens in the first 2 chapters that is entirely missed in the show.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="chapter-2"&gt;Chapter 2&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;The entire Grumman’s skull and hunt sub-plot hasn’t shown up in the book so far (presumably because we only see Lyra’s PoV).&lt;/li&gt;
  &lt;li&gt;The party scene is very-well handled (with all the subtle changes for the better. Superb acting as well :)&lt;/li&gt;
  &lt;li&gt;The hiding-lyra-in-the-boat scene is merely given a passing mention in the book, but so well done in the show.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="chapter-3"&gt;Chapter 3&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Splitting Lyra’s parentage reveal (Coulter reveals her father) is a smart move in the show.&lt;/li&gt;
  &lt;li&gt;The show changes Lyra’s kidnappers from Turkish slavers to Gobblers.&lt;/li&gt;
  &lt;li&gt;The Alethiometer reveal happens with both Father Coram and John Fa in the book. The section also has a huge infodump, especially since it involves the parentage reveal. The show breaks it into 3: alethiometer reveal with Father Coram, a previous interrogation of Lyra with John Fa, and Lyra’s parentage reveal (mother) with Ma Costa.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="chapter-4"&gt;Chapter 4&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;The one notable “not-in-the-book” scene is the Coulter’s meeting with Iofur.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="chapter-5"&gt;Chapter 5&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Interesting to note that the characters of Billy and Roger are fused in both the film and the TV adaptations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="chapter-6"&gt;Chapter 6&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Lyra starts a fire in the books, but the show makes it more dramatic by destroying the machine.&lt;/li&gt;
  &lt;li&gt;The balloon ride covers a lot more in the books.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="learnings"&gt;Learnings&lt;/h2&gt;

&lt;p&gt;Overall, the show has been nicely adapted so far, and I think there’s a few reasons:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The show barely messes with Lyra’s timeline. Important to ensure this to avoid creating cascading issues down the path.&lt;/li&gt;
  &lt;li&gt;Majority of the changes are either made on kill-able subplots, or side-plots that show us what’s going on elsewhere.&lt;/li&gt;
  &lt;li&gt;And finally, the show spends time on where the medium works best. The scaring scene in Chapter 2, for eg.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I’m still sad that the ghosts in the crypt don’t get to be seen, though.&lt;/p&gt;</description><author>Nemo's Home</author><pubDate>Sun, 07 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://captnemo.in/blog/2020/06/07/his-dark-materials/</guid></item><item><title>Book Review: Amusing Ourselves to Death</title><link>https://lambdaland.org/posts/2020-06-07-amusing-ourselves-to-death/</link><description>&lt;h1 id="overview"&gt;Overview&lt;/h1&gt;
&lt;p&gt;The primary thrust of this book is that television has degraded our mode
of public discourse. Our news, politics, education, and even religion
are delivered to us primarily through television, where they were once
delivered via the written word. This transformation of medium is not
irrelevant: just as poetry doesn’t survive fully intact when translated
from one language to another, likewise ideas do not survive translation
of medium.&lt;/p&gt;
&lt;p&gt;This book was written in 1986. What foresight. If Postman was worried
about the effects that &lt;em&gt;television&lt;/em&gt; was having on public discourse, he
would have been scared silly to see how much of our dialog is held
online on Facebook and Twitter, where all ideas are compressed into 140
to 280 characters and algorithms designed to optimize for consumer
engagement determine what rises to prominence and what does not. Thus
rational thought is drowned out—stamped out—by a deluge of content
that is shallow, simplistic, and sensational.&lt;/p&gt;
&lt;p&gt;What follows are my notes that I wrote as I read the book, organized by
chapter. Do note that these notes are not meant to stand on their own;
if you have not read the book, they will likely seem disjoint.&lt;/p&gt;
&lt;h1 id="reading-notes"&gt;Reading Notes&lt;/h1&gt;
&lt;h2 id="typographic-america-p-30"&gt;Typographic America (p. 30)&lt;/h2&gt;
&lt;p&gt;The typographical America read a lot.&lt;/p&gt;
&lt;p&gt;The telegraph &lt;em&gt;commoditized&lt;/em&gt; information: news was suddenly taken out of
context and held as valuable &lt;em&gt;per se&lt;/em&gt;. &lt;em&gt;The question&lt;/em&gt;: if something is
not relevant to my actions, can it still be valuable?&lt;/p&gt;
&lt;h2 id="the-peek-a-boo-world-p-64"&gt;The Peek-a-Boo World (p.64)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;p. 69&lt;/strong&gt;: Is the problem then in &lt;em&gt;unidirectional&lt;/em&gt; means of
communication? We can’t reply and can’t really engage. We become passive
and the signal gets lost in the noise.&lt;/p&gt;
&lt;h2 id="now-this-p-99"&gt;Now… This (p. 99)&lt;/h2&gt;
&lt;p&gt;The idea here seems to be this: television has become the paradigm of
information transmittal. Because it strips things of context and things
are to be understood by themselves, contradictions fade. Magazines
follow suit: entertainment is news, and news must be entertaining.&lt;/p&gt;
&lt;h2 id="shuffle-off-to-bethlehem-p-114"&gt;Shuffle Off to Bethlehem (p. 114)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;p. 117&lt;/strong&gt;: Prose survives translation between languages, whereas poetry
does not survive. Likewise, ideas do not survive changes in medium
unchanged. Television (and now mediums like Twitter, Instagram, etc.) do
great violence to ideas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p. 121&lt;/strong&gt;: TV demands that what what be presented be &lt;em&gt;easy&lt;/em&gt;. Elder
Maxwell’s talks are nice to watch, but move far too quickly and are way
more intricate than can be comfortably comprehended. There is some place
for easy: beginners to faith will have difficulty appreciating
everything about Elder Maxwell.&lt;/p&gt;
&lt;h2 id="reach-out-and-elect-someone-p-125"&gt;Reach Out and Elect Someone (p. 125)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;p. 128&lt;/strong&gt;: Commercials are less about the character of the product and
mare more about the &lt;em&gt;character of the consumer&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="reach-out-and-elect-someone-p-126"&gt;Reach out and Elect Someone (p. 126)&lt;/h2&gt;
&lt;p&gt;Capitalism works when the buyer and producer can both know what is good
and what is valuable. In sports, there are rules and standards that
cannot be muffled over; a basketball player who misses all his free
throws cannot weasel his way into being considered a “good player”.&lt;/p&gt;
&lt;p&gt;Yet the virtues exposed by television are how &lt;strong&gt;entertaining&lt;/strong&gt; something
is. It becomes “How good can a president look?” rather than “is this a
good man?” We see that quite strongly today.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p. 135&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As Xenophanes remarked twenty-five centuries ago, men always make
their gods in their own image. But to this, television politics has
added a new wrinkle: Those who would be gods refashion themselves into
images the viewers would have them be.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Is this what gets Trump supporters so fanatic—to the point where they
cannot see his contradictions? What image does he portray that they wish
they had?&lt;/p&gt;
&lt;p&gt;One thing he projects is a disregard for the status quo. He’s also
fiercely tribal—people want an enemy they can scapegoat, and he leads
the charge against everyone and everything. People then feel like if
they’re on his team, they’re winning. What they think they’re
winning, I have no idea. But they seem to think that they are winning
&lt;em&gt;something&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That’s kind of like a game show: a meaningless contest of luck,
strength, trivia recall, etc. which is filmed in a futuristic studio.
Everything is automatic and accompanied by jazzy music and flashing
lights. Game shows are strange things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p. 141&lt;/strong&gt;: Television’s Censorship: television doesn’t &lt;em&gt;ban&lt;/em&gt;
books—it displaces them, which is just as bad. I’ve wished for a
super power—not to be invisible, but that no one would be able to
focus their attention on me and pay attention to what I am doing. It
would be far easier to get away with stuff if no one noticed you than it
would be if you were merely invisible: floating objects catch people’s
attention rather quickly!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p. 141&lt;/strong&gt;: Collateral learning: what do you learn outside of the
content of the lesson? Helping students develop the right attitudes
towards learning is important and tricky.&lt;/p&gt;
&lt;h2 id="teaching-as-an-amusing-activity-p-142"&gt;Teaching as an Amusing Activity (p. 142)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;p. 145&lt;/strong&gt;: Television makes new conceptions of knowledge and how it is
acquired. The Internet has compounded this a thousand fold: google it,
tweet it, stream it on-demand, etc.&lt;/p&gt;</description><author>Lambda Land</author><pubDate>Sun, 07 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lambdaland.org/posts/2020-06-07-amusing-ourselves-to-death/</guid></item><item><title>On real (digital?) convenience and real community</title><link>https://stop.zona-m.net/2020/06/on-real-digital-convenience-and-real-community/</link><description>&lt;p&gt;There is convenience that we cannot afford to refuse anymore.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sun, 07 Jun 2020 02:49:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/on-real-digital-convenience-and-real-community/</guid></item><item><title>CVE-2020-13254</title><link>https://3059274a.danpalmer-me.pages.dev/2020-06-07-django-memcache-vulnerability/</link><description>&lt;h1 id="information-exposure-vulnerability-with-django-and-memcached"&gt;Information Exposure Vulnerability with Django and Memcached&lt;/h1&gt;
&lt;p&gt;On Wednesday April 29th, Thread started experiencing a partial outage of our
main backend service. We traced the issue down to the existence of malformed
&lt;a href="https://www.memcached.org"&gt;Memcached&lt;/a&gt; keys and corrected the issue on &lt;a href="https://www.thread.com"&gt;thread.com&lt;/a&gt;.
Along the way we suspected that this could be exploited on some &lt;a href="https://www.djangoproject.com"&gt;Django&lt;/a&gt;
sites using Memcached to cause private data exposure – either internal service
data or data about other users. The only issue on Thread was HTTP 500 server
errors seen by a small number of users, no private data was leaked.&lt;/p&gt;</description><author>Dan Palmer</author><pubDate>Sun, 07 Jun 2020 02:00:00 GMT</pubDate><guid isPermaLink="true">https://3059274a.danpalmer-me.pages.dev/2020-06-07-django-memcache-vulnerability/</guid></item><item><title>Evolutionary Software Architecture</title><link>https://venam.net/blog/programming/2020/06/07/evolutionary-software-arch.html</link><description>In a previous post, I've underlined the philosophy behind Domain Driven Design, DDD, and now I'd like to move to a practical approach that handles real issues in software development and architecture, requirements that constantly change, and models that are never precise, never current, and/or never using the best technology available. One of the solution to such problems is to build an evolutionary architecture.</description><author>Venam's Blog — Patrick Louis (Lebanon)</author><pubDate>Sun, 07 Jun 2020 00:00:00 GMT</pubDate><guid isPermaLink="true">https://venam.net/blog/programming/2020/06/07/evolutionary-software-arch.html</guid></item><item><title>Terraform in AWS:  use AMI Names not IDs - and is Terraform the right answer still?</title><link>https://blog.herlein.com/post/terraform/</link><description>&lt;p&gt;In AWS the AMI ID for a particular VM image is unique to that region.  But it&amp;rsquo;s name is consistent across AWS.  When building infra-as-code (such as terraform) use the name, not the ID.  And some musings on terraform.  Is it still the right answer for infra-as-code?&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 06 Jun 2020 18:21:00 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/terraform/</guid></item><item><title>From C to exec: Part 3</title><link>https://dorotac.eu/posts/gcc_symbols/</link><description>&lt;h1&gt;From C to exec: Part 3&lt;/h1&gt;
&lt;p&gt;In &lt;a href="/posts/linking/"&gt;Previous&lt;/a&gt; &lt;a href="/posts/dynamic_linking/"&gt;parts&lt;/a&gt;, we followed a story of a piece of code transformed into a linked executable. The center stage was taken by symbols, around which the entire process of linking happens. They are the crucial component that lets us put programs fro multiple pieces. However, we watched what happens to symbols after they are there, but we haven't seen how to control their existence, and how to solve problems we may encounter.&lt;/p&gt;
&lt;p&gt;The third part focuses on practical problem solving related to symbols and C.&lt;/p&gt;
&lt;h2&gt;Emitting symbols in C&lt;/h2&gt;
&lt;p&gt;You might remember the term "translation unit". It's just a more convenient name for "a thing that is compiled together", the bunch of source files that result in a single object file. This simple definition will be used to refer to the sources as opposed to the object file.&lt;/p&gt;
&lt;p&gt;C does not support namespaces, so whenever you define a function under the same name in a different context (e.g. a logging function, an error handler or a container operation), they truly take the same name. This can lead to trouble. Let's introduce a new set of files: &lt;code&gt;floats.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
void print_number(float n) {
  printf("Float %f\n", n);
}

void multiply_by_tau(int number) {
  print_number(6.68 * number);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then &lt;code&gt;float.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void multiply_by_tau(int number);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, &lt;code&gt;main.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include "float.h"

void print_number(int number) {
  printf("Integer %d\n", number);
}

void power_of_two(int number) {
  print_number(2 &amp;lt;&amp;lt; number);
}

int main(void) {
  multiply_by_tau(100);
  power_of_two(10);
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we end up having two different functions called &lt;code&gt;print_number&lt;/code&gt;. One is in the translation unit with &lt;code&gt;main.c&lt;/code&gt;, the other in &lt;code&gt;float.c&lt;/code&gt;. They are only called from the relevant translation unit, so we should be fine, right?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c main.c -o main.o
# gcc -c float.c -o float.o
# nm main.o | grep print_number
0000000000000000 T print_number
# nm float.o | grep print_number
0000000000000000 T print_number
# gcc float.o main.o -o main
/usr/bin/ld: main.o: in function `print_number':
main.c:(.text+0x0): multiple definition of `print_number'; float.o:float.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not really. We emitted a symbol in both of them, and the linker doesn't know which one to choose. Oops. We have to tell the compiler explicitly that each of those functions will only ever be called from the same translation unit. C defines a keyword &lt;code&gt;static&lt;/code&gt; for this purpose. Let's check if it works. &lt;code&gt;float.c&lt;/code&gt; becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
static void print_number(float n) {
  printf("Float %f\n", n);
}

void multiply_by_tau(int number) {
  print_number(6.68 * number);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And &lt;code&gt;main.c&lt;/code&gt; now looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include "float.h"

static void print_number(int number) {
  printf("Integer %d\n", number);
}

void power_of_two(int number) {
  print_number(2 &amp;lt;&amp;lt; number);
}

int main(void) {
  multiply_by_tau(100);
  power_of_two(10);
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the compilation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c float.c -o float.o
# gcc -c main.c -o main.o
# gcc float.o main.o -o main
# ./main
Float 668.000000
Integer 2048
# nm main.o
0000000000000045 T main
                 U multiply_by_tau
0000000000000022 T power_of_two
                 U printf
0000000000000000 t print_number
# nm float.o
0000000000000024 T multiply_by_tau
                 U printf
0000000000000000 t print_number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Success! We turned&lt;code&gt;print_number&lt;/code&gt; into a &lt;a href="https://www.technovelty.org/code/why-symbol-visibility-is-good.html"&gt;&lt;em&gt;local symbol&lt;/em&gt;&lt;/a&gt;, (&lt;code&gt;t&lt;/code&gt; is lowercase) which is ignored during linking.&lt;/p&gt;
&lt;h2&gt;Keywords&lt;/h2&gt;
&lt;p&gt;C defines keywords for controlling linkage type. Those are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;extern&lt;/code&gt; for external linkage, i.e. emitting a symbol&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static&lt;/code&gt; for internal linkage, i.e. limiting usage to the current translation unit&lt;/li&gt;
&lt;li&gt;no keyword defaults to &lt;code&gt;extern&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, functions aren't the only items that can be assigned symbols. While any kind of memory area can get a symbol, global variables are the other most common usage. Let's see it all in action in &lt;code&gt;linkage.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int v_def = 0;
extern int v_ext = 0;
static int v_stat = 0;

void f_def(void) {};
extern void f_ext(void) {};
static void f_stat(void) {};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at the symbols shows us:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c linkage.c -o linkage.o
linkage.c:2:12: warning: ‘v_ext’ initialized and declared ‘extern’
    2 | extern int v_ext = 0;
      |            ^~~~~
# nm linkage.o
0000000000000000 T f_def
0000000000000007 T f_ext
000000000000000e t f_stat
0000000000000000 B v_def
0000000000000004 B v_ext
0000000000000008 b v_stat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As expected, the default is to emit a symbol, and &lt;code&gt;static&lt;/code&gt; makes the symbol local. But there's an unexpected warning from the compiler, suggesting that &lt;code&gt;extern&lt;/code&gt; on a variable does more than just emit a symbol for it. Let's try to apply compiler's advice and not assign any value in&lt;code&gt;variable.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern int v_ext;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at symbols:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c variable.c -o variable.o
# nm variable.o
#
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;…nothing? Let's try something else in &lt;code&gt;variable.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern int v_ext;

void use_variable(void) {
  v_ext = 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Symbols:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c variable.c -o variable.o
# nm variable.o
0000000000000000 T use_variable
                 U v_ext
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There it is, undefined! Without the body of the variable, the compiler took &lt;code&gt;extern&lt;/code&gt; to mean "not defined here" instead of "emit a symbol". No wonder that we didn't see its trace when we didn't try to make use of it. This is similar to &lt;em&gt;function prototypes&lt;/em&gt; we covered earlier.&lt;/p&gt;
&lt;p&gt;Notice that &lt;code&gt;U&lt;/code&gt; printed by the &lt;code&gt;nm&lt;/code&gt; program does not mean "symbol of the undefined kind present". Instead, it means "the relocation table calls for this symbol, but we don't have it". Here, &lt;code&gt;nm&lt;/code&gt; mixes up the symbol table and the relocations table, which can be confusing.&lt;/p&gt;
&lt;h2&gt;Using variables&lt;/h2&gt;
&lt;p&gt;Variables with the &lt;code&gt;extern&lt;/code&gt; symbol may sound confusing at first, but they work the same way functions do. Let's take an example of three files. First is &lt;code&gt;main_var.c&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include "var.h"

int main(void) {
  set_var(10);
  printf("var is %d\n", var);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file &lt;code&gt;var.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern int var;
extern void set_var(int v);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally, &lt;code&gt;var.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int var = 5;
void set_var(int v) {
  var = v;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compiling them shows us that both the &lt;code&gt;set_var&lt;/code&gt; function and the &lt;code&gt;var&lt;/code&gt; variable are needed by &lt;code&gt;main_var.c&lt;/code&gt;, and provided by &lt;code&gt;var.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c main_var.c -o main_var.o
# gcc -c var.c -o var.o
# gcc main_var.o var.o -o main_var
# ./main_var 
var is 10
# nm main_var.o
0000000000000000 T main
                 U printf
                 U set_var
                 U var
# nm var.o
0000000000000000 T set_var
0000000000000000 D var
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, we managed to modify a variable from a different file using a function from a different file, and then read it out directly. This mechanism is commonly used to give programs access to memory managed by a library.&lt;/p&gt;
&lt;h2&gt;Header file trouble&lt;/h2&gt;
&lt;p&gt;There is a situation is when a function clashes with itself. It sounds silly, but this can happen if the same function creates a symbol in multiple translation units.&lt;/p&gt;
&lt;p&gt;This usually happens when a function lives inside a header of a library we're using. Headers are not actually restricted to holding function prototypes, but instead they are fully fledged pieces of C code, verbosely included in the source file. Let's create &lt;code&gt;source.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const int before;
#include "header.h"
const int after;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And &lt;code&gt;header.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const int inside;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After running the C preprocessor, which happens as the first compilation step, we get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcc -E source.c
# 1 "source.c"
# 1 "&amp;lt;built-in&amp;gt;"
# 1 "&amp;lt;command-line&amp;gt;"
# 31 "&amp;lt;command-line&amp;gt;"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "&amp;lt;command-line&amp;gt;" 2
# 1 "source.c"
const int before;
# 1 "header.h" 1
const int inside;
# 3 "source.c" 2
const int after;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see here that the text from the header was indeed included in place of the &lt;code&gt;#include&lt;/code&gt; directive.&lt;/p&gt;
&lt;p&gt;Now, why would anyone actually &lt;em&gt;want&lt;/em&gt; to place a function in the header?&lt;/p&gt;
&lt;p&gt;As you can see, the inclusion of a full function inside header means that it will land in the translation unit of the &lt;em&gt;calling&lt;/em&gt; file, instead of the &lt;em&gt;providing&lt;/em&gt; file, unlike in our library examples. Here we don't even &lt;em&gt;have&lt;/em&gt; a separate "providing" file. We can see that our single translation unit contains what the header provided:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c source.c -o source.o
# nm source.o
0000000000000004 C after
0000000000000004 C before
0000000000000004 C inside
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The most obvious purpose for placing a function in the same translation unit as the caller is optimization. Making a function call is slow. In broad strokes, the compiled code usually saves a generic set of working data, as part of issuing a call and restores it as part of returning from it. But this doesn't make sense if our function is relatively simple. Sometimes it's more efficient to copy the contents of the function instead of calling it. The name for that is &lt;em&gt;inlining&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A call to a function in a dynamic library can't be inlined automatically. That would require some advanced processing at the time our program is starting. A call to a function in a static library can sometimes be inlined. That is called &lt;em&gt;link-time optimization&lt;/em&gt;, and it's done at linking time as a sort of additional, slow compilation step.&lt;/p&gt;
&lt;p&gt;On the other hand, a call to a function in the same translation unit can be inlined as part of the compilation process even before the linking, and without much additional penalty. If we place the body of our function in the header, this is exactly what we get, regardless of the kind of library we create in our other translation units.&lt;/p&gt;
&lt;p&gt;But what does this have to do with a symbol clashing with itself? Let's introduce an example of a library that must store something for bookkeeping, but doesn't want to be a burden for the calling code. Starting with &lt;code&gt;store.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int calls_made = 0;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Corresponding &lt;code&gt;store.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern int calls_made;

void log_call(void) {
  calls_made += 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, &lt;code&gt;user.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include "store.h"

void print_and_bump(void) {
  puts("Caller print");
  log_call();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Its &lt;code&gt;user.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void print_and_bump(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, &lt;code&gt;clash.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include "store.h"
#include "user.h"

int main(void) {
  puts("main print");
  log_call();
  print_and_bump();
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's try compiling and linking this project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c store.c -o store.o
# gcc -c user.c -o user.o
# gcc -c clash.c -o clash.o
# gcc store.o user.o clash.o -o clash
/usr/bin/ld: clash.o: in function `log_call':
clash.c:(.text+0x0): multiple definition of `log_call'; user.o:user.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's an error! Remember that we placed the &lt;code&gt;log_call&lt;/code&gt; function into the header file. That means that every translation unit including the header file will get a copy. We can see that this is what happened:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# nm store.o | grep log_call
# nm user.o | grep log_call
0000000000000000 T log_call
# nm clash.o | grep log_call
0000000000000000 T log_call
# gcc -E user.c
[...]
# 1 "store.h"
extern int calls_made;

void log_call(void) {
  calls_made += 1;
}
# 3 "user.c" 2
[...]
# gcc -E clash.c
[...]
# 1 "store.h"
extern int calls_made;

void log_call(void) {
  calls_made += 1;
}
# 3 "clash.c" 2
[...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The solution is straightforward. Let's change &lt;code&gt;store.h&lt;/code&gt; to show this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern int calls_made;

static void log_call(void) {
  calls_made += 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Linking test:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c user.c -o user.o
# gcc -c clash.c -o clash.o
# gcc store.o user.o clash.o -o clash
# nm clash.o | grep log_call
0000000000000000 t log_call
# nm user.o | grep log_call
0000000000000000 t log_call
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That did it! Our static function's symbol turned local, and stopped being a duplicate.&lt;/p&gt;
&lt;h2&gt;Inline woes&lt;/h2&gt;
&lt;p&gt;You might know the C99 keyword &lt;code&gt;inline&lt;/code&gt; already. It's meant to be a suggestion to the compiler that the function should be copied instead of called. It turns out that it affects linking.&lt;/p&gt;
&lt;p&gt;Taking the example from above and modifying it slightly, we get a new &lt;code&gt;store.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern int calls_made;

inline void log_call(void) {
  calls_made += 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you think that &lt;code&gt;inline&lt;/code&gt; implies no need for any sort of linking, you may be surprised:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -std=c99 -c user.c -o user.o
# gcc -std=c99 -c clash.c -o clash.o
# gcc store.o user.o clash.o -o clash
/usr/bin/ld: user.o: in function `print_and_bump':
user.c:(.text+0xf): undefined reference to `log_call'
/usr/bin/ld: clash.o: in function `main':
clash.c:(.text+0xf): undefined reference to `log_call'
collect2: error: ld returned 1 exit status
# nm user.o | grep log_call
                 U log_call
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I'm not going to dive into what exactly happened here, but it boils down to C99 designers wanting to avoid too many copies when inlining isn't possible. A symbol may still be needed for the function, as &lt;a href="https://gustedt.wordpress.com/2010/11/29/myth-and-reality-about-inline-in-c99/"&gt;explained&lt;/a&gt; by Jens Gustedt. That explanation offers a solution in the form of placing the following line into exactly one translation unit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern inline void log_call(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, use the &lt;code&gt;static&lt;/code&gt; version, although it may offer a different rate of success in inlining or emit too many copies.&lt;/p&gt;
&lt;h2&gt;Bad declaration&lt;/h2&gt;
&lt;p&gt;Remember that symbols don't carry type information? One of the most confusing problems is using something believing it's one type when in reality it's another. For a quick example, see a botched version check in file &lt;code&gt;version.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const char version[] = "10.1";
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The header &lt;code&gt;version.h&lt;/code&gt; has a mistake! The variable is declared as &lt;code&gt;int&lt;/code&gt; instead of &lt;code&gt;char&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extern const int version;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file &lt;code&gt;check.c&lt;/code&gt; is using the declaration from the header:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include "version.h"

int main(void) {
  printf("Version %d\n", version);
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And when it tries to read the &lt;code&gt;version&lt;/code&gt; variable…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c version.c -o version.o
# gcc -c check.c -o check.o
# gcc version.o check.o -o check
# ./check
Version 825110577
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That doesn't look right… Nowhere during the entire process was the type of the actual variable compared to the one declared in the header. The compiler believed what was the header file, the linker matched the symbol simply by name, and the mistake only appeared when we tried to execute the program.&lt;/p&gt;
&lt;p&gt;This time we got off easily, with an obvious problem. But the bugs can crash your code outright – if the type in the mistaken definition is larger than the actual type, or be subtle, if the wrong type is only slightly bigger and causes unrelated memory corruption, or when an &lt;code&gt;int&lt;/code&gt; is taken for a &lt;code&gt;float&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Your C++ compiler can catch some of those errors:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# g++ -c check.c -o check.o
# g++ -c version.c -o version.o
# g++ version.o check.o -o check
/usr/bin/ld: check.o: in function `main':
check.c:(.text+0x6): undefined reference to `version'
collect2: error: ld returned 1 exit status
# nm version.o
0000000000000000 r _ZL7version
# nm check.o
0000000000000000 T main
                 U printf
                 U version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately, C offers no solution but to always keep the headers correct!&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Those are the most common but annoying problems you may encounter which stem from the way C and symbols interact. If you're intrigued about some other linking problem, let me know about it. You can find me on the "about me" page.&lt;/p&gt;
&lt;h2&gt;Glossary&lt;/h2&gt;
&lt;p&gt;Important terms this episode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;inlining&lt;/em&gt; – copying a function's body instead of making a call&lt;/li&gt;
&lt;li&gt;&lt;em&gt;link-time optimization (LTO)&lt;/em&gt; – attempting to inline functions while linking, across translation unit boundaries&lt;/li&gt;
&lt;/ul&gt;</description><author>dcz's posts</author><pubDate>Sat, 06 Jun 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/gcc_symbols/</guid></item><item><title>Tu YouYou's speech at the 2002 China-Africa Forum on Traditional Medicine</title><link>https://walkabout165.blogspot.com/2020/06/tu-youyous-speech-at-2002-china-africa.html</link><description>There is a famous person who really should be a lot more famous, even after having earned the Nobel Prize in Physiology or Medicine in 2015. Her name is Tu YouYou.&amp;nbsp; She discovered artemisinin, which is now the first line malaria medication for infected cases.&amp;nbsp; What's even more interesting and perhaps more deserving of fame (in light of the result of course) was that she did so by mining traditional medicine systems, in this case Traditional Chinese Medicine, to find this therapeutic.&amp;nbsp; This is one of those medications that are probably most easily and appropriately termed a 'cure', although the medical profession looks down at that term for anything because of the expectations it instills in the patient and their loved ones (and there's always an exception, complication, or side effect in some small number of patients relative to the total number of treated).&lt;br /&gt;
&lt;br /&gt;
Anyway I was at the KEnya Medical Research Institute hq the other day, in their Traditional Medicine Research department.&amp;nbsp; There was a binder there from 2002 with the agenda and speeches from an Africa-China traditional medicine research convocation in Beijing.&amp;nbsp; There was a speech of hers inside, and I was given permission to transcribe it.&amp;nbsp; Here it is:&lt;br /&gt;
&lt;br /&gt;
"&lt;br /&gt;
&lt;br /&gt;
China-Africa Forum on Traditional Medicine convened from 20-22 October in Beijing&lt;br /&gt;
&lt;br /&gt;
Qinghaosu [ed. note: Artemisinin] - the Crystal of Traditional Anti-malaria Chinese Medicine&lt;br /&gt;
&lt;br /&gt;
Tu Youyou&lt;br /&gt;
Director, Research Center for Qinghao and Qinghaosu, China Academy of Traditional Chinese Medicine, Beijing, 100700, China&lt;br /&gt;
&lt;br /&gt;
I am a researcher from the China Academy of traditional Chinese medicine.&amp;nbsp; Traditional Chinese medicine (TCM) with its unique theory is shaped from the long history of medical practice and experiences accumulation of the Chinese nation.&amp;nbsp; TCM protects the development and multiplication of the nation.&amp;nbsp; THe flourishing of TCM today is based on the continuous invention nad innovation in its history.&amp;nbsp; In 11th century BC, anatomic terms of human body and descriptions of a number of diseases were recorded by inscriptions on bones and tortoise shells.&amp;nbsp; The Yellow Emperor's Internal Classic (Qin dynasty and Han dynasty) and Treatise on Diseases (by Zhang Zhongjing, East Han dynasty) establish the theoretical basis of TCM, and guided the clinical practice of the medicine.&amp;nbsp; Medicine and drugs are inseparable.&amp;nbsp; Chinese herbal medicine has a long history as the one of TCM.&amp;nbsp; Over a hundred of herbal medicines and treatment and/or prevention for dozens of diseases are registered in Canon of mountains and Sea (3rd century BC). Historical Record carries the following message " Shen Nong (the god of agriculture) tasted hundreds of herbs and initiated the medicine".&amp;nbsp; Shen Nong is certainly a legend character.&amp;nbsp; However, Shen Nong's Herbal Classic is a reality.&amp;nbsp; It carries 365 kinds medicines from herbal, animal and mineral origins.&amp;nbsp; The newly-revised Materia Medica (659 AD) was implemented in Tang dynasty. In 1578 , the well-known Compendium of Materia Medica was completed by Li Shizhen of Ming dynasty, and printed the cut blocks in 1593. After founding of new China, the Academy of Traditional Chinese Medicine, affiliated to the Ministry of Health, was set up in 1955. In 1983, seven WHO collaborating centers for TCM in China were established. The Institute of Chinese Materia Medica, China Academy of TCM is one of them.&lt;br /&gt;
&lt;br /&gt;
In 1960's, malaria was epidemic when Vietnam was in the flames of war. It has been an urgent need for new antimalarial drugs due to the problem of chloroquine-resistant strains of P. Facliparum. Globally, hundreds of millions of people were annually suffered from the disease, and the mortality was increased sharply. A large scale screening for antimalarial drugs was carried out home and abroad at that time, without satisfactory results. Our project for developing new antimalarial drugs was set up under the above mentioned situation in 1969. Malaria is a common disease for the world, and recorded in a medical literature (12 century, BC) in China.&amp;nbsp; I graduated from the Department of Pharmacy, Beijing Medical College, and systematically studied TCM after employed.&amp;nbsp; I firmly believe that TCM with this long history is a great treasure-house, and efforts should be made to explore its essence. On the basis of collection and analysis of traditional prescriptions, over two hundreds of herbs and three hundreds and eighty abstracts from them were screened by malarial models of mouse or monkey.&amp;nbsp; The screening showed positive results in October, 1971. We isolated and purified the effective compound from the traditional Chinese herb, Artemisia annua L, in 1972. It was named Qinghaosu after the herb's pronunciation in Chinese. Qinghaosu showed 100% inhibition to malaria parasites for monkey and mouse.&amp;nbsp; In 1973, clinical trials verified the efficacy of Qinghaosu. A new antimalarial drug was finally appeared. Qinghaosu is a compound of sesquiterpene lactone with a peroxide. It is just what we were looking for - the antimalarial drug with totally new chemical structure. The antimalarial effect of Artemisia annua L was firstly described in "The handbook of prescriptions for emergencies" compiled by Ge Hong (281-340 AD), the physician and alchemist in East Jin dynasty. The invention of Qinghaosu is benefited from TCM. It is a good illustration of the treasure and essence in TCM and the potential for contribution to the world medicine. Qinghaosu is a drug with high efficacy, fast-action and safe. In October of 1981, I delivered a talk on the chemical research of Qinghaosu during the international symposium of Qinghaosu held in Beijing. The talk evoked great attention. Qinghaosu was appreciated as "a new antimalarial drug with importance of pointing direction for drug synthesis and design". New drug certificate for Qinghaosu was issued as the first category drug in 1986, and the one for dihydro-Qinghaosu later on. Dihydro-Qinghaosu is a derivative of Qinghaosu with two hydroxides. It provides basis for further development of derivatives of Qinghaosu. The achievements gained the National Invention Award and the Top Ten National Award for Progress in Science and Technology accordingly.&lt;br /&gt;
&lt;br /&gt;
For our good wishes, the 21st century should be a better one with magnificent prospects. Although we can roam in the heavens, and the world is connected closely by the internet, but we still have to face the cruel facts of local wars and life-threatening diseases.&amp;nbsp; Malaria is still a dangerous enemy to mankind in the new century. An airplane crash may kill hundreds of people, and results in an impact of shake and grief for the living people for a long time to come.&amp;nbsp; However, we sometimes neglect the significant tragedy. Malaria, as the tropical disease, is cruelly killing the poor people in the developing countries. Some 500 million infections are globally reported, and some 3,000 children are killed daily in Africa only.&amp;nbsp; The simple figures tell us that ten abuses [editors note: Airbuses probably] full of children were crashed every day. What a nightmare to the mankind! We get to fight back. "Roll back malaria" is the fighting target for the new century setup by WHO. I believe Qinghaosu and its derivatives are the right weapons for the combat. We sincerely hope that the invention of Qinghaosu will save thousands of endangered people from the verge of death daily. Research Center for Qinghao and Qinghaosu was established at the China Academy of TCM due to the invention of Qinghaosu. The center carries out systematic researches on Qinghaosu, and gains new progresses in compound prescriptions with better therapeutic efficacy ( increased 7.6 folds ) and in new applications of Qinghaosu.&amp;nbsp; We are looking forward to cooperating with our African colleagues. I heartily hope that Qinghaosu will contribute more for the benefit of human health in the 21st century and for the bright future of mankind.&lt;br /&gt;
&lt;br /&gt;
"&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</description><author>The Walkabout Blog</author><pubDate>Sat, 06 Jun 2020 16:20:36 GMT</pubDate><guid isPermaLink="true">https://walkabout165.blogspot.com/2020/06/tu-youyous-speech-at-2002-china-africa.html</guid></item><item><title>lightdriver</title><link>https://www.anfractuosity.com/projects/lightdriver/</link><description>I created a PMOD module PCB using KiCAD, that enables connecting WS2812B lighting strips to an FPGA board with a PMOD interface. The board was assembled by JLCPCB. This is my first project using an FPGA, I plan to soon implement an SPI interface with the FPGA, to accept colour pixels via SPI from a [&amp;#8230;]</description><author>Anfractuosity</author><pubDate>Sat, 06 Jun 2020 14:32:57 GMT</pubDate><guid isPermaLink="true">https://www.anfractuosity.com/projects/lightdriver/</guid></item><item><title>Black Lives Matter</title><link>https://blog.herlein.com/post/blm/</link><description>&lt;p&gt;We all protest and effect change in our own ways.  I choose mentorship, education, and work - because that&amp;rsquo;s what I can do best to make a difference.&lt;/p&gt;</description><author>Greg Herlein</author><pubDate>Sat, 06 Jun 2020 11:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.herlein.com/post/blm/</guid></item><item><title>FatturaElettronica for .NET v3.0 released</title><link>https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.0-released/</link><description>It features full support for latest specifications by the Italian Public Administration (v1.6), and is now delivered with a single package model.</description><author>Nicola Iarocci</author><pubDate>Sat, 06 Jun 2020 08:05:25 GMT</pubDate><guid isPermaLink="true">https://nicolaiarocci.com/fatturaelettronica-for-.net-v3.0-released/</guid></item><item><title>Emacs, search hackingwithswift.com</title><link>https://xenodium.com/emacs-search-hackingwithswiftcom</link><description>&lt;p&gt;&lt;img alt="" src="https://xenodium.github.io/images/emacs-search-hackingwithswiftcom/hws.gif" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/twostraws"&gt;Paul Hudson&lt;/a&gt; authors excellent Swift material at &lt;a href="https://www.hackingwithswift.com/"&gt;hackingwithswift.com&lt;/a&gt;. I regularly land on the site while searching for snippets from the browser. I was wondering if I could search for snippets directly from Emacs.&lt;/p&gt;
&lt;p&gt;Turns out, hackingwithswift uses a JSON HTTP request for querying code examples. With this in mind, we can use &lt;em&gt;ivy-read&lt;/em&gt; like Oleh Krehel's &lt;a href="https://github.com/abo-abo/swiper/blob/8d840b2e8680e2768edb794c9ccecf975f6ba4cf/counsel.el#L6680"&gt;counsel-search&lt;/a&gt; and search for Swift snippets from our favorite editor:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-{.commonlisp"&gt;(require 'request)
(require 'json)

(defun ar/counsel-hacking-with-swift-search ()
  &amp;quot;Ivy interface to query hackingwithswift.com.&amp;quot;
  (interactive)
  (ivy-read &amp;quot;hacking with swift: &amp;quot;
            (lambda (input)
              (or
               (ivy-more-chars)
               (let ((request-curl-options (list &amp;quot;-H&amp;quot; (string-trim (url-http-user-agent-string)))))
                 (request
                   &amp;quot;https://www.hackingwithswift.com/example-code/search&amp;quot;
                   :type &amp;quot;GET&amp;quot;
                   :params (list
                            (cons &amp;quot;search&amp;quot; input))
                   :parser 'json-read
                   :success (cl-function
                             (lambda (&amp;amp;key data &amp;amp;allow-other-keys)
                               (ivy-update-candidates
                                (mapcar (lambda (item)
                                          (let-alist item
                                            (propertize .title 'url .url)))
                                        data)))))
                 0)))
            :action (lambda (selection)
                      (browse-url (concat &amp;quot;https://www.hackingwithswift.com&amp;quot;
                                          (get-text-property 0 'url selection))))
            :dynamic-collection t
            :caller 'ar/counsel-hacking-with-swift-search))
&lt;/code&gt;&lt;/pre&gt;</description><author>xenodium.com @alvaro</author><pubDate>Sat, 06 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://xenodium.com/emacs-search-hackingwithswiftcom</guid></item><item><title>Java agent - Bond or Smith?</title><link>https://zserge.com/posts/javaagent/</link><description>The previous post about JVM turned out to be well-received, so I would like to uncover another fun topic related to JVM - Java agents. Although not everyone gets a chance to write custom Java agents in his career, they are still a wonderful field to explore and open an endless way to customize JVM behavior.
Java agents are special in the way that JVM allows them to do much more than a regular Java app is allowed to: they can instrument or profile code, hot-swap classes, patch methods, etc.</description><author>zserge's blog</author><pubDate>Sat, 06 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/javaagent/</guid></item><item><title>Booting Gentoo from SAR-Preinit; or Debugging the init, the Hard Way</title><link>https://wantguns.dev/blog/booting-gentoo-using-preinit/</link><description>&lt;p&gt;As you would know from my previous &lt;a href="https://wantguns.dev/blog/uart-on-lavender/"&gt;blog&lt;/a&gt;, I couldn't make the UART work for my phone. Since without a serial console, the boot-up process is no less than a black-box, I decided to use some hacky debugs for finding out what went wrong with the original &lt;code&gt;preinit&lt;/code&gt;. If you're not in for the process of going through it and just want to cut to the chase, jump onto this &lt;a href="https://wantguns.dev/blog/booting-gentoo-using-preinit/#final-comments-and-what-to-follow-next"&gt;section&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="circumventing-system-as-root"&gt;Circumventing System-As-Root&lt;/h2&gt;
&lt;p&gt;So, flashing a &lt;code&gt;preinit&lt;/code&gt; failed for me. Again this was because of the changes in the boot-process of newer Android devices. If you have no clue about this, I would recommend reading this &lt;a href="https://wantguns.dev/blog/android-boot-high-jinks/"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What we needed to change was the behaviour of our kernel to take the &lt;code&gt;ramdisk&lt;/code&gt; provided to it in the &lt;code&gt;boot.img&lt;/code&gt; as its &lt;code&gt;rootfs&lt;/code&gt;. @topjohnwu suggested in his &lt;a href="https://forum.xda-developers.com/apps/magisk/pixel-2-pixel-2-xl-support-t3697427/post74361728#post74361728" rel="external"&gt;infamous xda comment&lt;/a&gt; that it could be achieved by substituting the &lt;code&gt;skip_ramdisk&lt;/code&gt; string with any other. I tried doing this but it make the device boot straight up to Lineage (which we do not want).&lt;/p&gt;
&lt;p&gt;Then I looked into what goes on under-the-hood when Magisk is flashed. It seems that Magisk hexpatches the kernel with some specfic strings which ultimately leads the kernel to take the ramdisk inside &lt;code&gt;boot.img&lt;/code&gt; as its &lt;code&gt;rootfs&lt;/code&gt;.
I double checked by cpio'ing the &lt;code&gt;magiskinit64&lt;/code&gt; binary into an &lt;code&gt;ramdisk.cpio&lt;/code&gt; incpio and then patching the kernel image using &lt;code&gt;magiskboot&lt;/code&gt;, in a similar fashion to that of Magisk. Then packed the stuff into a &lt;code&gt;boot.img&lt;/code&gt; (ofc including a bootimg.cfg).&lt;/p&gt;
&lt;p&gt;Now remember, since we have patched the kernel, the kernel would take the &lt;code&gt;magiskinit64&lt;/code&gt; as its init and exec it. Then &lt;code&gt;magiskinit64&lt;/code&gt; would ultimately mount &lt;code&gt;/system&lt;/code&gt; as root and exec the &lt;code&gt;/system/bin/init&lt;/code&gt; thus entering the Android land.&lt;/p&gt;
&lt;p&gt;And so we did. Lineage booted up. To cross-check, I also tried to boot using a boot.img without &lt;code&gt;magiskinit64&lt;/code&gt; as its init. It did not reach the Android land.&lt;/p&gt;
&lt;p&gt;And so I adopted this approach for circumventing SAR. But using &lt;code&gt;preinit&lt;/code&gt; as the init inside &lt;code&gt;boot.img&lt;/code&gt; still did not boot Gentoo up. So we come to the debugging phase.&lt;/p&gt;
&lt;h2 id="the-debugging-phase-skippable"&gt;The Debugging Phase (skippable)&lt;/h2&gt;
&lt;p&gt;The lack of a serial console, made me come up with some ugly debugs. First I tried to access the &lt;code&gt;last_kmsg&lt;/code&gt; and &lt;code&gt;console-ramoops-0&lt;/code&gt; for getting the kernel logs from the previous reboot. But I didn't get any. I double checked my kernel defconfig whether I had the correct options enabled and yes they were.&lt;/p&gt;
&lt;p&gt;At this point, I wan't even unhappy. Time for a new debug method. What occured to me next was that we could &lt;code&gt;sleep&lt;/code&gt; the init script between certain steps and time the process of my phone bootlooping. For a reference value, I recorded the time it took my phone to boot-loop without any &lt;code&gt;sleep&lt;/code&gt;. I prepared myself for a night of constant phone reboots. The table below describes the entire process until finally booting Gentoo with insightful comments at the end.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style="text-align: center;"&gt;Attempt&lt;/th&gt;&lt;th style="text-align: center;"&gt;Time (in sec)&lt;/th&gt;&lt;th style="text-align: center;"&gt;Remarks&lt;/th&gt;&lt;th style="text-align: center;"&gt;Commit&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;1&lt;/td&gt;&lt;td style="text-align: center;"&gt;10&lt;/td&gt;&lt;td style="text-align: center;"&gt;reference&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/2037d2b9523f9c954b18d6efe85c803cac432563" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;2&lt;/td&gt;&lt;td style="text-align: center;"&gt;20&lt;/td&gt;&lt;td style="text-align: center;"&gt;test &lt;code&gt;sleep&lt;/code&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/195c4d40a30bd412c8574d670432098ed1fd4ed9" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;3&lt;/td&gt;&lt;td style="text-align: center;"&gt;30&lt;/td&gt;&lt;td style="text-align: center;"&gt;failed to mount at &lt;code&gt;/userdata&lt;/code&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/15c1f7ae1c60983141f5f96e82d47c924e075d53" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;4&lt;/td&gt;&lt;td style="text-align: center;"&gt;41&lt;/td&gt;&lt;td style="text-align: center;"&gt;kernel panics&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/b373d65a132363d58d608d354e82f1469cc3d289" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;5&lt;/td&gt;&lt;td style="text-align: center;"&gt;41&lt;/td&gt;&lt;td style="text-align: center;"&gt;abandoning this approach&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/a5b6ac35c2822fb516bc471f4387a784308f94d3" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;6&lt;/td&gt;&lt;td style="text-align: center;"&gt;21&lt;/td&gt;&lt;td style="text-align: center;"&gt;couldn't mount &lt;code&gt;/dev&lt;/code&gt;&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/3db8942d0c31cc3b3184962a4eea403cc6e49bc5" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;7&lt;/td&gt;&lt;td style="text-align: center;"&gt;35&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;code&gt;/dev&lt;/code&gt; is mounted&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/4af274df4fcda6ad05c63e6d8caca3cd3c422b47" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;8&lt;/td&gt;&lt;td style="text-align: center;"&gt;60+&lt;/td&gt;&lt;td style="text-align: center;"&gt;Gentoo boots&lt;/td&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commit/f786531094daf77b7a0877177f9888d5d9e9b750" rel="external"&gt;link&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ol start="3"&gt;
&lt;li&gt;At this point, I found out that the kernel could mount the userdata partition. I also realised that I was not getting last_ksmg because the kernel was not panicking and instead just &lt;code&gt;exit&lt;/code&gt;ing. So I tried to get the &lt;code&gt;last_kmsg&lt;/code&gt; next.&lt;/li&gt;
&lt;li&gt;I tried to forcefully panic the kernel. And got the &lt;code&gt;last_kmsg&lt;/code&gt; and &lt;code&gt;console-ramoops-0&lt;/code&gt; in the next boot. But they didnt have the parts where kernel logged the Preinit messages. So I thought that giving them a higher priority would make them get picked by the &lt;code&gt;last_kmsg&lt;/code&gt; and it didn't help either.&lt;/li&gt;
&lt;li&gt;Finally I abandoned this approach.&lt;/li&gt;
&lt;li&gt;Then I looked into mounting the pseudo-filesystems. I realised that the kernel could not mount /dev.&lt;/li&gt;
&lt;li&gt;I realised that using &lt;code&gt;tmpfs&lt;/code&gt; instead of &lt;code&gt;devtmpfs&lt;/code&gt; mounts the &lt;code&gt;/userdata&lt;/code&gt;. What I did not know at that time that my kernel did not have the options for &lt;code&gt;devtmpfs&lt;/code&gt; enabled in its &lt;code&gt;defconfig&lt;/code&gt;, this all could be avoided.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dev&lt;/code&gt; mounts now, but we have to populate it as well.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I did not have just 8 attempts, the &lt;a href="https://gitlab.com/WantGuns/sar-preinit/-/commits/timer" rel="external"&gt;commit history&lt;/a&gt; would show that I forgot that my kernel was SELinux Enforcing, I had to change that among many other things. Robert Landley's &lt;a href="https://landley.net/writing/" rel="external"&gt;blogs&lt;/a&gt; on initramfs helped me get to know the very basics of an initramfs.&lt;/p&gt;
&lt;h2 id="final-comments-and-what-to-follow-next"&gt;Final comments and What to follow next&lt;/h2&gt;
&lt;p&gt;My &lt;a href="https://gitlab.com/WantGuns/sar-preinit" rel="external"&gt;sar-preinit&lt;/a&gt; repository holds the current workflow of getting a SAR-enabled device boot Gentoo in the Android based device. The Makefile is pretty self-explanatory but still, if you want to follow the process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install Gentoo in you phone following this &lt;a href="https://wantguns.dev/blog/install-gentoo/"&gt;blog&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Extract the &lt;code&gt;boot.img&lt;/code&gt; from you Android phone. At the time of writing this blog, we dont have changing &lt;code&gt;selinux&lt;/code&gt; modes automated. Please make sure that you do that first by adding &lt;code&gt;androidboot.selinux=permissive&lt;/code&gt; string at the end of the kernel commandline in &lt;code&gt;bootimg.cfg&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Rename &lt;code&gt;boot.img&lt;/code&gt; to &lt;code&gt;ogboot.img&lt;/code&gt; and place it inside the artifacts folder.&lt;/li&gt;
&lt;li&gt;Fire up a terminal and run&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-entity z-name z-function"&gt;make&lt;/span&gt;&lt;span class="z-string"&gt; bootimg_chute&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start="5"&gt;
&lt;li&gt;Flash the &lt;code&gt;boot_mod.img&lt;/code&gt; created inside the &lt;code&gt;out&lt;/code&gt; directory on your phone, preferably using &lt;code&gt;fastboot boot&lt;/code&gt;, if you're not that confident. &lt;code&gt;fastboot boot&lt;/code&gt; somehow doesn't work for my device, but that's going off-track.&lt;/li&gt;
&lt;li&gt;Since we haven't figured out the Android in LXC part yet, the best you could do to check your Gentoo boot, is to reboot into the recovery, fire up adb and check the &lt;code&gt;/data/gnu/var/log/&lt;/code&gt; directory for &lt;code&gt;dmesg&lt;/code&gt; or any other logs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I plan to merge this entire workflow into SharkBait, so that you don't have to go through the hassle of doing it all.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I should have already mentioned this somewhere, but if I didn't, I should tell the readers that all is based on the &lt;a href="https://www.shark-bait.org/" rel="external"&gt;SharkBaitOS&lt;/a&gt; established mostly by @KireinaHoro. The &lt;a href="https://github.com/KireinaHoro/preinit" rel="external"&gt;&lt;code&gt;preinit&lt;/code&gt;&lt;/a&gt; I used as a template was the original one from SharkBaitOS. In order to have a better understanding about this project I would recommend the readers to have a look at &lt;a href="https://jsteward.moe/" rel="external"&gt;KireinaHoro's Blogs&lt;/a&gt; as well.&lt;/p&gt;
&lt;p&gt;In my next blog, I will discuss about getting Android 9+ to work inside a LXC-Container, in the Gentoo land. I have yet to achieve doing that myself. Hopefully we will reach there soon.&lt;/p&gt;
&lt;p&gt;Until then, Happy Hacking !&lt;/p&gt;</description><author>Gunwant Jain - @wantguns</author><pubDate>Sat, 06 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://wantguns.dev/blog/booting-gentoo-using-preinit/</guid></item><item><title>Generating a REST API from a database</title><link>http://notes.eatonphil.com/generating-a-rest-api-from-a-database.html</link><description>&lt;p&gt;I recently published an &lt;a href="https://eatonphil.github.io/dbcore/"&gt;alpha version of a code generation tool,
DBCore,&lt;/a&gt; that reads a database
schema from PostgreSQL or MySQL and generates an entire Go API with
CRUD operations, pagination, filtering, and authentication.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://pbs.twimg.com/media/EZJ7TvNXQAEgraD?format=png&amp;amp;name=large" /&gt;&lt;/p&gt;
&lt;p&gt;But more than just generating code like
&lt;a href="https://github.com/xo/xo"&gt;xo/xo&lt;/a&gt; or &lt;a href="https://gnorm.org/"&gt;gnorm&lt;/a&gt;,
DBCore defines a standard REST API that can be implemented in any
language -- and includes a reference implementation in Go. I'm eager
to add Java and Ruby implementations as well. And I'd be more than
happy to accept community contributions.&lt;/p&gt;
&lt;h3 id="boilerplate-&amp;amp;-code-generation"&gt;Boilerplate &amp;amp; code generation&lt;/h3&gt;&lt;p&gt;Web application boilerplate is boring. You should do it once from
scratch (preferably down to the socket layer) and never do it again. I
struggled for the last few years to find the right system to reduce
boilerplate. If I were building a new line-of-business application as
an employee I'd pick one of Rails, ASP.NET, Spring, Django, or
similar.&lt;/p&gt;
&lt;p&gt;I've never worked on one of those frameworks professionally and I've
never been able to force myself to learn any of them in my free
time. But even if I could use one of these, none of them get close to
giving you an entire functioning application with authentication,
pagination, filtering all based on your existing database.&lt;/p&gt;
&lt;p&gt;Over the last few years though I've relied heavily on code generation
for Go projects. Code generation is basically the only way to conserve
type-safe code in Go. But it's similarly
&lt;a href="https://www.jooq.org/doc/3.13/manual/code-generation/"&gt;popular&lt;/a&gt; in
more powerful languages like Java.&lt;/p&gt;
&lt;p&gt;However none of the existing projects give you much flexibility or
provide you with enough templates to be useful.&lt;/p&gt;
&lt;h3 id="dbcore"&gt;DBCore&lt;/h3&gt;&lt;p&gt;DBCore is written in F# and can be distributed as a static
binary on all systems .NET now supports (read: not just Windows!).&lt;/p&gt;
&lt;p&gt;Reading from MySQL or PostgreSQL is supported but I'd like to see that
extended to include SQLite, Oracle, and MS SQL at least.&lt;/p&gt;
&lt;p&gt;As mentioned, currently DBCore only provides a Go REST API
template. That only solves half the problem of building an application
though. And while there are some projects that can generate an admin
CRUD interface for you, I want to see that more tightly integrated
into DBCore. So I'll be introducing a new template for a browser
application as well. For each table in the database it will generate a
page showing paginated entries and allow you to create, update, and
delete.&lt;/p&gt;
&lt;p&gt;Finally, while the tool only currently has a concept of "browser" and
"api" templates, the project should be able to accept any kind of
template and generate any text based on any database schema.&lt;/p&gt;
&lt;p&gt;&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;New blog post, background and goals for dbcore&lt;a href="https://t.co/XW9gUCtvr0"&gt;https://t.co/XW9gUCtvr0&lt;/a&gt;&lt;/p&gt;&amp;mdash; Phil Eaton (@phil_eaton) &lt;a href="https://twitter.com/phil_eaton/status/1269467766727327745?ref_src=twsrc%5Etfw"&gt;June 7, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;/p&gt;</description><author>Notes on software development</author><pubDate>Sat, 06 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://notes.eatonphil.com/generating-a-rest-api-from-a-database.html</guid></item><item><title>How to remove DNS record takeover bug class ?</title><link>https://badshah.io/blog/remove-domain-takeover-bug-class/</link><description>Dangling DNS records are not something new. They are just out-of-date DNS records which may have served its purpose in the past. This DNS record trash has been there for ages and was not considered a security issue. They are pointing to some resource (IP or DNS record) that was owned/trusted in the past.
What makes the dangling DNS record deadly is the fact that others can seize the resources that the record is pointing to.</description><author>Chandrapal Badshah | Security Engineer on Chandrapal Badshah</author><pubDate>Fri, 05 Jun 2020 21:30:00 GMT</pubDate><guid isPermaLink="true">https://badshah.io/blog/remove-domain-takeover-bug-class/</guid></item><item><title>Why and how to avoid slow Internet Access Networks</title><link>https://stop.zona-m.net/2020/06/why-and-how-to-avoid-slow-internet-access-networks/</link><description>&lt;p&gt;We may learn from North Dakota (if we ask all the right questions)&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 05 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/why-and-how-to-avoid-slow-internet-access-networks/</guid></item><item><title>Which files do they edit</title><link>https://peterlyons.com/problog/2020/06/which-files-do-they-edit/</link><description>&lt;p&gt;When hopping in to an unfamiliar git repo, if it's a big sprawling repo or even a monorepo, it can be hard to know which parts are relevant. Well, if you know someone on your team's name, I have a script that can give you a pretty solid clue.&lt;/p&gt;
&lt;p&gt;Here's the pipeline and explanations.&lt;/p&gt;
&lt;pre class="language-sh "&gt;&lt;code class="language-sh"&gt;# Show me the hash of every commit by someone named Doe
# for the last 3 months
git log --author=&amp;#x27;Doe&amp;#x27; --pretty=format:%H --since=&amp;quot;3 months ago&amp;quot;

# Now show me the files changed in each of those commits
  xargs -n 1 git diff-tree --no-commit-id --name-only -r |

# now remove duplicates and count how many commits per file
  sort |
  uniq -c |
  sort -nr
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--since&lt;/code&gt; has pretty intuitive natural language processing so you can easily adjust that. &lt;code&gt;--author&lt;/code&gt; seems to work on portions of either name or email.&lt;/p&gt;
&lt;p&gt;For example, here's a snippet of the files Eric Dobbertin has been changing in the main reaction commerce repo the last 6 months.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git log --author=&amp;#x27;Dobbertin&amp;#x27; --pretty=format:%H --since=&amp;quot;3 months ago&amp;quot; |
  xargs -n 1 git diff-tree --no-commit-id --name-only -r |
  sort |
  uniq -c |
  sort -nr

     19 package-lock.json
     14 package.json
     10 plugins.json
     10 jest.config.cjs
      7 tests&amp;#x2f;integration&amp;#x2f;api&amp;#x2f;mutations&amp;#x2f;createProduct&amp;#x2f;createProduct.test.js
      6 tests&amp;#x2f;util&amp;#x2f;factory.js
      6 tests&amp;#x2f;integration&amp;#x2f;api&amp;#x2f;mutations&amp;#x2f;createProductVariant&amp;#x2f;createProductVariant.test.js
      6 src&amp;#x2f;mockTypes.graphql
      5 tests&amp;#x2f;integration&amp;#x2f;api&amp;#x2f;queries&amp;#x2f;taxServices&amp;#x2f;taxServices.test.js
      5 tests&amp;#x2f;integration&amp;#x2f;api&amp;#x2f;queries&amp;#x2f;ordersByAccountId&amp;#x2f;ordersByAccountId.test.js
      5 tests&amp;#x2f;integration&amp;#x2f;api&amp;#x2f;queries&amp;#x2f;catalogItemProduct&amp;#x2f;catalogItemProduct.test.js
      5 tests&amp;#x2f;integration&amp;#x2f;api&amp;#x2f;queries&amp;#x2f;anonymousCartByCartId&amp;#x2f;anonymousCartByCartId.test.js
&lt;/code&gt;&lt;/pre&gt;</description><author>Pete's Points</author><pubDate>Fri, 05 Jun 2020 05:02:45 GMT</pubDate><guid isPermaLink="true">https://peterlyons.com/problog/2020/06/which-files-do-they-edit/</guid></item><item><title>Examining the complex web of USD stable coins</title><link>https://omarabid.com/usd-stable-coins/</link><description>A brief look on some USD stable coins</description><author>Omar Abid - Personal Blog</author><pubDate>Fri, 05 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://omarabid.com/usd-stable-coins/</guid></item><item><title>Dark Mode For Excalidraw</title><link>https://francoisbest.com/posts/2020/dark-mode-for-excalidraw?utm_source=rss</link><description>How to give a dark twist to Excalidraw diagrams with CSS filters.</description><author>Articles by François Best</author><pubDate>Fri, 05 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://francoisbest.com/posts/2020/dark-mode-for-excalidraw?utm_source=rss</guid></item><item><title>Mark Zuckerberg may have just realized he is Prof. Falken</title><link>https://stop.zona-m.net/2020/06/mark-zuckerberg-may-have-just-realized-he-is-prof.-falken/</link><description>&lt;p&gt;Because everybody grows up, at last. Hopefully.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 04 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/mark-zuckerberg-may-have-just-realized-he-is-prof.-falken/</guid></item><item><title>Devlog #0: vision and goals</title><link>https://domwillia.ms/devlog0</link><description>This post aims to introduce my ambitious, long-term gamedev project, along with my vision and long term goals for it. In essence, it could be described as a deep simulation, not unlike and very much inspired by Dwarf Fortress and Rimworld.</description><author>Dom Williams</author><pubDate>Thu, 04 Jun 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://domwillia.ms/devlog0</guid></item><item><title>Why I Keep a Research Blog</title><link>http://gregorygundersen.com/blog/2020/01/12/why-research-blog/</link><description>&lt;p&gt;Gregory Gundersen, in writing &lt;a href="http://gregorygundersen.com/blog/2020/01/12/why-research-blog/"&gt;&lt;em&gt;Why I Keep a Research Blog&lt;/em&gt;&lt;/a&gt;, might as well have just written a post on why &lt;em&gt;everyone&lt;/em&gt; should blog. I have talked about this &lt;a href="https://zacs.site/blog/own-your-platform.html"&gt;before&lt;/a&gt;, and how you can &lt;a href="https://zacs.site/blog/how-to-own-your-platform.html"&gt;get started today with a handful of free services&lt;/a&gt;; I hope you will.&lt;/p&gt;


                &lt;p&gt;&lt;a href="http://gregorygundersen.com/blog/2020/01/12/why-research-blog/"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Thu, 04 Jun 2020 14:05:19 GMT</pubDate><guid isPermaLink="true">http://gregorygundersen.com/blog/2020/01/12/why-research-blog/</guid></item><item><title>Not impossible prosthetics</title><link>https://stop.zona-m.net/2020/06/not-impossible-prosthetics/</link><description>&lt;p&gt;here is a project that you want to know about.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Wed, 03 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/not-impossible-prosthetics/</guid></item><item><title>crickybo</title><link>https://rjp.is/blogging/crickybo/</link><description>Alas, due to the current world situation, crickybo is on lockdown.
Fediverse: @crickybo@social.rjp.is Twitter Telegram</description><author>infrequent oscillations</author><pubDate>Wed, 03 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/crickybo/</guid></item><item><title>Beginning in Beige</title><link>http://spirals.blog/articles/beige-introduction/</link><description>&lt;h2&gt;What is consciousness?&lt;/h2&gt;
&lt;p&gt;Welcome to the journey of Spiral Dynamics! You’re in a great place to begin picking up some of the basics of this beautiful model. If you haven’t already, please read the &lt;a href="https://spirals.blog/articles/what-is-spiral-dynamics"&gt;What is Spiral Dynamics&lt;/a&gt; introduction. Let’s begin!&lt;/p&gt;
&lt;p&gt;For us to understand any developmental model as it pertains to humans, it would be wise to start at the very beginning. Where did we begin to think in the first place?&lt;/p&gt;
&lt;p&gt;While defining human consciousness and it’s origins is undoubtedly out of scope for this article (and definitely above our pay grade) it’s important to briefly address this question before laying the foundations of specific colors.&lt;/p&gt;
&lt;p&gt;There are hundreds of theories as to why Sapiens rose from their other Homo cousins. Some argue that humans developed our ability to observe through our binocular vision, and by looking out in the distance, over time, we started to notice patterns. In combination with our social structures that we developed to survive, this may have kick-started the “grey matter upgrade.” Others argue that it arose out of language generated from the collective words that were forming. Bicameralism suggests that commands are being sent in the brain and expressed through auditory experiences (eventually words expressed as thought). Some believe that consciousness may have been triggered by naturally occurring psychedelics, providing a “boot loader” for human thoughts and self-observation.&lt;/p&gt;
&lt;p&gt;Whichever the case (and perhaps we’ll never honestly know), it began some time ago. One could imagine the world was very different back then. No cities, or religions, planes, or sliced bread. Just humans and the wild.&lt;/p&gt;
&lt;h2&gt;The Agent, and the Arena&lt;/h2&gt;
&lt;p&gt;For us to understand Spiral dynamics and it’s true potential, we must understand the relationship between the subjective experience, and our objective reality (or Life Conditions). This connection is sometimes referred to as the &lt;a href="https://www.youtube.com/watch?v=39NpjQDtqNw"&gt;Agent/Arena relationship&lt;/a&gt; wherein there is a party acting in some expected fashion for the arena in which they’re involved.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Doctors" src="http://spirals.blog/articles/beige-introduction/doctors.jpg" /&gt;
&lt;em&gt;Photo by Piron Guillaume @gpiron&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Take a doctor, for instance, in their arena of a hospital. There are things we expect them to do, ways to behave, and beliefs to hold. One would expect their doctor to value cleanliness and have a high standard of personal hygiene, maintain confidentiality, and always have your best interest at heart. When this agent operates in accordance with the arena they’re situated in, they’re considered “successful”. However, if there is some imbalance (doctors writing subscriptions you don’t need for commissions), we could say they’re out of balance in that relationship.&lt;/p&gt;
&lt;p&gt;These two forces, the agent and area, form the double helix from which Spiral grows. As human beings solve the problems of the world (arena), they live in, with more complex issues arise, a different agent/arena relationship. This cycle continues indefinitely, growing more complex and broader in scope as we solve problems.&lt;/p&gt;
&lt;h2&gt;The Beige problem&lt;/h2&gt;
&lt;p&gt;Many moons ago, our ancestors were walking the earth as foragers and hunters. Living a nomadic life in the animal kingdom creates its challenges. It is these conditions that produce the seeding ground for Spiral to begin.&lt;/p&gt;
&lt;p&gt;The Agent/Arena relationship also applies to the stages in Spiral Dynamics. For our forefathers roaming the savannahs of Africa, they were an agent in a perilous arena. Humans were living in small bands of no more than around 150 people providing two options if you lived back then. &lt;em&gt;Are you with the tribe, or are you on your own?&lt;/em&gt; This article is an introduction to Beige, the stage of human development, existential awareness, and perspective that evolved to deal with this harsh, base reality.&lt;/p&gt;
&lt;div class="disclaimer"&gt;
&lt;h3&gt;A note from one learner to another&lt;/h3&gt;
&lt;p&gt;Problems in Spiral Dynamics are an incredibly broad and fascinating topic, which, when studied, offer deep insights into human patterns and self-awareness. It is worth explicitly noting that one article is not in the least bit sufficient to explain the complexities of an entire color. These become subjects you will spend an entire lifetime discovering, discussing, and learning.&lt;/p&gt;
&lt;p&gt;So as we step through our journey, be mindful to not “simplify a color” into &lt;a href="https://spirals.blog/articles/behaviour-vs-intention/"&gt;just a behavior&lt;/a&gt;, or identify with &lt;a href="https://spirals.blog/articles/wholearchy/"&gt;“higher colors” because they seem “cool”&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;If we were to take ourselves back to that time of our ancestors, what problems were we likely to have had? Food would probably have been a significant concern, with most of the day spent searching for it, hunting it, or trying to grow it. Shelter from the elements, perhaps in caves or forests. Sex and reproduction would also have taken up much of our awareness and is still a major biological challenge we experience to this day.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Beige Arena:&lt;br /&gt;
A wild, survival-focused, base reality. Predominant concerns are food, water, shelter, sex, and safety.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Suffice to say; life was relatively simple to us looking back on it now. However, I’m sure it was not viewed as simple back then. So what happened between now and then for us to consider that lifestyle basic?&lt;/p&gt;
&lt;h2&gt;The Beige Perspective&lt;/h2&gt;
&lt;p&gt;Someone in a Beige existence operates automatically. They are driven by bodily urges and respond to physical base desires. In Beige, we simply survive. Eat or be eaten. Our goal is solely to make it through the night or day.&lt;/p&gt;
&lt;p&gt;With so much focus on the core problems, this reality presents very little (if any) consideration is given to more complex concepts. Time, the future, society, or the ‘self’ are not in the awareness of someone in Beige.&lt;/p&gt;
&lt;h3&gt;Manifestations of Beige today&lt;/h3&gt;
&lt;p&gt;We can observe Beige in infants. Before we transition into more complex states of awareness, we rely solely on those around us to provide and nurture us. It is only later in life as we grow older and develop more of a sense of self that we’re able to step out into our own being.&lt;/p&gt;
&lt;p&gt;Beige is often represented in minorities who have experienced unfortunate illness or significant trauma. If we grow to be senile as we get older, this too could shift us into a Beige reality. We rely on the kindness and compassion (and sometimes the unfortunate guilt) of those around us to be kept alive.&lt;/p&gt;
&lt;p&gt;As with any color, we should hold no judgment in our understanding of Spiral towards any perspective or environment. Every individual is struggling with their own existential experience, and to compare them is to miss the point entirely. Beige uncovers it’s unique challenges, as does Purple, Red, and so on (which we will get to in later articles). This perspective does &lt;strong&gt;not&lt;/strong&gt; necessarily mean stupid or lacking for any human, group, or organization, only that they struggle with the life conditions that Beige creates.&lt;/p&gt;
&lt;p&gt;For example, if a violent earthquake were to shake the ground beneath your feet suddenly, your city would be thrown into turmoil. Instantly, whoever present would “down-shift” into a Beige perspective to deal with the recent change of environment. It is fair to say that our focus would be on self-preservation and of those around us that we care about and little else. &lt;em&gt;The report that you were working on that was due at lunch ceases to exist in your mind.&lt;/em&gt; Such is the adaptive and resilient nature of the human brain. We’re able to shift perspectives to suit the given problem at hand.&lt;/p&gt;
&lt;h2&gt;Leaving Beige&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Tribe" src="http://spirals.blog/articles/beige-introduction/tribe.jpg" /&gt;
&lt;em&gt;Photo by Bradford Zak @2721poipu&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It is suffice to say that the grand potential of consciousness is not limited to the perspective of the Beige environment. So how did we go from hunting and gathering to where we are today?&lt;/p&gt;
&lt;p&gt;As with any color that deals with external life conditions in a given arena, we can address the existential problems. What does this look like in Beige?&lt;/p&gt;
&lt;p&gt;Perhaps some bands of humans discover that, separately, they’re bear food; however, together the bear is &lt;em&gt;their&lt;/em&gt; food. The competition between the groups of our ancestors over territory, food, mates, and resources was realized to be harmful to all involved. Replaced with a newer perspective of the possibilities of forming larger tribes, humans began to shift their perspectives to “safety in numbers”.&lt;/p&gt;
&lt;p&gt;This transition freed up more cognitive resources for observing other aspects of our surroundings. If merely “surviving” was no longer our only concern, on what then could we focus? One might argue that humans developed their intensive quest for meaning once they no longer needed to think about if they were going to eat that night. “What &lt;strong&gt;is&lt;/strong&gt; this place we all seem to be in?”. “Who are the people that I’m living with, and what are they motivated by?”. These newfound questions bring about more complex emotions (something a Beige does not have a conception of) towards those around us, more significant events, and our environment.&lt;/p&gt;
&lt;p&gt;Reflected in magic, rain dances, totems and trinkets, and a strong sense of community, we left behind the lonely limitations of Beige, dancing instead towards the tribal conditions and safety of Purple.&lt;/p&gt;</description><author>A Matter of Perspective</author><pubDate>Wed, 03 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">http://spirals.blog/articles/beige-introduction/</guid></item><item><title>Compiling AutoDock Vina on iOS</title><link>https://web.navan.dev/posts/2020-06-02-Compiling-AutoDock-Vina-on-iOS.html</link><description>Compiling AutoDock Vina on iOS</description><author>Navan's Archive</author><pubDate>Wed, 03 Jun 2020 02:23:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-06-02-Compiling-AutoDock-Vina-on-iOS.html</guid></item><item><title>Making AWS Amplify work with Rollup</title><link>https://www.swyx.io/making-aws-amplify-work-with-rollup-2d9m</link><description>AWS Amplify assumes CommonJS, which Rollup is allergic to. I recently discovered that you can make it work with Rollup with a few tweaks.</description><author>swyx's site RSS Feed</author><pubDate>Wed, 03 Jun 2020 01:22:28 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/making-aws-amplify-work-with-rollup-2d9m</guid></item><item><title>On Frugal Innovation, again</title><link>https://stop.zona-m.net/2020/06/on-frugal-innovation-again/</link><description>&lt;p&gt;Where to look for REAL innovation? In large companies, or &amp;ldquo;at the bottom of the pyramid&amp;rdquo;?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Tue, 02 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/on-frugal-innovation-again/</guid></item><item><title>Claquette - Animated Screenshots</title><link>https://thomas.zoechling.me/journal/2020/06/Claquette.html</link><description>&lt;div&gt;&lt;p&gt;&lt;em&gt;This post was originally written as &lt;a href="https://blog.eternalstorms.at/2016/09/28/guest-blog-post-the-story-behind-claquette-animated-screenshots/"&gt;guest entry on the Eternal Storms Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Animated GIF is not a good video format. &lt;br /&gt;Actually it even isn't a proper video format because it lacks random access and audio support. Nonetheless animated GIFs &lt;a href="http://www.popularmechanics.com/technology/a21457/the-gif-is-dead-long-live-the-gif/"&gt;experienced a rennaisance&lt;/a&gt; in recent years. &lt;br /&gt;My theory is, that the format's success doesn't stem from the features it has, but from the ones it lacks:&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;No random access: Defaults to autoplay – No playback interaction needed&lt;/li&gt;
&lt;li&gt;No sound: Guarantees silence – Always "Safe for Work"&lt;/li&gt;
&lt;li&gt;No support for 32bit colors: Moderate file sizes and a characteristic look&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Given those constraints, GIFs are a great way to communicate simple concepts or interactions. &lt;br /&gt;Want to showcase an animation or an application feature? Instead of a static screenshot with paragraphs of text, a 3 second GIF works equally well and also draws more attention.&lt;/p&gt;&lt;p&gt;In my daily life as software developer, I often need a quick way to capture graphical bugs. Those clips can be easily shared with colleagues or included with bug reports. &lt;br /&gt;Sometimes it's also simpler to attach a GIF to customer support requests instead of explaining how a certain feature works. &lt;br /&gt;To cover my own needs, I wrote a small macOS application that allows me to record the screen and export the result as animated GIF. The app uses a custom recording codec and also covers the rest of the GIF creation workflow like crop, trim and file size optimization.   &lt;/p&gt;&lt;p&gt;You can &lt;a href="https://itunes.apple.com/app/claquette-animated-screenshots/id587748131?mt=12"&gt;download Claquette&lt;/a&gt; from the Mac App Store. For detailed product information, please &lt;a href="https://www.peakstep.com/claquette"&gt;visit our website&lt;/a&gt;.&lt;/p&gt;&lt;h2&gt;Development&lt;/h2&gt;&lt;p&gt;​When I started to implement the Animated GIF feature for Claquette, I began with a naïve approach. &lt;br /&gt;Armed with several years of experience in writing Objective-C and some knowledge about video APIs on the Mac, I wrote a small prototype. 
That first version just read a video file frame by frame and sent the resulting frames to ImageIO. ImageIO is a system framework that supports reading and writing several file formats.
It also comes with a basic Animated GIF encoder and so I decided to skip any third party libraries and just use the built-in mechanisms of macOS. &lt;br /&gt;I was able to come up with a working prototype in a single afternoon. The program was just a simple command line utility, but it was able to turn an arbitrary video file into an animated GIF.  &lt;/p&gt;&lt;p&gt;There was just one problem... Or actually there were several of them: Due to the inner workings of ImageIO, the program used vast amounts of memory. Also, the encoding took very long and the files it created were huge. On top of all that, the resulting GIFs looked horrible. &lt;br /&gt;So while it only took me one Sunday afternoon to create a working prototype, it took me several months to fix the above issues. Especially the large file size and the bad visual appearance of the resulting GIFs required a lot of research.&lt;/p&gt;&lt;h2&gt;Getting the most out of a 30 year old file format&lt;/h2&gt;&lt;p&gt;The original GIF specification (GIF87a) was written in 1987 - almost 30 years ago. Animation features were added in GIF89a, which is still the &lt;a href="https://www.w3.org/Graphics/GIF/spec-gif89a.txt"&gt;most recent version&lt;/a&gt; of the format. &lt;br /&gt;So how is it possible that a file format designed for low resolution screens and 256 colors is still in use today? &lt;br /&gt;It turns out that the GIF specification contains some sections that open room for exploitation. Additionally the visual nature of GIFs allows for optimizations, that trick human color perception.&lt;/p&gt;&lt;p&gt;The format is simple and has the following basic structure:&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Header&lt;/li&gt;
&lt;li&gt;Logical Screen Descriptor&lt;/li&gt;
&lt;li&gt;Global Color Table&lt;/li&gt;
&lt;li&gt;Graphic Control Extension    (Frame #1)&lt;ul&gt;
&lt;li&gt;Delay &lt;/li&gt;
&lt;li&gt;Disposal Method&lt;/li&gt;
&lt;li&gt;Local Color Table&lt;/li&gt;
&lt;li&gt;Image Descriptor&lt;/li&gt;
&lt;li&gt;Image Data&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Graphic Control Extensions   (Frame #2) &lt;/li&gt;
&lt;li&gt;Graphic Control Extension    (Frame #3)&lt;/li&gt;
&lt;li&gt;...                          (1 GCE for each animation frame)&lt;/li&gt;
&lt;li&gt;Trailer&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Header and Trailer are basically just magic numbers that mark the start and the end of the file. The Logical Screen Descriptor contains some general image information like width, height and background color. The Global Color Table is a simple list of colors that may contain a maximum of 256 entries. &lt;br /&gt;Main image information is stored in one ore more Graphic Control Extension blocks.&lt;/p&gt;&lt;h2&gt;Color Table Generation&lt;/h2&gt;&lt;p&gt;The color table sections of the format specification are a good starting point to optimize the visual quality of an animated GIF. &lt;br /&gt;Both palettes are restricted by the format's infamous 256 color limit. When reducing an image that uses 32bit (16777216 colors, 256 alpha values) to 8bit (255 colors, 1 alpha bit) it becomes really important &lt;em&gt;which&lt;/em&gt; colors you leave out. The process of reducing large palettes to small ones is called &lt;a href="https://en.wikipedia.org/wiki/Color_quantization"&gt;Color Quantization&lt;/a&gt;. Choosing a good quantization algorithm is crucial when aiming for visually similar images with a reduced palette. &lt;br /&gt;Naïve quantization implementations are based on occurrence, where seldom used colors are left out in the final image. More elaborate algorithms use techniques like &lt;a href="https://en.wikipedia.org/wiki/Median_cut"&gt;dimensional clustering&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Octree"&gt;tree partitioning&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;When developing for Apple devices there are several libraries that provide color quantization functionality. macOS and iOS even have basic color quantization algorithms built-in. Apple's implementation is part of the ImageIO framework's CGImageDestination API.&lt;/p&gt;&lt;p&gt;The following sample images were created using different quantization techniques. They illustrate the quality impact of the used algorithm on the final image.&lt;/p&gt;&lt;p&gt;&lt;img src="https://thomas.zoechling.me/journal/2020/06/Claquette/CGImageDestinationQuantization.gif" style="width: 500px;" /&gt;&lt;br /&gt;The first image shows the output of &lt;a href="https://developer.apple.com/reference/imageio/1666386-cgimagedestination#"&gt;CGImageDestination&lt;/a&gt;. The resulting colors are noticeably off. Apple's encoder also messes up the transparency color in the GIF palette, which leads to holes in some areas of the image (e.g. the titlebar). &lt;br /&gt;
&lt;br /&gt;
&lt;img src="https://thomas.zoechling.me/journal/2020/06/Claquette/FFmpegQuantization.gif" style="width: 500px;" /&gt;&lt;br /&gt;The open source library &lt;a href="https://www.ffmpeg.org"&gt;FFmpeg&lt;/a&gt; also includes a color quantizer. FFmpeg produces way better results than CGImageDestination. The colors are more vibrant and the transparency color is set correctly. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;img src="https://thomas.zoechling.me/journal/2020/06/Claquette/ClaquetteQuantization.gif" style="width: 500px;" /&gt;&lt;br /&gt;The color quantization library used by Claquette also outputs a good choice of colors. Additionally the app performs color matching to avoid color shifts and to guarantee correct gamma values.&lt;/p&gt;&lt;h2&gt;Frame Difference Calculation&lt;/h2&gt;&lt;p&gt;Another important factor during GIF generation is efficient frame difference calculation. &lt;br /&gt;The disposal mode in the Graphic Control Extension allows an encoder to specify how the context is set up before the next frame gets rendered. &lt;br /&gt;GIF89a defines 4 disposal modes:  &lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Unspecified: Replaces the existing canvas with the full contents of the current frame. &lt;/li&gt;
&lt;li&gt;Do not Dispose: Leaves the existing canvas as-is and composites the current (sub)frame over it. &lt;/li&gt;
&lt;li&gt;Restore to Background: Sets a defined background color and draws the current frame. Areas outside of the subsection in the Image Descriptor shine through. &lt;/li&gt;
&lt;li&gt;Restore to Previous: Fully restores the canvas to the last frame that did not specify a disposal method. &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The Image Descriptor section can be used to define a sub-image which does not provide pixel data for a full frame.  Instead it contains coordinates and pixel data for a subsection of the full image. 
By using frame differences and sub-images with a proper disposal mode, redundant image data can be avoided. Depending on the nature of the input video, this can greatly reduce the file size of the final GIF. &lt;br /&gt;Modern video codecs like H.264 use techniques like macro blocks and motion compensation. Those methods introduce small errors that propagate from frame to frame. Propagated errors show up as noise when calculating frame diffs and eventually lead to unnecessary large files. &lt;br /&gt;Claquette uses a custom lossless codec, that only stores regions that actually changed. This guarantees exact  frame diffs.&lt;/p&gt;&lt;p&gt;The following images show the difference between frame #1 and frame #2 of a screen recording. The only effective change between those frames is a change in the mouse cursor location. An exact diff should therefore only contain an offsetted cursor image. &lt;/p&gt;&lt;p&gt;&lt;img src="https://thomas.zoechling.me/journal/2020/06/Claquette/FFmpegDiff.gif" style="width: 500px;" /&gt;&lt;br /&gt;The above diff image was created between 2 frames of an H.264 encoded movie. The visible noise is a result of intra-frame encoding errors.&lt;/p&gt;&lt;p&gt;&lt;img src="https://thomas.zoechling.me/journal/2020/06/Claquette/ClaquetteDiff.gif" style="width: 500px;" /&gt;&lt;br /&gt;The second image was created by Claquette's image diff algorithm. It only contains the mouse cursor - The only image element that actually changed between frame #1 and #2.&lt;/p&gt;&lt;h2&gt;Finishing Touches&lt;/h2&gt;&lt;p&gt;After implementing technical details like encoding and optimization, there were still some features missing. Claquette needed an editing UI to handle the whole GIF creation workflow. &lt;br /&gt;As I wanted to keep the app lightweight and simple to use, I decided to add only a small set of editing capabilities: Trim and Crop. &lt;br /&gt;Claquette uses AVFoundation, and therefore I was able to use the AVPlayer class, which comes with a built-in trim tool. &lt;br /&gt;Crop functionality was a bit harder to implement. AVFoundation doesn't provide any UI component to display crop handles so I had to implement my own. &lt;br /&gt;Besides the standard drag &amp;amp; move interface, my implementation also provides some unique features. It offers alignment guides with haptic feedback and the possibility to enter crop coordinates.&lt;/p&gt;&lt;p&gt;You can see the final implementation of the crop utility in the animated GIF below. &lt;br /&gt;
&lt;img src="https://thomas.zoechling.me/journal/2020/06/Claquette/ClaquetteCrop.gif" style="width: 500px;" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Launch&lt;/h2&gt;&lt;p&gt;To launch the animated GIF feature, I prepared a press kit and wrote mails to review sites that mostly cover Mac software. &lt;br /&gt;Additionally I submitted the app to &lt;a href="https://www.producthunt.com/"&gt;Product Hunt&lt;/a&gt; and informed Apple's App Store Marketing team. &lt;br /&gt;I can really recommend to launch on Product Hunt: &lt;a href="https://www.producthunt.com/tech/claquette"&gt;Claquette received over 400 upvotes&lt;/a&gt; and finished in the top 3 on launch day. The site also hosts a friendly community, that makes extensive use of the Q&amp;amp;A section below each hunted product. &lt;br /&gt;I was also lucky to get some mentions from &lt;a href="https://twitter.com/steipete/status/757595361880014848"&gt;high profile Twitter users&lt;/a&gt; and good App Store reviews. &lt;br /&gt;Two weeks after launch, Apple suddenly moved Claquette into the "New and Noteworthy" feature section on the Mac App Store front page. Of course this also lead to a noticeable spike in the sales charts. &lt;br /&gt;Overall I was very pleased with the release and the reception of Claquette 1.5.&lt;/p&gt;
&lt;/div&gt;</description><author>Build and Run</author><pubDate>Tue, 02 Jun 2020 18:37:01 GMT</pubDate><guid isPermaLink="true">https://thomas.zoechling.me/journal/2020/06/Claquette.html</guid></item><item><title>First Crack Release Notes, May 2020</title><link>https://zacs.site/blog/first-crack-release-notes-0520.html</link><description>&lt;p&gt;I have wanted to add this to First Crack for a while now, and this month, I finally did it: First Crack now supports post categories. &lt;/p&gt;
                &lt;p&gt;&lt;a href="https://zacs.site/blog/first-crack-release-notes-0520.html"&gt;Permalink.&lt;/a&gt;&lt;/p&gt;</description><author>Zac Szewczyk</author><pubDate>Tue, 02 Jun 2020 15:30:20 GMT</pubDate><guid isPermaLink="true">https://zacs.site/blog/first-crack-release-notes-0520.html</guid></item><item><title>Recursion</title><link>https://arunmani.in/library/recursion/</link><description>First ever sci-fi novel I have ever read. As always time machines are dangerous.</description><author>Arun Mani</author><pubDate>Tue, 02 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://arunmani.in/library/recursion/</guid></item><item><title>UART on Xiaomi Redmi Note 7</title><link>https://wantguns.dev/blog/uart-on-lavender/</link><description>&lt;p&gt;This blog is a short sequel to my previous &lt;a href="https://wantguns.dev/blog/android-boot-high-jinks/"&gt;blog&lt;/a&gt; where I discussed why I needed to access a serial console on Redmi Note 7 (I'll refer to it using its codename, lavender here onwards). I should give a disclaimer that this blog is one dead-end in the GSoC2020 series. But it could always help newcomers and other curious souls.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="the-need-of-a-serial-console"&gt;The Need of a Serial Console&lt;/h2&gt;
&lt;p&gt;My first attempt at porting SharkBait for SAR failed. I was confident about the approach but had trouble finding out what went wrong. If only somehow I could get the kernel logs before my phone went into the bootloop, I could quickly provide fixes.&lt;/p&gt;
&lt;p&gt;Fortunately that is when I found &lt;a href="https://wiki.postmarketos.org/wiki/Xiaomi_Redmi_Note_7_(xiaomi-lavender)" rel="external"&gt;this article&lt;/a&gt; from the awesome guys at PostMarketOS. My device had a serial console built in. Accessing it via UART could provide the logs I required.&lt;/p&gt;
&lt;p&gt;So I followed the process described there and disassembled my phone, soldered the required jumper wires to the GPIO pins mentioned in the article and was ready for connecting it to a convertor.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Please excuse the potato quality of the upcoming images.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;div class="imageClass"&gt;
    &lt;figure class="center"&gt;
        &lt;img alt="Opening the back" class="center" src="https://wantguns.dev/blog/uart-on-lavender/smallfull.jpg" /&gt;
        
            &lt;figcaption class="center"&gt;
                Opening the back
            &lt;/figcaption&gt;
        
    &lt;/figure&gt;
&lt;/div&gt;
&lt;div class="imageClass"&gt;
    &lt;figure class="center"&gt;
        &lt;img alt="GPIO pins" class="center" src="https://wantguns.dev/blog/uart-on-lavender/smallpins.jpg" /&gt;
        
            &lt;figcaption class="center"&gt;
                Soldered the wires on the GPIO pins
            &lt;/figcaption&gt;
        
    &lt;/figure&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;h2 id="pl2303hxa"&gt;PL2303HXA&lt;/h2&gt;
&lt;p&gt;After that, I connected the jumper wires to the PL2303HXA convertor I bought and quickly fired up a &lt;code&gt;screen&lt;/code&gt; session, excited to look at the console output.&lt;/p&gt;
&lt;p&gt;But there was &lt;a href="https://youtu.be/UGSwtv_PKHE" rel="external"&gt;no output&lt;/a&gt;. You can see that the convertor's RX LED is blinking when the phone boots up, but there is no output on the console end.&lt;/p&gt;
&lt;p&gt;I consulted around with people at PostMarketOS and the SharkBait IRC chat. KireinaHoro asked me to grab a multimeter and check out the voltage the UART operated on. The GPIO pins were at a voltage difference of 1.8V with the ground. I came to the realisation that the PL2303 could not interpret signals with voltage that low. So I decided to buy another convertor, about which I was sure to read signals at 1.8V.&lt;/p&gt;
&lt;h2 id="ft232r"&gt;FT232R&lt;/h2&gt;
&lt;p&gt;&lt;div class="imageClass"&gt;
    &lt;figure class="center"&gt;
        &lt;img alt="FT2303R based convertor" class="center" src="https://wantguns.dev/blog/uart-on-lavender/smallFT232R.jpg" /&gt;
        
            &lt;figcaption class="center"&gt;
                FT232R based convertor
            &lt;/figcaption&gt;
        
    &lt;/figure&gt;
&lt;/div&gt;
&lt;div class="imageClass"&gt;
    &lt;figure class="center"&gt;
        &lt;img alt="FT2303R" class="center" src="https://wantguns.dev/blog/uart-on-lavender/smallfinal.jpg" /&gt;
        
            &lt;figcaption class="center"&gt;
                Final Product
            &lt;/figcaption&gt;
        
    &lt;/figure&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;With my fingers crossed, I fired up another &lt;code&gt;screen&lt;/code&gt; shell, and finally got &lt;em&gt;some&lt;/em&gt; output.
But all I got were the logs thrown by the Bootloader. I needed the kernel logs because the &lt;code&gt;init&lt;/code&gt; is launched by the kernel. And so yet again, I went to chat with Alexey from PostMarketOS who is working on lavender. He informed me that the vendor's downstream kernel for lavender would not give any UART logs for some reason &lt;a href="https://github.com/minlexx/android_kernel_xiaomi_lavender/blob/lineage-16.0/arch/arm/boot/dts/qcom/sdm660-pinctrl.dtsi#L69" rel="external"&gt;(related)&lt;/a&gt;. To get the kernel logs via UART, we would have to use the mainline kernel, but that would mean no android for us.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;So I had two options :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Work on bringing UART to lavender by patching the vendor's downstream kernel. But this would take a lot of time from a &lt;em&gt;very&lt;/em&gt; beginner kernel hacker like me. Also it would be rather too off-topic from my original GSoC journey.&lt;/li&gt;
&lt;li&gt;Abandon UART altogether. I had some very hacky debugs in mind which I could use. It would take some time to yield a fruitful result but this was a lower hanging fruit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And so, I chose the second option.&lt;/p&gt;
&lt;p&gt;Which I am very glad to share, worked out. As of yesterday, I was finally able to boot Gentoo via the preinit, but all that's for another blog (coming tomorrow).&lt;/p&gt;</description><author>Gunwant Jain - @wantguns</author><pubDate>Tue, 02 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://wantguns.dev/blog/uart-on-lavender/</guid></item><item><title>Anxiety rules...</title><link>https://stop.zona-m.net/2020/06/anxiety-rules.../</link><description>&lt;p&gt;but most of it is NOT Coronavirus' fault.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Mon, 01 Jun 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/06/anxiety-rules.../</guid></item><item><title>From C to exec: Part 2</title><link>https://dorotac.eu/posts/dynamic_linking/</link><description>&lt;h1&gt;From C to exec: Part 2&lt;/h1&gt;
&lt;p&gt;The &lt;a href="/posts/linking/"&gt;last part&lt;/a&gt; explored static linking, but stopped before actually executing our executable. If you think this was all the linking, you're in for a surprise!&lt;/p&gt;
&lt;p&gt;This post is best followed using the code from the previous part.&lt;/p&gt;
&lt;h2&gt;Act 1: Unexpected symbol&lt;/h2&gt;
&lt;h3&gt;Scene 1: Undefined?&lt;/h3&gt;
&lt;p&gt;Did you notice the lonely symbol in the last act? Let's call it forth:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c -o printer.o printer.c
# ar rcs libprinter.a printer.o
# nm libprinter.a

printer.o:
0000000000000000 T print_hello
                 U puts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's a lonely "Undefined" symbol! And where did it even come from? Remember &lt;code&gt;printer.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
void print_hello(void) {
  puts("Hello World!\n");
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We call &lt;code&gt;puts&lt;/code&gt;, but we never define it… Previously, when we tried to use a symbol that we didn't define, gcc refused to finish the linking, but here it works:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc hello.o libprinter.a -o hello
# ./hello
Hello World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What gives?&lt;/p&gt;
&lt;h3&gt;Scene 2: Deus ex library&lt;/h3&gt;
&lt;p&gt;Before we solve the mystery, let me throw another hint towards the solution: &lt;code&gt;puts&lt;/code&gt; is hidden in a library! More specifically, it's in libc:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# nm /lib64/libc.so.6 | grep puts
[…]
0000000000073280 W puts
[…]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, "W" means it's a "weak" but defined symbol.&lt;/p&gt;
&lt;p&gt;We know where the lost symbol is, and where it's missing from. But we still don't know the connection between the two places! The newest trace we have is the &lt;code&gt;/lib64/libc.so.6&lt;/code&gt; file...&lt;/p&gt;
&lt;h3&gt;Scene 3: Dynamic libraries&lt;/h3&gt;
&lt;p&gt;We're familiar with static libraries already. They have the &lt;code&gt;.a&lt;/code&gt; file ending, and they are an ingredient for the executable, and are no longer used after linking. But another variety exists. Like static libraries, it contain symbols, but its usefulness extends beyond linking time, and into the actual execution. They are called &lt;em&gt;dynamic libraries&lt;/em&gt;, and their file names traditionally end with &lt;code&gt;.so&lt;/code&gt;, for "shared object".&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# file /lib64/libc.so.6
/lib64/libc.so.6: symbolic link to libc-2.29.so
# file /lib64/libc-2.29.so
/lib64/libc-2.29.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=51377236ad01808e26404c98faa41d72f11a46a5, for GNU/Linux 3.2.0, not stripped, too many notes (256)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;libc.so.6&lt;/code&gt; is one of them.&lt;/p&gt;
&lt;h3&gt;Scene 4: Reconstruction&lt;/h3&gt;
&lt;p&gt;If we want to make progress on the story of the misplaced &lt;code&gt;puts&lt;/code&gt;, we need to understand dynamic libraries. Time to create our own!&lt;/p&gt;
&lt;p&gt;We already created a static library before, so let's use the same procedure, but make a dynamic one this time:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -fPIC -c printer.c -o printer.o
# gcc -shared printer.o -o libprinter.so
# file libprinter.so
libprinter.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=dd2595216f9c10b317ab3dbece8450a31fcaf672, not stripped
# nm libprinter.so | grep hello
0000000000001109 T print_hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The procedure is similar to building a static library, except packaging with &lt;code&gt;ar&lt;/code&gt; was replaced by another linking step (with &lt;code&gt;-shared&lt;/code&gt;), making it look more like creating an executable. The object file gets created in a slightly different way, with the &lt;code&gt;-fPIC&lt;/code&gt; flag being obligatory.&lt;/p&gt;
&lt;p&gt;Most importantly, we see our &lt;code&gt;print_hello&lt;/code&gt; symbol as present! Let's link the whole program together:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc hello.o libprinter.so -o hello_dynamic
# file hello_dynamic
hello_dynamic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=5a8e0d151089682720545349da87b330ab089805, not stripped
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far so good, this looks just like our previous static binary. Let's make sure all is fine.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# nm hello_dynamic | grep hello
                 U print_hello
# ./hello_dynamic
./hello_dynamic: error while loading shared libraries: libprinter.so: cannot open shared object file: No such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uh oh! We lost &lt;code&gt;print_hello&lt;/code&gt; along the way, and the program now tries to open the shared library we created. The one that contains &lt;code&gt;print_hello&lt;/code&gt;! Could there be a connection? What made the program try to load a file if all we do is printing text?&lt;/p&gt;
&lt;h3&gt;Scene 5: Dynamic linker&lt;/h3&gt;
&lt;p&gt;The culprit here is the dynamic linker. It's part of the operating system responsible for loading programs. Remember the &lt;code&gt;interpreter&lt;/code&gt; part of our file descriptions?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[...] dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2 [...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The interpreter's responsibility is to execute executables. It sets up basic resources, links them together if needed (!), and finally gives control to the program by running the entry point (in C that ends up being the function corresponding to the &lt;code&gt;main&lt;/code&gt; symbol).&lt;/p&gt;
&lt;p&gt;You may be surprised to see linking here again. Didn't we do enough of that already? We linked object files together with the dynamic library, and the dynamic library needed to be linked itself. Why again?&lt;/p&gt;
&lt;p&gt;Well, that's because we chose to create a dynamic library instead of a static one. The static library's selling point is that its code is injected (at the time of linking) into the executable. The dynamic library's point is that its code is injected (at the time of execution) into the running program. The former option provides some degree of certainty that the program doesn't change, while the latter gives some flexibility: the dynamic library can get changed and updated without the need to recreate the executable.&lt;/p&gt;
&lt;p&gt;When the interpreter complains about &lt;code&gt;cannot open shared object file&lt;/code&gt;, it means that it needed the library for the linking step, but couldn't find it in the standard location. The &lt;code&gt;ldd&lt;/code&gt; command lists all dynamic libraries that need to be linked together before running the executable:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ldd ./hello_dynamic
        linux-vdso.so.1 (0x00007ffc35be9000)
        libprinter.so =&amp;gt; not found
        libc.so.6 =&amp;gt; /lib64/libc.so.6 (0x00007fc874215000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc874419000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our shared library is &lt;code&gt;not found&lt;/code&gt;, because it's not in one of the standard paths. Thankfully, we can tell the dynamic linker to look for extra libraries in the current directory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# LD_LIBRARY_PATH=`pwd` ldd ./hello_dynamic
        linux-vdso.so.1 (0x00007ff5f4e32000)
        libprinter.so =&amp;gt; /home/rhn/libprinter.so (0x00007ff5f4e28000)
        libc.so.6 =&amp;gt; /lib64/libc.so.6 (0x00007ff5f4c26000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff5f4e33000)
# LD_LIBRARY_PATH=`pwd` ./hello_dynamic
Hello World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great, we directed the computer to find our lost &lt;code&gt;print_hello&lt;/code&gt; symbol inside a shared library!&lt;/p&gt;
&lt;h3&gt;Scene 6: Standard libraries&lt;/h3&gt;
&lt;p&gt;The list coming from &lt;code&gt;ldd&lt;/code&gt; is suspicious. In our final step using gcc, we linked &lt;code&gt;hello.o&lt;/code&gt; together with &lt;code&gt;libprinter.so&lt;/code&gt;. Where did the other dynamic libraries on the list come from?&lt;/p&gt;
&lt;p&gt;The answer is: kernel and standard libraries.&lt;/p&gt;
&lt;p&gt;If you look at our statically linked executable, you will see the same list:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ldd ./hello
        linux-vdso.so.1 (0x00007ffeda3d9000)
        libc.so.6 =&amp;gt; /lib64/libc.so.6 (0x00007f4e3293a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f4e32b3e000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The libraries here are required for the execution of virtually all programs, therefore gcc includes them implicitly. If you remember all the way back, we found &lt;code&gt;puts&lt;/code&gt; in one of them: in &lt;code&gt;libc.so.6&lt;/code&gt;. It turns out that all our executables do eventually link with that library, just well after the executable is created. That's why we were allowed to use &lt;code&gt;puts&lt;/code&gt; even without knowing where it was defined.&lt;/p&gt;
&lt;h2&gt;Final words&lt;/h2&gt;
&lt;p&gt;With this, you should have a pretty good understanding of where linking happens on a modern computer. Linking still has a lot of quirks when working with C — after all, we may want some control over what we mark as symbols and how. That will et covered in a future part.&lt;/p&gt;
&lt;h2&gt;Glossary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;interpreter&lt;/em&gt;: the software that executes executables&lt;/li&gt;
&lt;li&gt;&lt;em&gt;standard library&lt;/em&gt;: libraries containing basic functionality that most programmers don't need to think about&lt;/li&gt;
&lt;/ul&gt;</description><author>dcz's posts</author><pubDate>Mon, 01 Jun 2020 17:00:00 GMT</pubDate><guid isPermaLink="true">https://dorotac.eu/posts/dynamic_linking/</guid></item><item><title>Workflow for Lightning Fast Molecular Docking Part One</title><link>https://web.navan.dev/posts/2020-06-01-Speeding-Up-Molecular-Docking-Workflow-AutoDock-Vina-and-PyMOL.html</link><description>This is my workflow for lightning fast molecular docking.</description><author>Navan's Archive</author><pubDate>Mon, 01 Jun 2020 16:10:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-06-01-Speeding-Up-Molecular-Docking-Workflow-AutoDock-Vina-and-PyMOL.html</guid></item><item><title>The Bane of TODOs</title><link>https://domwillia.ms/todos</link><description>TODOs are great. In my head they're short and concise notes that will remind future me about issues and outstanding work that he'll get to one day. They'll be ticked off one by one in small commits that paint a beautifully satisfying `git log`. Surely?</description><author>Dom Williams</author><pubDate>Mon, 01 Jun 2020 15:00:00 GMT</pubDate><guid isPermaLink="true">https://domwillia.ms/todos</guid></item><item><title>MPWTest Only Tests Frameworks</title><link>https://blog.metaobject.com/2020/06/mpwtest-only-tests-frameworks.html</link><description>It should be noted, if it wasn't obvious, that &lt;a href="https://blog.metaobject.com/2020/05/mpwtest-reducing-test-friction-by-going.html"&gt;MPWTest&lt;/a&gt; is &lt;em&gt;opinionated software&lt;/em&gt;, meaning it
achieves some of its smoothness by gleefully embracing constraints that some might view as 
potentially crippling limitations.&lt;p&gt;

Maybe the biggest of these constraints, mentioned in the previous post, is that MPWTest only tests
frameworks.  This means that the following workflow is not supported out of the box:

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;The original OCUnit (that I wrote after &lt;a href="https://twitter.com/KentBeck?ref_src=twsrc%5Etfw"&gt;@KentBeck&lt;/a&gt;'s paper and was out at about the same time as JUnit) friction was not &amp;quot;high&amp;quot; IMHO: add the test framework, write a subclass of TestCase, launch your app with a -Test argument, results are logged in ProjectBuilder' console.&lt;/p&gt;&amp;mdash; Marco Scheurer (@phink0) &lt;a href="https://twitter.com/phink0/status/1266803201447268352?ref_src=twsrc%5Etfw"&gt;May 30, 2020&lt;/a&gt;&lt;/blockquote&gt; 

The point being that this is a workflow I not just somewhat indifferently do not want, but rather
emphatically and actively &lt;em&gt;want to avoid&lt;/em&gt;.  Tests that are run (only?) when launching the 
app are application tests.  My perspective is that unit tests are an integral part of the
class.  This may seem a subtle distinction, but subtle differences in something you do
constantly can have huge impacts.  "Steter Tropfen höhlt den Stein."&lt;p&gt;

Another aspect is that launching the app for testing as a permanent and fixed part of your build
process seems highly annoying at best.  Linker finishes, app pops up, runs for a couple of seconds,
shuts down again.  I don't see that as viable.  For testing to be integral and pervasive, it has 
to be invisible when the tests succeed.&lt;p&gt;

The &lt;a href="https://www.agilecoachjournal.com/wp-content/uploads/2014/01/AgileTestingPyramid1.jpg?189db0&amp;amp;189db0"&gt;testing pyramid&lt;/a&gt; is helpful here: my contention is that you want to be
at the bottom of that pyramid, ideally &lt;em&gt;all&lt;/em&gt; of the time.  Realistically, you're
probably not going to get there, but you should push really, really hard, even making
sacrifices that appear to be unreasonable to achieve that goal.&lt;p&gt;


&lt;h3&gt;Framework-oriented programming&lt;/h3&gt;

Only testing frameworks begs the question as to how to test those parts of the application
not in frameworks.  For me the answer is simple:  there isn't any production code outside
of frameworks.&lt;p&gt;

None. Not the UI, not the application delegate.  Only the auto-generated &lt;code&gt;main()&lt;/code&gt;.&lt;p&gt;

The benefits of this approach are plentiful, the effort minimal.  And if you think this is
an, er, eccentric position to take, the program you almost certainly use to create apps
for iOS/macOS etc. takes the same eccentric position:  Xcode's main executable is 45K in size and
only contains a &lt;code&gt;main()&lt;/code&gt; function and some Swift boilerplate.&lt;p&gt;

&lt;img alt="" border="0" height="" src="https://dl.dropbox.com/s/8osjcuto8jevqhk/xcode-main.png?dl=0" title="" width="500" /&gt;&lt;p&gt;

If all your code is in frameworks, only testing frameworks is not a problem. That may seem
like a somewhat extreme case of sour grapes, with the arbitrary limitations of a one-off
unit testing framework driving major architectural decisions, but the causality is the
other way around: I embraced framework-oriented programming before and independently of
MPWTest.&lt;p&gt;


&lt;h3&gt;iOS&lt;/h3&gt;

Another issue is iOS.  Running a command-line tool that dynamically loads and tests frameworks
is at least tricky and may be impossible, so that approach currently does not work.  My current
approach is that I view on-device and on-simulator tests as higher-up in the testing hierarchy:
they are more costly, less numerous and run less frequently.&lt;p&gt;



The vast majority of code lives in cross-platform frameworks (see: Ports and Adapters) and is
developed and tested primarily on macOS.  I have found this to be much faster than 
using the simulator or a device in day-to-day programming, and have used this "mac-first"
technique even on projects where we were using XCTest.&lt;p&gt;

Although not testing on the target platform may be seen as a problem, I have found 
discrepancies to be between exceedingly rare and non-existent, with "normal" code
trending towards the latter.  One of the few exceptions in the not-quite-so-normal
code that I sometimes create was the change of calling conventions on arm64, which 
meant that plain method pointers (IMPs) no longer worked, but had to be cast to
the "correct" pointer type, only on device.  Neither macOS nor the simulator 
would show the problem.&lt;p&gt;

For that purpose, I hacked together a small iOS &lt;a href="https://github.com/mpw/MPWFoundation/blob/master/TestMPWFoundation/AppDelegate.m"&gt;app&lt;/a&gt; that runs the tests specified
in a plist in the app bundle.  There is almost certainly a better way to handle this, but
I haven't had the cycles or motivation to look into it.&lt;p&gt;



&lt;h3&gt;How to approximate&lt;/h3&gt;

So you can't or don't want to adopt MPWTest.  That doesn't mean you can't get at least some
of the benefits of the approach.  As a start, instead of using Cmd-B in Xcode to build, just
use Cmd-U instead.  That's what I did when working on Wunderlist, where we used XCTest.&lt;p&gt;

Second, adopt framework-oriented programming and the Ports and Adapters style as much as possible.
Put all your code in frameworks, and as much as possible in cross-platform frameworks that you
can test/run on macOS, and even if you are developing exclusively for iOS, create a macOS target
for that framework.  This makes using Cmd-U to build much less painful.&lt;p&gt;

Third, adhere to a strict 1:1 mapping between production classes and test classes, and place
your test classes in the same file as the class they are testing.&lt;p&gt;


&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Thanks for sharing! I do this all the time in Rust, where tests are at the bottom of the source. I love it. Some people complain that now we're mingling testing code and prod code, but I think that doesn't hold: we're also adding logs and assertions to our prod code.&lt;/p&gt;&amp;mdash; Benedikt Terhechte @ 🏠 (@terhechte) &lt;a href="https://twitter.com/terhechte/status/1267380695896403968?ref_src=twsrc%5Etfw"&gt;June 1, 2020&lt;/a&gt;&lt;/blockquote&gt; 


&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;With OCUnit you didn't have to but your tests in a separate bundle, target etc. You could have them at the bottom of your class file in a subclass of TestCase instead of a &amp;quot;(testing) category&amp;quot;. The difference is not that big.&lt;/p&gt;&amp;mdash; Marco Scheurer (@phink0) &lt;a href="https://twitter.com/phink0/status/1267079516603777024?ref_src=twsrc%5Etfw"&gt;May 31, 2020&lt;/a&gt;&lt;/blockquote&gt; 

My practical experience with both JUnit and XCTest on medium-sized projects does not 
square with the assertion that the difference is not that big:  you still have to
create these additional classes, they have to communicate with the class under tests
(&lt;code&gt;self&lt;/code&gt; in MPWTest), you have to track changes etc.  And of course, you 
have to know to configure und use the framework differently from the way it was 
built, intended and documented.  And what I've seen of OCUnit use was that the
tests were not co-located with the class, but in a separate part of the project.&lt;p&gt;

A final note is that the trick of interchangeably using the class as the test fixture is only
really possible in a language like Objective-C where classes are first class objects.
It simply wouldn't be possible in Java.  This is how the class can test itself, and the
tests become an integral part of the class, rather than something that's added 
somewhere else.&lt;p&gt;</description><author>metablog</author><pubDate>Mon, 01 Jun 2020 14:10:28 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2020/06/mpwtest-only-tests-frameworks.html</guid></item><item><title>A solution to one RSS inconsistency</title><link>https://www.swilliams.io/w/solution-to-rss-inconsistency</link><description>&lt;p&gt;RSS feeds are a beautiful and wonderful open standard that anyone can, and should, utilise on their blogs, websites, or anything else. The standards RSS
    follows are reasonably flexible, but there is another aspect to RSS that is incredibly inconsistent across all use cases. That inconsistency is the location
    of the RSS feed file and the name of that file.&lt;/p&gt;
&lt;p&gt;A common idea seems to be putting a file after the domain root, though there is very little consensus on what this file should be called. Whilst
    &lt;code class="inline"&gt;feed.xml&lt;/code&gt; is certainly popular, I've seen &lt;code class="inline"&gt;atom.xml&lt;/code&gt;, &lt;code class="inline"&gt;posts.xml&lt;/code&gt;,
    &lt;code class="inline"&gt;feed.atom&lt;/code&gt; and &lt;code class="inline"&gt;rss.xml&lt;/code&gt;.&lt;sup&gt;&lt;a href="#fn-1"&gt;[1]&lt;/a&gt;&lt;/sup&gt; Additionally, websites which have blogs
    located in a subfolder of the site, such as, commonly, &lt;code class="inline"&gt;/w&lt;/code&gt; or &lt;code class="inline"&gt;/writing&lt;/code&gt; will generally, though not
    always, have the feed be in that folder and not in the site index. &lt;/p&gt;
&lt;p&gt;Looking at the big corporations. WordPress blogs can find their RSS feeds at &lt;code class="inline"&gt;/feed&lt;/code&gt;, which is a technique a fair few personal
    blogs employ as well&lt;sup&gt;&lt;a href="#fn-2"&gt;[2]&lt;/a&gt;&lt;/sup&gt; and this is the system other blogger platforms use, such as dev.to. Meanwhile, Reddit has feeds all
    over the place - every user, subreddit, or post has a feed associated with it which you can find by adding &lt;code class="inline"&gt;/.rss&lt;/code&gt; to the URL.
&lt;/p&gt;
&lt;p&gt;Its impossible to list all the possible varieties, and I've only just scatched the surface. I highly recommend you read through the responses to &lt;a
        href="https://news.ycombinator.com/item?id=22800136"&gt;this hacker news post&lt;/a&gt;, where hundreds of people have shared their blogs, to find yet more
    interesting instances of RSS implementation.&lt;/p&gt;
&lt;p&gt;It's very apparent that there is no standardisation as to where and how you should place your RSS feed in your site structure, which is an issue that might
    potentially cause confusion for visitors to your website. The solution I've used for this website is to place redirects everywhere a potential user might
    look for an RSS feed. These redirects point to a single &lt;code class="inline"&gt;atom.xml&lt;/code&gt; file. Below is the gulp task which does this. &lt;/p&gt;
&lt;code class="block"&gt;var rssStrings = [ 'atom', 'feeds', 'feeds.xml', 'feed.xml', 'rss', 'rss.xml' ];
gulp.task('rss', function() {
    let tasks = [];
    for (let i in rssStrings) {
        tasks.push(
            gulp.src("dist/feed/**")
            .pipe(rename(function(path) {
                path.dirname = rssStrings[i];
            }))
            .pipe(gulp.dest("./dist"))
        );
    }
    return mergeStream(tasks);
});&lt;/code&gt;
&lt;p&gt;Where &lt;code class="inline"&gt;dist/feed/**&lt;/code&gt; points an HTML file which provides a redirect to the &lt;code class="inline"&gt;atom.xml&lt;/code&gt; which contains the
    feed. Potentially, you could also copy the atom file itself, instead of a redirect. But I decided I'd rather ensure that there is only one atom file I need
    to worry about. Using this method, access to the RSS file is as available as possible.&lt;/p&gt;
&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
    &lt;li&gt;A few examples: &lt;a name="fn-1" href="https://writing.markchristian.org"&gt;writing.markchristian.org&lt;/a&gt;, &lt;a
            href="https://paulstamatiou.com/"&gt;paulstamatiou.com&lt;/a&gt;, &lt;a href="https://xkcd.com/"&gt;xkcd.com&lt;/a&gt;, &lt;a
            href="https://what-if.xkcd.com/"&gt;what-if.xkcd.com&lt;/a&gt;, &lt;a href="https://rachelbythebay.com/w/"&gt;rachelbythebay.com/w/&lt;/a&gt; &lt;/li&gt;
    &lt;li&gt;A few examples: &lt;a name="fn-2" href="https://tkainrad.dev"&gt;tkainrad.dev&lt;/a&gt;, &lt;a href="http://extremelearning.com.au"&gt;extremelearning.com.au&lt;/a&gt;, &lt;a
            href="https://walkedtheblueline.com"&gt;walkedtheblueline.com&lt;/a&gt;, &lt;a href="https://www.caribbeansignal.com"&gt;caribbeansignal.com&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As an aside, I also saw one instance (&lt;a href="https://paul.copplest.one/"&gt;paul.copplest.one&lt;/a&gt;) where the RSS feed was a link to the GitHub commits feed,
    which I suppose is innovative in its own sort of way.&lt;/p&gt;</description><author>SWilliams.io</author><pubDate>Mon, 01 Jun 2020 04:01:01 GMT</pubDate><guid isPermaLink="true">https://www.swilliams.io/w/solution-to-rss-inconsistency</guid></item><item><title>How to write a (toy) JVM</title><link>https://zserge.com/posts/jvm/</link><description>Whether we like it or not, but Java is one of the most widely used programming languages. However, since most of the applications in Java are either too boring or too complex - not every Java developer has enough curiosity to look under the hood and see how JVM works.
In this post I will try to write a toy (and incomplete) JVM to show the core principles behind it and hopefully sparkle some interest in you to learn it further.</description><author>zserge's blog</author><pubDate>Mon, 01 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://zserge.com/posts/jvm/</guid></item><item><title>Android Boot High Jinks: And What it Means for SharkBait</title><link>https://wantguns.dev/blog/android-boot-high-jinks/</link><description>&lt;p&gt;Presently, SharkBait aims at devices launching with Android version lower than 9. I will discuss few ways we could the port this setup to newer devices, whose boot mechanisms are different. We shall also address the boot process of SharkBait and what System-As-Root actually is.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id="the-boot-process-of-present-day-sharkbait"&gt;The Boot process of present-day SharkBait&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Swapping the Android's &lt;code&gt;init&lt;/code&gt; with &lt;a href="https://gitlab.com/sharkbaitOS/bootstrap/preinit" rel="external"&gt;&lt;code&gt;preinit&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We swapped the &lt;code&gt;init&lt;/code&gt; executable present in a functioning boot.img with KireinaHoro's &lt;code&gt;preinit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Preinit was responsible for early-mounting partitions and finally switch_root to Gentoo's init, thus firing OpenRC.&lt;/li&gt;
&lt;li&gt;The "swapping" was essentially replacing a normal Android &lt;code&gt;boot.img&lt;/code&gt;'s &lt;code&gt;ramdisk&lt;/code&gt;'s init with &lt;code&gt;preinit&lt;/code&gt;, and then flashing the new &lt;code&gt;boot.img&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;After OpenRC is fired, it starts the lxc.android service.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Android lxc container.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prior to swapping inits, we established an lxc container in the Gentoo userland.&lt;/li&gt;
&lt;li&gt;The Android rootfs (at that time it was &lt;strong&gt;ramdisk&lt;/strong&gt; &lt;em&gt;inside the boot.img&lt;/em&gt;), is extracted in the lxc container's rootfs folder.&lt;/li&gt;
&lt;li&gt;Android boots inside the container easily.&lt;/li&gt;
&lt;li&gt;The lxc container's &lt;code&gt;config&lt;/code&gt; might provide some insights as well:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.uts.name = android&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.rootfs.path = /var/lib/lxc/android/rootfs&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.init.cmd = /init&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.net.0.type = none&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.autodev = 0&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.hook.pre-start = /var/lib/lxc/android/pre-start.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.hook.post-stop = /var/lib/lxc/android/post-stop.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span&gt;lxc.cgroup.cpu.rt_runtime_us = 950000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is just a gist of what happened. There was a lot more involved.
Gentoo's &lt;code&gt;fstab&lt;/code&gt; was tweaked such that it mounted the device blocks and binded them to the container for Android's use.
Also KireinHoro managed to make a &lt;a href="https://wiki.gentoo.org/wiki/Android/SharkBait/Starting_Android_in_LXC" rel="external"&gt;working real-time group scheduling model&lt;/a&gt; by the use of cgroups.&lt;/p&gt;
&lt;h2 id="changes-in-android-9-devices"&gt;Changes in Android 9+ devices&lt;/h2&gt;
&lt;p&gt;Well, Google has made it very confusing to follow their language in the &lt;a href="https://source.android.com/devices/bootloader/system-as-root" rel="external"&gt;AOSP docs&lt;/a&gt;, I found that &lt;a href="https://topjohnwu.github.io/Magisk/boot.html" rel="external"&gt;Magisk's Documentation&lt;/a&gt; is very insightful.
Basically, Android Kernels dont use ramdisks as their &lt;code&gt;rootfs&lt;/code&gt; now. The &lt;a href="https://source.android.com/devices/bootloader/system-as-root#partition-layouts-nonabdevices" rel="external"&gt;older ramdisks&lt;/a&gt; found inside a &lt;code&gt;boot.img&lt;/code&gt; are now merged inside system.img.&lt;/p&gt;
&lt;h3 id="this-poses-some-challenges"&gt;This poses some challenges&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;What do we use now as lxc-container's rootfs&lt;/li&gt;
&lt;li&gt;If the kernel does not take a ramdisk inside the &lt;code&gt;boot.img&lt;/code&gt; as its rootfs, how do we perform the "&lt;code&gt;init&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;preinit&lt;/code&gt; swaps".&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Turns out Magisk already has some workarounds.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="magisk-s-approach-to-system-as-root"&gt;Magisk's approach to System-As-Root&lt;/h3&gt;
&lt;p&gt;In order to circumvent the new system.img-as-rootfs approach, Magisk hexpatches the device's Kernel to use the &lt;code&gt;ramdisk&lt;/code&gt; inside &lt;code&gt;boot.img&lt;/code&gt; as rootfs. The hexpatch essentially is just replacing the &lt;code&gt;skip_initramfs&lt;/code&gt; with &lt;code&gt;want_initramfs&lt;/code&gt; (could be any 4 lettered word instead as well) from the Kernel commandline. But replacing it from the extracted &lt;code&gt;bootimg.cfg&lt;/code&gt; of a &lt;code&gt;initrd.img&lt;/code&gt; did not work for me. So I stick to using hexpatching using &lt;code&gt;magiskboot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then Magisk patches the original &lt;code&gt;boot.img&lt;/code&gt; by adding a new &lt;code&gt;ramdisk.cpio&lt;/code&gt; incpio inside it.
The new &lt;code&gt;ramdisk&lt;/code&gt; has &lt;code&gt;magiskinit&lt;/code&gt; disguised as &lt;code&gt;init&lt;/code&gt;.
&lt;a href="https://topjohnwu.github.io/Magisk/deploy.html#systemless" rel="external"&gt;Source&lt;/a&gt;&lt;/p&gt;
&lt;pre class="giallo z-code"&gt;&lt;code&gt;&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt; original System-As-Root ramdisk #####&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;	.&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-comment"&gt;#&lt;/span&gt;&lt;span class="z-comment"&gt; ramdisk after flashing Magisk #######&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-support z-function"&gt;	.&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-keyword z-operator"&gt;	|&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;-&lt;/span&gt;&lt;span class="z-string"&gt; .backup/&lt;/span&gt;&lt;/span&gt;
&lt;span class="giallo-l"&gt;&lt;span class="z-string"&gt;	`&lt;/span&gt;&lt;span class="z-entity z-name z-function"&gt;-&lt;/span&gt;&lt;span class="z-string"&gt; init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;magiskinit&lt;/code&gt; is responsible for :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Early mounting required partitions. On system-as-root devices, we will switch root to system.&lt;/li&gt;
&lt;li&gt;Injecting magisk services into &lt;code&gt;init.rc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Loading sepolicy either from &lt;code&gt;/sepolicy&lt;/code&gt;, precompiled &lt;code&gt;sepolicy&lt;/code&gt; in vendor, or compiling split sepolicy.&lt;/li&gt;
&lt;li&gt;Patching sepolicy rules and dump to &lt;code&gt;/sepolicy&lt;/code&gt; or &lt;code&gt;/sbin/.se&lt;/code&gt; and patching init or &lt;code&gt;libselinux.so&lt;/code&gt; to load the patched policies&lt;/li&gt;
&lt;li&gt;Executing the original init to start the ordinary boot process&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is conceptually somewhat similar to KireinaHoro's approach at Preinit.&lt;/p&gt;
&lt;h2 id="my-approach-to-revise-sharkbait"&gt;My approach to revise SharkBait&lt;/h2&gt;
&lt;p&gt;I have two approaches. Both approaches have some commonality. We apply the same hexpatch which Magisk applies, to the custom kernel which is already lxc-enabled. This forces the kernel to use the &lt;code&gt;ramdisk&lt;/code&gt; inside the &lt;code&gt;boot.img&lt;/code&gt; as its &lt;code&gt;rootfs&lt;/code&gt;.
Then we package a new &lt;code&gt;boot.img&lt;/code&gt; which had KireinaHoro's &lt;code&gt;preinit&lt;/code&gt; as its &lt;code&gt;init&lt;/code&gt;. I assume, this enables the kernel to fire up Gentoo's init and eventually start the lxc-container on the way while Gentoo is booting up.&lt;/p&gt;
&lt;p&gt;We make the edits to the &lt;code&gt;fstab&lt;/code&gt; at the &lt;code&gt;/vendor&lt;/code&gt; partition (which as you might guess, is another change made by google), in order to provide Android with the correct mounts in Gentoo's userland.
Another change made by google was the decision to parse the cgroup mounts using &lt;code&gt;/etc/cgroups.json&lt;/code&gt; instead of the original parsing &lt;code&gt;init.rc&lt;/code&gt; approach. &lt;a href="https://source.android.com/devices/tech/perf/cgroups" rel="external"&gt;Source&lt;/a&gt;.
Fortunately this might not affect us as we dont need to mount any new cgroup. We make edits in the &lt;code&gt;init.rc&lt;/code&gt; for bind-mounting the container's pseudofs(s).&lt;/p&gt;
&lt;h3 id="1-w-magisk"&gt;1. w/ Magisk&lt;/h3&gt;
&lt;p&gt;The differences arises in what we use as the &lt;code&gt;rootfs&lt;/code&gt; for our lxc-container.
The approach I already followed, required using only magiskinit as the &lt;code&gt;rootfs&lt;/code&gt;.
I expected &lt;code&gt;magiskinit&lt;/code&gt; to follow its approach and eventually mount all the required device blocks inside the Android userland. Then finally switch to &lt;code&gt;/system&lt;/code&gt; as the rootdir.
This was the method which failed, causing my device to bootloop.&lt;/p&gt;
&lt;h3 id="2-w-o-magisk-untriaged"&gt;2. w/o Magisk (untriaged)&lt;/h3&gt;
&lt;p&gt;This approach requires to use entire &lt;code&gt;system.img&lt;/code&gt;, extracted, as &lt;code&gt;rootfs&lt;/code&gt;.
The &lt;code&gt;init&lt;/code&gt; used here is the Android's original &lt;code&gt;init&lt;/code&gt;.
Since every file required of the merged ramdisk is present in the &lt;code&gt;rootfs&lt;/code&gt;, I expect that &lt;code&gt;init&lt;/code&gt; fires up smoothly.&lt;/p&gt;
&lt;p&gt;Except that since &lt;code&gt;system.img&lt;/code&gt; should already be mounted by the kernel in a system-as-root device, We might have to mount it manually. &lt;a href="https://android.googlesource.com/platform/system/core/+/master/init/README.md#early-init-boot-sequence" rel="external"&gt;Source&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;P.S. This article was already written in drafts a few weeks ago, the next paragraphs serve no purpose other than that of history. I will be writing more articles explaining what happened afterwards in order to provide a smoother and realistic reading experience.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Without the use of a serial console, this whole "trace-fest" is difficult to understand. Finding out what went wrong, is on an entirely different level.&lt;/p&gt;
&lt;p&gt;We have no dmesg logs as they get overwritten by the recovery boot, which in turn is what I require to check the dmesg logs.
Since the kernel does not panic and the &lt;code&gt;init&lt;/code&gt; just &lt;code&gt;exit&lt;/code&gt;s, we have no &lt;code&gt;last_kmsg&lt;/code&gt; or &lt;code&gt;console-ramoops&lt;/code&gt; logs either.
Fortunately spending a lot of time researching I found &lt;a href="https://wiki.postmarketos.org/wiki/Xiaomi_Redmi_Note_7_(xiaomi-lavender)" rel="external"&gt;this&lt;/a&gt;.
My device has a serial-console baked in. Although accessing it would require taking out the phone's glass back, it is worth the fruit.&lt;/p&gt;</description><author>Gunwant Jain - @wantguns</author><pubDate>Mon, 01 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://wantguns.dev/blog/android-boot-high-jinks/</guid></item><item><title>Oracle: Generate DML scripts for images / blobs</title><link>https://hartenfeller.dev/blog/oracle-dml-script-images-blob-values</link><description>I want to share a little script I wrote which generates a DML scripts for blob values like images. The output script can be used in your schema install script with your other master data.</description><author>Philipp Hartenfeller Blog RSS Feed</author><pubDate>Mon, 01 Jun 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://hartenfeller.dev/blog/oracle-dml-script-images-blob-values</guid></item><item><title>Compiling Open Babel on iOS</title><link>https://web.navan.dev/posts/2020-05-31-compiling-open-babel-on-ios.html</link><description>Compiling Open Babel on iOS</description><author>Navan's Archive</author><pubDate>Mon, 01 Jun 2020 02:30:00 GMT</pubDate><guid isPermaLink="true">https://web.navan.dev/posts/2020-05-31-compiling-open-babel-on-ios.html</guid></item><item><title>Books and Links: May</title><link>http://evantravers.com/articles/2020/05/31/books-and-links-may/</link><description>&lt;p&gt;This month has been really busy for me. I've been doing a &lt;em&gt;lot&lt;/em&gt; of reading on work topics, and I'm in the middle of re-writing much of my note-taking apparatus, so this month will be kind of wordy and unstructured.&lt;/p&gt;
&lt;p&gt;This &lt;em&gt;may&lt;/em&gt; be the last time I do a post like this... I would like to move to shorter posts more often. We will see.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#books" id="books"&gt;&lt;/a&gt;Books&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-man-in-the-high-castle-by-philip-k-dick" id="the-man-in-the-high-castle-by-philip-k-dick"&gt;&lt;/a&gt;The Man in the High Castle by Philip K. Dick&lt;/h3&gt;
&lt;p&gt;I think I started this in high school, so it was a fun quick re-read.&lt;/p&gt;
&lt;p&gt;PKD's interior monologues are so skillful. Each character's mind speaks with its own voice. They don't get more poetic or use vernacular not accessible to that character's waking mind. It's subtle, but quite effective. I'm really tempted to get more intellectual or emotional within the mind of a character, but he stays with a very consistent voice.&lt;/p&gt;
&lt;p&gt;The recursive symmetry of the book within a book is compelling. I imagine that when the characters of Man in the High Castle read A Grasshopper Lies Heavy they are reading about us reading them reading us reading them...&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#the-raven-tower-by-ann-leckie" id="the-raven-tower-by-ann-leckie"&gt;&lt;/a&gt;The Raven Tower by Ann Leckie&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Perhaps the length of one’s life was not important—except in the way it is to so many living beings, desperate to avoid death. Perhaps, long or short, it mattered how one spent that time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Seeing how much I enjoyed the Ancillary series, I picked this up. While I wouldn't say it's as strong as Ancillary, I really enjoyed this one. It's a fun world, I like the parallel histories going on between the story's present and past, and the existential questions about worship and language that Patience of the Hill presents.&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#links" id="links"&gt;&lt;/a&gt;Links&lt;/h2&gt;
&lt;h3&gt;&lt;a class="anchor" href="#blank-vhs-covers-were-kinda-beautiful---youtube" id="blank-vhs-covers-were-kinda-beautiful---youtube"&gt;&lt;/a&gt;blank vhs covers were kinda beautiful - YouTube&lt;/h3&gt;

&lt;p&gt;This is &lt;em&gt;wonderful&lt;/em&gt;. Growing up, my dad had boxes of taped soccer matches and I remember some of these!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=e9DfSCk-6Ko&amp;amp;feature=youtu.be"&gt;blank vhs covers were kinda beautiful - YouTube&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#alabamas-nick-saban-the-scariest-man-in-college-football--gq" id="alabamas-nick-saban-the-scariest-man-in-college-football--gq"&gt;&lt;/a&gt;Alabama's Nick Saban: The Scariest Man in College Football | GQ&lt;/h3&gt;
&lt;p&gt;I got this link from Dan Shipper's Superorganizer's profile on the author of The Profile. (Meta, right?)&lt;/p&gt;
&lt;p&gt;I have to wonder if part of Saban's personality and the of perfection is rooted in the works-salvation of Catholicism.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;after a big victory, Saban feels less joy than relief. Saban is reaching for a standard, so there are only two possibilities: Either you did what you were supposed to do, or you fell short. If you fell short, you go work harder and better to try to meet the standard next time. And if you met the standard, you go work doubly hard to fight off complacency—a fatal disease transmitted by pats on the back and post-game confetti—so you have a shot at meeting it again. The process, then, is never over. Wins are not ends but merely data points that help Saban assess the state of the process at a given moment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's a fascinating profile.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.gq.com/story/coach-nick-saban-alabama-maniac"&gt;Alabama's Nick Saban: The Scariest Man in College Football | GQ&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#please-print-a-journaling-rant--the-cramped" id="please-print-a-journaling-rant--the-cramped"&gt;&lt;/a&gt;Please Print (A Journaling Rant) – The Cramped&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;In these historic times, many people have turned to journalling as a way of keeping account for the next generation. So when the grandkids ask what it was like to live through the 2020 Pandemic, you’ll be able grab your pipe, sit them on your lap, and regale them with yarns spun from your own written words.&lt;/p&gt;
&lt;p&gt;I see so many that I know discussing how important their digital journalling app of choice has become for this purpose and… my heart sinks. I feel so sad for them. The reason….&lt;/p&gt;
&lt;p&gt;None of these apps will be around.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a &lt;em&gt;really&lt;/em&gt; good point. He does have a good middle ground though:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So please, I implore you, if you insist on journalling using any digital tool, please also regularly print what you are writing. Stick it somewhere cool and dry.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://www.thecramped.com/please-print-a-journaling-rant/?ref=thenewsprint.co"&gt;Please Print (A Journaling Rant) – The Cramped&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#psychicpaper--ios-135-sandbox-escapeentitlement-0day" id="psychicpaper--ios-135-sandbox-escapeentitlement-0day"&gt;&lt;/a&gt;psychicpaper | iOS &amp;lt;13.5 sandbox escape/entitlement 0day&lt;/h3&gt;
&lt;p&gt;A pretty great read of a very intriguing security flaw.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[…] Because it’s very hard to parse XML correctly, valid XML makes all parsers return the same data, but slightly invalid XML makes them return just slightly not the same data. :D
In other words, any parser difference can be exploited to make different parsers see different things. This is the very heart of this bug, making it not just a logic flaw, but a system-spanning design flaw.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sadly, this is a 0day that was on iPhone for &lt;em&gt;quite&lt;/em&gt; a while… still affects non-beta at the time of this post.&lt;/p&gt;
&lt;p&gt;Another reminder that however slick the marketing packaging, every device is a 0day waiting to happen.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://siguza.github.io/psychicpaper/"&gt;psychicpaper | iOS 13.5 sandbox escape/entitlement 0day&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#frank-chimero--redesign-table-of-contents" id="frank-chimero--redesign-table-of-contents"&gt;&lt;/a&gt;Frank Chimero · Redesign: Table of Contents&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;At the start of 2020, I’ll begin redesigning this website. In the past, I’ve done this work in secret, but I’d like to document the process this time through.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not only is Frank an engaging writer, this is basically a curriculum in good design, and in the integrated design process between code and notebook. I should have reviewed this before I started my redesign.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://frankchimero.com/blog/2019/redesign/"&gt;Frank Chimero · Redesign: Table of Contents&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#3-tips-for-a-better-student-online-learning-experience---christensen-institute--christensen-institute" id="3-tips-for-a-better-student-online-learning-experience---christensen-institute--christensen-institute"&gt;&lt;/a&gt;3 tips for a better student online learning experience - Christensen Institute : Christensen Institute&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;With the shift to virtual learning, good teaching becomes more about checking in with students to coach them on self-directed learning activities and provide targeted interventions than about covering content via video lecture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While I'm sure it's different for everyone… this was &lt;em&gt;exactly&lt;/em&gt; my homeschooling experience.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.christenseninstitute.org/blog/3-tips-for-a-better-student-online-learning-experience/"&gt;3 tips for a better student online learning experience - Christensen Institute : Christensen Institute&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&lt;a class="anchor" href="#zettel" id="zettel"&gt;&lt;/a&gt;Zettel&lt;/h2&gt;
&lt;p&gt;I'm still using my Drafts system to create zettel from links, random thoughts... making it easy to create them means I've made a lot more than I thought. Here are some that are more useful for the three people who read my blog.&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#a-price-is-a-signal" id="a-price-is-a-signal"&gt;&lt;/a&gt;A price is a signal&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A price is a signal wrapped up in an incentive so if you want a strong signal and a strong incentive you need to let prices rise.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; I agree with this.&lt;/p&gt;
&lt;p&gt;It's an interesting argument for cold-hearted capitalism, and one I have attempted to voice without being this articulate. I feel that (barring common grace) there is a severe downside since the signal's strength does not correlate with moral good… I don't think that it follows that the signal you send and the incentive you create are necessarily &amp;quot;good&amp;quot; or aligned with universal truth.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://marginalrevolution.com/marginalrevolution/2020/05/blood-money.html"&gt;Tyler Cowen, Blood Money - Marginal REVOLUTION&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#minimum-viable-artifact" id="minimum-viable-artifact"&gt;&lt;/a&gt;Minimum viable artifact&lt;/h3&gt;
&lt;p&gt;Minimum viable artifacts are the least amount of work required to communicate between peers.&lt;/p&gt;
&lt;p&gt;Code artifacts are The Truth.
Design artifacts are part of a dialog to guide code.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If the code is right, you don't need a design artifact.&lt;/li&gt;
&lt;li&gt;If the code is wrong, simply draw the fix for only what is broken.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It is hard to trust a peer with less than pixel perfect when you have been hurt and betrayed before, but it is time to change our habits.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://overcast.fm/+WLc2zGxC4"&gt;11. Brad Frost and Evan Lovely: Code is the Source of Truth — Design Systems Podcast — Overcast&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;a class="anchor" href="#second-guessing-the-modern-web---macwrightorg" id="second-guessing-the-modern-web---macwrightorg"&gt;&lt;/a&gt;Second-guessing the modern web - macwright.org&lt;/h3&gt;
&lt;p&gt;This article does a good job of pointing out some of the technical problems with what &lt;a href="https://frankchimero.com/blog/2018/everything-easy/"&gt;Frank Chimero&lt;/a&gt; and many others have pointed out about the &amp;quot;modern web.&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As your React application grows, the application bundle grows. Unlike with a traditional multi-page app, that growth affects every visitor: you download the whole app the first time that you visit it. At some point, this becomes a real problem. Someone who lands on the About page is also downloading 20 other pages in the same application bundle. Bundle splitting ‘solves’ this problem by creating many JavaScript bundles that can lazily load each other. So you load the About page and what your browser downloads is an ‘index’ bundle, and then that ‘index’ bundle loads the ‘about page’ bundle.&lt;/p&gt;
&lt;p&gt;This sort of solves the problem, but it’s not great. Most bundle splitting techniques require you to load that ‘index bundle’, and then only once that JavaScript is loaded and executed does your browser know which ‘page bundle’ it needs. So you need two round-trips to start rendering.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Maybe I &lt;em&gt;am&lt;/em&gt; an old fogey, but it really does feel like a lot of clever javascript build system is a solution in search of a problem. I'm prejudiced in favor of the &amp;quot;new&amp;quot; old-way of the so-called JAMstack: static pages, rich interaction where required, readable source code.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But I’m at the point where I look at where the field is and what the alternative patterns are – taking a second look at unloved, unpopular, uncool things like Django, Rails, Laravel – and think what the heck is happening. We’re layering optimizations upon optimizations in order to get the SPA-like pattern to fit every use case, and I’m not sure that it is, well, worth it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Amen… but also great comments on how hard it is to swim against the industry current.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But the cultural tides are strong. Building a company on Django in 2020 seems like the equivalent of driving a PT Cruiser and blasting Faith Hill’s “Breathe” on a CD while your friends are listening to The Weeknd in their Teslas. Swimming against this current isn’t easy, and not in a trendy contrarian way.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I will be happily driving my PT Cruiser static-site blog long after React is as old-news as Angular 1.0. :-P&lt;/p&gt;
&lt;p&gt;&lt;a href="https://macwright.org/2020/05/10/spa-fatigue.html"&gt;Second-guessing the modern web - macwright.org&lt;/a&gt;&lt;/p&gt;</description><author>trv.rs</author><pubDate>Mon, 01 Jun 2020 00:33:00 GMT</pubDate><guid isPermaLink="true">http://evantravers.com/articles/2020/05/31/books-and-links-may/</guid></item><item><title>MPWTest: Reducing Test Friction by Going Beyond the xUnit Model</title><link>https://blog.metaobject.com/2020/05/mpwtest-reducing-test-friction-by-going.html</link><description>By popular demand, a quick rundown of &lt;a href="https://github.com/mpw/mpwtest"&gt;MPWTest&lt;/a&gt; (“&lt;em&gt;The Simplest Testing Framework That Could Possibly Work&lt;/em&gt;”), my own personal unit testing framework, and
how it makes TDD fast, fun, and frictionless.&lt;p&gt;

I created MPWTest because once I had been bitten by the TDD bug, I definitely did not
want to write software without TDD ever again, if I could help it.  This was long before XCTest, and even its
precursor SenTestKit was in at best in parallel development, I certainly
wasn't aware of it.&lt;p&gt;

It is a bit different, and the differences make it sufficiently better that I 
much prefer it to the xUnit variants that I've worked with (JUnit, some SUnit, XCTest).  All of these are
vastly better than not doing TDD, but they introduce significant amounts of
overhead, friction, that make the testing experience much more cumbersome 
than it needs to be, and to me at least partly explains some of the antipathy
I see towards unit testing from developers.&lt;p&gt;

The attitude I see is that testing is like eating your vegetables, you know
it's supposed to be good for you and you do it, grudgingly, but it really
is rather annoying and the benefits are more something you know intellectually.&lt;p&gt;

For me with MPWTest, TDD is also still intellectually a Good Thing™, but also
viscerally &lt;em&gt;fun&lt;/em&gt;, less like vegetables and more like tasty snacks, except
that those snacks are not just yummy, but also healthy.  It helps me stay in
the flow and get things done.&lt;p&gt; 


&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;I would second MPWTest.&lt;br /&gt;&lt;br /&gt;Mind you, I don't know how it's normally done—but the fact that everything is in one file &amp;amp;&amp;amp; part of the build process makes it WAY WAY WAY faster.&lt;br /&gt;&lt;br /&gt;Given the advent of SwiftUI—it's like Xcode previews—but for tests.&lt;br /&gt;&lt;br /&gt;1/&lt;/p&gt;&amp;mdash; 𝔾𝕦𝕤𝕥𝕒𝕧𝕠 𝕄𝕦𝕔𝕙𝕠 𝕃𝕠𝕧𝕖 👌🏻 (@LongMuchoLove) &lt;a href="https://twitter.com/LongMuchoLove/status/1266085192931868678?ref_src=twsrc%5Etfw"&gt;May 28, 2020&lt;/a&gt;&lt;/blockquote&gt; 

&lt;p&gt;
What it does is let me change code quickly and safely, the key to agile:
&lt;p&gt;

&lt;blockquote class="twitter-tweet"&gt;&lt;p dir="ltr" lang="en"&gt;Contrary to what you may have read in the Agile literature, the key to agility is the ability to change code quickly and safely. And the key to that is the ability to re-test code quickly and effectively. Fast-running automated tests (&amp;quot;unit tests&amp;quot;) are the key to agility.&lt;/p&gt;&amp;mdash; Jason Gorman (only, more indoors than usual) (@jasongorman) &lt;a href="https://twitter.com/jasongorman/status/1251408890505420800?ref_src=twsrc%5Etfw"&gt;April 18, 2020&lt;/a&gt;&lt;/blockquote&gt; 

Here is how it works.&lt;p&gt;


&lt;h3&gt;Setup&lt;/h3&gt;

First you need to build the &lt;code&gt;testlogger&lt;/code&gt; binary of the &lt;a href="https://github.com/mpw/mpwtest"&gt;MPWTest&lt;/a&gt; project.  I put mine in &lt;code&gt;/usr/local/bin&lt;/code&gt; and forget about it.  You can put it anywhere you like, but will have to adjust the paths
in what follows.&lt;p&gt;

Next, add a "Script" build phase to your (framework) project.   MPWTest currently only
tests frameworks.&lt;p&gt;


&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
tester=/usr/local/bin/testlogger
framework=${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}

if  [ -f ${tester}  ]  ; then
    $tester ${framework}
else
    echo "projectfile:0:1: warning: $tester or  $framework  not found, tests not run"
fi
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

The bottom of the Build Phases pane of your project should then look something roughly like the following:&lt;p&gt;

&lt;img alt="" border="0" height="" src="https://dl.dropbox.com/s/wmgvqsnc9fqen8z/test-phase.png?dl=0" title="" width="600" /&gt;

&lt;p&gt;
There is no separate test bundle, no extra targets, nada.  This may not seem such
a big deal when you have just a single target, but once you start getting having
a few frameworks, having an additional test target for each really starts to
add up.  And adds a decision-point:  should I really create an additional 
test bundle for this project?  Maybe I can just repurpose this existing one?&lt;p&gt;


&lt;h3&gt;Code&lt;/h3&gt;

In the class to be tested, add the &lt;code&gt;+(NSArray*)testSelectors&lt;/code&gt; method, 
returning the list of tests to run/test methods to execute.  Here is an example
from the JSON parser I've been writing about:&lt;p&gt;


&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
+testSelectors
{
  return @[
            @"testParseJSONString",
            @"testParseSimpleJSONDict",
            @"testParseSimpleJSONArray",
            @"testParseLiterals",
            @"testParseNumbers",
            @"testParseGlossaryToDict",
            @"testDictAfterNumber",
            @"testEmptyElements",
            @"testStringEscapes",
            @"testUnicodeEscapes",
            @"testCommonStrings",
            @"testSpaceBeforeColon",
          ];
}
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;
You could also determine these names automagically, but I prefer the explicit list
as part of the specification:  these are the tests that should be run.  
Otherwise it is too easy to just lose a test to editing mistakes and be 
none the wiser for it.&lt;p&gt;

Then just implement a test, for example &lt;code&gt;testUnicodeEscapes&lt;/code&gt;:

&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
+(void)testUnicodeEscapes
{
	MPWMASONParser *parser=[MPWMASONParser parser];
	NSData *json=[self frameworkResource:@"unicodeescapes" category:@"json"];
	NSArray *array=[parser parsedData:json];
	NSString *first = [array objectAtIndex:0];
	INTEXPECT([first length],1,@"length of parsed unicode escaped string");
	INTEXPECT([first characterAtIndex:0], 0x1234, @"expected value");
	IDEXPECT([array objectAtIndex:1], @"\n", @"second is newline");
}
&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

Yes, this is mostly old code.  The macros do what you, er, expect:  &lt;code&gt;INTEXPECT()&lt;/code&gt; expects integer equality (or other scalars, to be honest), &lt;code&gt;IDEXPECT()&lt;/code&gt; expects object equality.  There are 
also some conveniences for nil, not nil, true and false, as well as a specialized one
for floats that sets an acceptable range.&lt;p&gt;

In theory, you can put these methods anywhere, but I tend to place them in a 
&lt;code&gt;testing&lt;/code&gt; category at the bottom of the file.&lt;p&gt;

&lt;hr /&gt;
&lt;code&gt;
&lt;pre&gt;
...
@end

#import "DebugMacros.h"

@implementation MPWMASONParser(testing)

&lt;/pre&gt;
&lt;/code&gt;
&lt;hr /&gt;

The &lt;code&gt;DebugMacros.h&lt;/code&gt; header has the various &lt;code&gt;EXPCECT()&lt;/code&gt; macros.
The header is the only dependency in your code, you do not need to link anything.&lt;p&gt;

Even more than not having a separate test bundle, not having a separate test class
(-hierarchy) really simplifies things.  A lot.&lt;p&gt;

First, there is no question as to where to find the tests for a particular class:  
at the bottom of the file, just scroll down.  Same for the class for some tests:
scroll up.  I find this incredibly useful, because the tests serve as specification,
documentation and example code for class.&lt;p&gt;

There is also no need to maintain parallel class hierarchies, which are widely
regarded as a fairly serious &lt;a href="http://mikamantyla.eu/BadCodeSmellsTaxonomy.html"&gt;code-smell&lt;/a&gt;, for the obvious reasons:  the need to keep those hierarchies in sync along
with the problems once they do get out of sync, which they will, etc.&lt;p&gt; 


&lt;h3&gt;Use&lt;/h3&gt;

After the setup, you just build your projects, the tests will be run automatically
as part of the build.  If there are test failures, they are reported by Xcode
as you would expect:&lt;p&gt;

&lt;img alt="" border="0" height="" src="https://dl.dropbox.com/s/e75j3m71yqgs6ei/xcode-integration.png?dl=0" title="" width="650" /&gt;

&lt;p&gt;

My steps tend to be:  
&lt;ol&gt;
&lt;li&gt;add name of test to &lt;code&gt;+testSelectors&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;hit build to ensure tests are red,&lt;/li&gt;
&lt;li&gt;while Xcode builds, add empty test method,&lt;/li&gt;
&lt;li&gt;hit build again to ensure tests are now green,&lt;/li&gt;
&lt;li&gt;either add an actual &lt;code&gt;EXPECT()&lt;/code&gt; for the test, &lt;/li&gt;
&lt;li&gt;or an &lt;code&gt;EXPECTTRUE(false,@"impelemented")&lt;/code&gt; as placeholder&lt;/li&gt;
&lt;/ol&gt;

This may seem like a lot of steps, but it's really mostly just letting
Xcode check things while I am doing the edits that need to be done 
anyhow.  Hitting Cmd-B a couple of times while editing doesn't hurt.&lt;p&gt;

The fact that tests run as part of every build, because you cannot
build without running the tests, gives you a completely different
level of confidence in your code, which translates to &lt;a href="http://www.extremeprogramming.org/values.html"&gt;courage&lt;/a&gt;.&lt;p&gt;

Running the tests all the time is also splendid motivation to keep those
tests green, because if the tests fail, the build fails.   And if the
build fails, you cannot run the program.  Last not least, running the
tests on every build also is strong motivation to keep those tests
fast.  Testing just isn't this separate activity, it's as integral
a part of the development process as writing code and compiling it.&lt;p&gt;

&lt;h3&gt;Caveats&lt;/h3&gt;

There are some drawbacks to this approach, one that the pretty Xcode 
unit test integration doesn't work, as when this was done Apple had
already left the platform idea behind and was only focused on making
an integrated solution.&lt;p&gt;

As noted above, displaying test failures as errors and jumping to the
line of the failed test-expectation &lt;em&gt;does&lt;/em&gt; work.  This hooks
into the mechanism Xcode uses to get that information from compilers,
which simply output the line number and error message on &lt;code&gt;stdout&lt;/code&gt;.
Any tool that formats its output the same way will work wth Xcode.&lt;p&gt;

In the end, while I do enojoy the blinkenlights of Xcode's unit test
integration, and being able to run tests individually with simple
mouse-click, all this bling really just reinforces that idea of
tests as a separate entity.  If my tests are always run and
are always green, and are always fast, then I don't need or
even want UI for them, the UI is a distraction, the tests
should fade into the background.&lt;p&gt;


Another slightly more annoying issue is debugging:  as the tests are run
as part of the build, a test failure is a build failure and will
block any executables from running.  However, Xcode only debugs
executables, so you can't actually get to a debuggable run session.&lt;p&gt;

As I don't use debuggers all that much, and failure in TDD usually 
manifests itself in test failure rather than something you need the
debugger to track, this hasn't been much of a problem.  In the past,
I would then just revert to the command line, for example with 
&lt;code&gt;lldb testlogger MPWFoundation&lt;/code&gt; to debug my foundation framework,
as you can't actually run a framewework.  

Or so I thought.  Only receently
did I find out that you can set an executable parameter in your target's
build scheme.  I now set that to &lt;code&gt;testlogger&lt;/code&gt; and can debug the
framework to my heart's content.

&lt;p&gt;

&lt;img alt="" border="0" height="" src="https://dl.dropbox.com/s/ewbb36osopmjxm3/set-executable.png?dl=0" title="" width="500" /&gt; 

&lt;p&gt;
Leaving the problem of Xcode not actually letting me run the executable due to 
the build failing, and as far as I know having no facility for debugging
build phases.&lt;p&gt;

The workaround for that is temporarily disabling the Test build phase,
which can be accomplished by misusing the "Run script only when installing" flag.


&lt;p&gt;

&lt;img alt="" border="0" height="" src="https://dl.dropbox.com/s/6ll82zialx77chf/disabled-tests.png?dl=0" title="" width="600" /&gt;
&lt;p&gt;



While these issues aren't actually all the significant, they are somewhat more
jarring than you might expect because the experience is so buttery smooth the
rest of the time.&lt;p&gt;

Of course, if you want a pure test class, you can do that:  just create a 
class that only has tests.  Furthermore, each class is actually asked for
a test fixture object for each test. The default is just to return the
class object itself, but you can also return an instance, which can have
setup and teardown methods the way you expect from xUnit.&lt;p&gt;

The code to enumerate and probe all classes in the system in order to find
tests is also interesting, if straightforward, and needs to be updated from 
time to time, as there are a few class in the system that do not like to be probed.


&lt;h3&gt;Outlook&lt;/h3&gt;

I'd obviously be happy if people try out MPWTest and find it useful.  Or find
it not so useful and provide good feedback.  I currently have no specific 
plans for Swift support.  Objective-C compatible classes should probably work, 
the rest of the language probably isn't dynamic enough to support this kind
of transparent integration, certainly not without more compiler work.
But I am currently investigating Swift interop. more generally, and now
that I am no longer restricted to C/Objective-C, more might be possible.&lt;p&gt;

I will almost certainly use the lessons learned here to create linguistically
integrated testing in Objective-Smalltalk.  As with many other aspects of
Objective-Smalltalk, the gap to be bridged for super-smooth is actually not
that large.&lt;p&gt;

Another takeaway is that unit testing is really, really simple.  In fact,
when I asked Kent Beck about it, his response was that everyone should
build their own.  So go and build wonderful things!&lt;p&gt;</description><author>metablog</author><pubDate>Sun, 31 May 2020 09:59:55 GMT</pubDate><guid isPermaLink="true">https://blog.metaobject.com/2020/05/mpwtest-reducing-test-friction-by-going.html</guid></item><item><title>How to: dokku wildcard certificates</title><link>https://nutcroft.mataroa.blog/blog/how-to-dokku-wildcard-certificates/</link><description>&lt;p&gt;Everybody knows that &lt;a href="https://github.com/dokku/dokku"&gt;dokku&lt;/a&gt; is the best thing ever when it comes to deploying web applications. Unfortunately, though, the best thing's Let's Encrypt plugin &lt;a href="https://github.com/dokku/dokku-letsencrypt"&gt;dokku-letsencrypt&lt;/a&gt; does not support wildcard certificates.&lt;/p&gt;
&lt;p&gt;This is how to succeed when faced with such challenge.&lt;/p&gt;
&lt;h2 id="dokku-certs-inner-workings"&gt;dokku certs inner workings&lt;/h2&gt;
&lt;p&gt;Dokku stores everything around the deployment of an app in a aptly named directory inside &lt;code&gt;/home/dokku&lt;/code&gt;. It also stores the certificates there, which are referenced from the app's nginx.conf.&lt;/p&gt;
&lt;p&gt;An app's nginx.conf is customizable via the sigil template dokku uses.&lt;/p&gt;
&lt;p&gt;Assuming we get a wildcard certificate, one way to install it would be to copy the cert files there and let the templated nginx config find it. This course of action would also require changing the &lt;code&gt;DOKKU_PROXY_PORT_MAP&lt;/code&gt; and &lt;code&gt;DOKKU_PROXY_SSL_PORT&lt;/code&gt; app environment variables to include the 443 port mapping so that the template understands that certificates exist and accepts requests at 443.&lt;/p&gt;
&lt;p&gt;But there is a better way, by using the &lt;code&gt;dokku certs&lt;/code&gt; command.&lt;/p&gt;
&lt;h2 id="getting-the-wildcard-cert"&gt;Getting the wildcard cert&lt;/h2&gt;
&lt;p&gt;First we need to get our wildcard cert manually. &lt;a href="https://certbot.eff.org/"&gt;certbot&lt;/a&gt; supports wildcard certficates with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;certbot certonly --manual --preferred-challenges=dns
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When asked for the domain, enter both the bare root domain and the wildcard one. I.e. &lt;code&gt;example.com, *.example.com&lt;/code&gt;. Dokku's wish is to have one cert/key pair per app and we must respect it.&lt;/p&gt;
&lt;p&gt;The command asks for a DNS challenge (it's the only option on wildcard domains), a TXT record on a subdomain.&lt;/p&gt;
&lt;p&gt;After following all the steps methodically, it generates the cert and the private key at: &lt;code&gt;/etc/letsencrypt/live/&amp;lt;you-domain&amp;gt;/fullchain.pem&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="installing-the-cert-into-dokku"&gt;Installing the cert into dokku&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://dokku.viewdocs.io/dokku~v0.20.4/configuration/ssl/#certificate-setting"&gt;Dokku states&lt;/a&gt; it is intelligent enough to understand which is which even when they are not named &lt;code&gt;server.key&lt;/code&gt; and &lt;code&gt;server.crt&lt;/code&gt;. Yet I still renamed them — not that I don't trust software. Then tar'ed them as per dokku's desire with:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;tar&lt;span style="color: #657B83;"&gt; &lt;/span&gt;cvf&lt;span style="color: #657B83;"&gt; &lt;/span&gt;certs.tar&lt;span style="color: #657B83;"&gt; &lt;/span&gt;server.key&lt;span style="color: #657B83;"&gt; &lt;/span&gt;server.crt
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, the actual installation process, which was much less complicated than expected:&lt;/p&gt;
&lt;div style="background: #fdf6e3;"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;dokku&lt;span style="color: #657B83;"&gt; &lt;/span&gt;certs:add&lt;span style="color: #657B83;"&gt; &lt;/span&gt;mataroa&lt;span style="color: #657B83;"&gt; &lt;/span&gt;&amp;lt;&lt;span style="color: #657B83;"&gt; &lt;/span&gt;certs.tar
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that's it. &lt;a href="https://mataroa.blog/"&gt;mataroa.blog&lt;/a&gt; was wildcardly certificated.&lt;/p&gt;
&lt;h2 id="renewal"&gt;Renewal&lt;/h2&gt;
&lt;p&gt;Let's Encrypt certificates are valid for 3 months, at which point, because it's a &lt;code&gt;--manual&lt;/code&gt; certbot command, you need to do the same operation from the top :(&lt;/p&gt;</description><author>nutcroft</author><pubDate>Sun, 31 May 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/how-to-dokku-wildcard-certificates/</guid></item><item><title>The Best Self-Hosted RSS Feed Readers</title><link>https://lukesingham.com/rss-feed-reader/</link><description>&lt;h2 id="what-is-rss%3F"&gt;What is &lt;a href="https://en.wikipedia.org/wiki/RSS"&gt;RSS&lt;/a&gt;? &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#what-is-rss%3F"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It aims to be an open standard for the open web, where applications can get updates from websites. This runs against the current closed off portions of the web like Facebook that keep content behind their account login - i.e. the internet's &lt;a href="https://en.wikipedia.org/wiki/Closed_platform"&gt;'walled gardens'&lt;/a&gt;. For a while, a lot of people used the popular &lt;a href="https://en.wikipedia.org/wiki/Google_Reader"&gt;Google Reader&lt;/a&gt; RSS application - unfortunately, as with many loved Google projects it got killed off because of declining usage and it didn't generate revenue.&lt;/p&gt;
&lt;p&gt;So why get one now?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ideals of an open web. I don't have a Facebook account. I believe there are interesting blogs out there that I don't necessarily see unless they are surfaced through the front page of search results or aggregators like Hacker News or Reddit.&lt;/li&gt;
&lt;li&gt;Solve the problem of - &lt;em&gt;huh this blog/site was really interesting. How do I keep track of new content without signing up to a thousand newsletters or entering a walled garden?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="my-starting-point"&gt;My Starting Point &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#my-starting-point"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There's a bunch of open source Feed Readers listed on the &lt;a href="https://github.com/awesome-selfhosted/awesome-selfhosted#feed-readers"&gt;Feed Reader section of Awesome Self-Hosted&lt;/a&gt;. My criteria to filter the list were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minimum 1000 Github Stars&lt;/li&gt;
&lt;li&gt;Commit in the last 6 months&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is what I was left with. Which I then filtered based on my UI and tech preferences i.e. don't be ugly and don't use PHP/Java.&lt;/p&gt;
&lt;h2 id="%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A7-the-contenders"&gt;👨‍👩‍👧‍👧 The Contenders &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#%F0%9F%91%A8%E2%80%8D%F0%9F%91%A9%E2%80%8D%F0%9F%91%A7%E2%80%8D%F0%9F%91%A7-the-contenders"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="winds"&gt;&lt;a href="https://getstream.io/winds/"&gt;Winds&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#winds"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;The kitchen sink reader&lt;/em&gt;&lt;br /&gt;
Github Stars: 7.5k&lt;br /&gt;
Built With: JavaScript (React + Express)&lt;br /&gt;
Test Website: No, but free account creation&lt;br /&gt;
Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recommender service via external service&lt;/li&gt;
&lt;li&gt;Very nice UI&lt;/li&gt;
&lt;li&gt;'Listen and read' i.e. podcast player too&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stringer"&gt;&lt;a href="https://github.com/swanson/stringer"&gt;Stringer&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#stringer"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Stringer is simple... 'has no external dependencies, no social recommendations/sharing, and no fancy machine learning algorithms.'&lt;/em&gt;&lt;br /&gt;
Github Stars: 3.2k&lt;br /&gt;
Built With: Ruby&lt;br /&gt;
Test Website: No, but has a click to deploy to Heroku option&lt;br /&gt;
Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simple and nice UI&lt;/li&gt;
&lt;li&gt;Keyboard shortcuts (I use &lt;a href="https://vimium.github.io/"&gt;Vimium&lt;/a&gt; so not sold on this)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="selfoss"&gt;&lt;a href="https://selfoss.aditu.de/"&gt;selfoss&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#selfoss"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Didn't look further at this one PHP+ugly =&lt;/em&gt; 😱🏃‍♂️.&lt;br /&gt;
Github Stars: 1.9k&lt;br /&gt;
Built With: PHP&lt;br /&gt;
Test Website: No&lt;/p&gt;
&lt;h3 id="miniflux"&gt;&lt;a href="https://github.com/miniflux/miniflux"&gt;Miniflux&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#miniflux"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Ultra simplicity in terms of stack and UI. Slightly ugly, but I agree with the software philosophy of keeping it simple.&lt;/em&gt;&lt;br /&gt;
Github Stars: 1.9k&lt;br /&gt;
Built With: Plain go-lang+minimal vanilla JavaScript&lt;br /&gt;
Test Website: No&lt;br /&gt;
Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support multiple enclosures/attachments (Podcasts, videos, music, and images)&lt;/li&gt;
&lt;li&gt;Play videos from YouTube channels directly inside Miniflux&lt;/li&gt;
&lt;li&gt;Categories&lt;/li&gt;
&lt;li&gt;Bookmarks&lt;/li&gt;
&lt;li&gt;Fetch website icons (favicons)&lt;/li&gt;
&lt;li&gt;Save articles to third-party services e.g. Pocket&lt;/li&gt;
&lt;li&gt;Dark theme (otherwise kind of ugly)&lt;/li&gt;
&lt;li&gt;Optional keyboard shortcuts&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="freshrss"&gt;&lt;a href="https://github.com/FreshRSS/FreshRSS"&gt;FreshRSS&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#freshrss"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Like Selfoss - Didn't look further at this one PHP+ugly =&lt;/em&gt; 😱🏃‍♂️.&lt;br /&gt;
Github Stars: 2.3k&lt;br /&gt;
Built With: PHP&lt;br /&gt;
Test website: &lt;a href="https://demo.freshrss.org/i/"&gt;Yes&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="feedbin"&gt;&lt;a href="https://github.com/feedbin/feedbin"&gt;feedbin&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#feedbin"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Didn't look further as the app tech + ui wasn't appealing to me&lt;/em&gt;.&lt;br /&gt;
Github Stars: 2.5k&lt;br /&gt;
Built With: Ruby on Rails&lt;br /&gt;
Test Website: No - but free trial&lt;/p&gt;
&lt;h3 id="commafeed"&gt;&lt;a href="https://github.com/Athou/commafeed"&gt;Commafeed&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#commafeed"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Github at the time had a &lt;strong&gt;🛑build error&lt;/strong&gt; + Java turned me away&lt;/em&gt;&lt;br /&gt;
Github Stars: 1.7k&lt;br /&gt;
Built With: Java 😱 at the time of reviewing had a 'build: error'&lt;br /&gt;
Test Website: no - but free trial&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Final round contenders: Miniflux, Stringer and Winds&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="%F0%9F%8F%81-top-3-contenders---install-and-review"&gt;🏁 Top 3 contenders - Install and Review &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#%F0%9F%8F%81-top-3-contenders---install-and-review"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;N.B. I'm running these locally to assess before deploying to my server.&lt;/p&gt;
&lt;h3 id="stringer-2"&gt;&lt;a href="https://github.com/swanson/stringer"&gt;Stringer&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#stringer-2"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre class="language-bash"&gt;&lt;code class="language-bash"&gt;$ &lt;span class="token function"&gt;docker&lt;/span&gt; run &lt;span class="token parameter variable"&gt;--rm&lt;/span&gt; &lt;span class="token parameter variable"&gt;-it&lt;/span&gt; &lt;span class="token parameter variable"&gt;-e&lt;/span&gt; &lt;span class="token assign-left variable"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="token operator"&gt;=&lt;/span&gt;&lt;span class="token string"&gt;"sqlite3:':memory:'"&lt;/span&gt; &lt;span class="token parameter variable"&gt;-p&lt;/span&gt; &lt;span class="token number"&gt;8080&lt;/span&gt;:8080 mdswanson/stringer&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Opened on &lt;code&gt;localhost:8080&lt;/code&gt; - Simple as that. UI feels nice and simple. Unfortunately, the only import methods are from the long defunct Google Reader or with one URL at a time.&lt;br /&gt;
&lt;img alt="" src="https://lukesingham.com/content/images/2020/05/image.png" /&gt;&lt;br /&gt;
I tried importing the OPML file through this method but that seemed to crash the application - poor error handling?&lt;br /&gt;
&lt;img alt="" src="https://lukesingham.com/content/images/2020/05/image-1.png" /&gt;&lt;br /&gt;
Once you do manually load some feeds the &lt;code&gt;/feeds&lt;/code&gt; interface is nice and clean.&lt;br /&gt;
&lt;img alt="" src="https://lukesingham.com/content/images/2020/05/image-2.png" /&gt;&lt;br /&gt;
The &lt;code&gt;/news&lt;/code&gt; view is well laid out and the fonts used are a nice reading experience.&lt;br /&gt;
&lt;img alt="" src="https://lukesingham.com/content/images/2020/05/Screen-Shot-2020-05-31-at-09.41.46.png" /&gt;&lt;br /&gt;
Lastly, whilst poking around the Github repo I found this comment on &lt;a href="https://github.com/swanson/stringer/issues/512"&gt;this recent issue&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;... I don't think anyone is currently developing new features. I'm available to review code and merge it if you want to submit a patch.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So whilst the UI is nice and the setup is incredibly easy. The active development of  Miniflux and Wind have started to look more appealing.&lt;/p&gt;
&lt;p&gt;⭐️ 6.5 / 10 - Easy install, nice UI, functionality is low and active development has slowed.&lt;/p&gt;
&lt;h3 id="miniflux-2"&gt;&lt;a href="https://github.com/miniflux/miniflux"&gt;Miniflux&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#miniflux-2"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;You need postgres which I had not setup on my mac. I recommend doing this the easy way with &lt;a href="https://postgresapp.com/"&gt;postgres.app&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://miniflux.app/docs/installation.html#docker"&gt;instructions &lt;/a&gt;here are a little hairy. I went with saving the following to a &lt;code&gt;docker-compose.yml&lt;/code&gt;. I couldn't get it working on port 80 so switched the port to 8050.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="language-docker"&gt;&lt;code class="language-docker"&gt;version: '3'&lt;br /&gt;services:&lt;br /&gt;  miniflux:&lt;br /&gt;    image: miniflux/miniflux:latest&lt;br /&gt;    ports:&lt;br /&gt;      - "8050:8080"&lt;br /&gt;    depends_on:&lt;br /&gt;      - db&lt;br /&gt;    environment:&lt;br /&gt;      - DATABASE_URL=postgres://miniflux:secret@db/miniflux?sslmode=disable&lt;br /&gt;      - RUN_MIGRATIONS=1&lt;br /&gt;      - CREATE_ADMIN=1&lt;br /&gt;      - ADMIN_USERNAME=admin&lt;br /&gt;      - ADMIN_PASSWORD=test123&lt;br /&gt;  db:&lt;br /&gt;    image: postgres:latest&lt;br /&gt;    environment:&lt;br /&gt;      - POSTGRES_USER=miniflux&lt;br /&gt;      - POSTGRES_PASSWORD=secret&lt;br /&gt;    volumes:&lt;br /&gt;      - miniflux-db:/var/lib/postgresql/data&lt;br /&gt;volumes:&lt;br /&gt;  miniflux-db:&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then run the following commands and go to &lt;code&gt;localhost:8050&lt;/code&gt; once the containers have finished booting:&lt;/p&gt;
&lt;pre class="language-bash"&gt;&lt;code class="language-bash"&gt;$ &lt;span class="token function"&gt;docker-compose&lt;/span&gt; up &lt;span class="token parameter variable"&gt;-d&lt;/span&gt; db&lt;br /&gt;$ &lt;span class="token function"&gt;docker-compose&lt;/span&gt; up miniflux&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Firstly, the initial UI is &lt;em&gt;very&lt;/em&gt; simple, whilst incredibly plain is very functional. Navigating the app is explicit with text whereas Stringer you had to poke around using icons without text descriptions.&lt;br /&gt;
&lt;img alt="" src="https://lukesingham.com/content/images/2020/05/Screen-Shot-2020-05-31-at-09.46.28.png" /&gt;&lt;br /&gt;
There are several integrations to apps like Pocket, Instapaper and Wallabag. And after changing the theme. the reader is quite nice. Although, I do notice the entire page refresh from the server side oriented app - but I have to tell myself that the simplicity philosophy trumps the complexity of introducing a frontend framework.&lt;br /&gt;
&lt;img alt="" src="https://lukesingham.com/content/images/2020/05/Screen-Shot-2020-05-31-at-13.36.10.png" /&gt;&lt;br /&gt;
⭐️ 8.5 / 10 - Whilst being minimalistic has all the features you need, dark theme and the most active development of them all with a clear software philosophy.&lt;/p&gt;
&lt;h3 id="winds-2"&gt;&lt;a href="https://getstream.io/winds/"&gt;Winds&lt;/a&gt; &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#winds-2"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The install is relatively long particularly with the external dependencies which include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://getstream.io/"&gt;Stream&lt;/a&gt; - an API for building activity feeds + handle personalization (machine learning).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.algolia.com/"&gt;Algolia&lt;/a&gt; - for search&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/cloud/atlas"&gt;MongoDB Atlas&lt;/a&gt; - a DB as a service (DBaaS)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point I opt to sign up for a free account to try it out. I get the &lt;a href="https://apps.apple.com/us/app/winds-by-getstream-io/id1381446741"&gt;app from the apple store&lt;/a&gt;. Upon opening Winds, you are first confronted with a selection of interests like 'Programming', 'News' etc. I pick a couple and click next. I then have to create an account 😑 which I do. Then once logged in I have a very populated set of feeds and podcasts.&lt;br /&gt;
&lt;img alt="" src="https://lukesingham.com/content/images/2020/05/Screen-Shot-2020-05-31-at-14.02.22.png" /&gt;&lt;br /&gt;
I then want to try and remove all of these and start fresh, which no amount of clicking around can I figure out how to do other than clicking individually on each feed to remove it. I could create a new account and then add my OPML file - however at this point I'm already missing the bloat free approach of Miniflux.&lt;/p&gt;
&lt;p&gt;⭐️ 7 / 10  - for a non self-hosted piece of software I can see this is actually really nice. However major downsides of the installation complexity for self-hosted installation combined with features I don't particularly want. For instance, I don't want a recommender system - I can find my own content and probably consume too much as it is! If I want reinforcing recommender systems I'd go into a walled garden like Facebook.&lt;/p&gt;
&lt;h2 id="%F0%9F%8E%89-winner---miniflux-%F0%9F%8E%89"&gt;🎉 Winner - Miniflux 🎉 &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#%F0%9F%8E%89-winner---miniflux-%F0%9F%8E%89"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h2 id="rss-tips"&gt;RSS Tips &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#rss-tips"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Do you have a list of websites you want to follow?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A lot of sites you can just &lt;code&gt;/rss&lt;/code&gt; e.g &lt;code&gt;domainname.com/rss&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;For medium sites add &lt;code&gt;/feed/&lt;/code&gt; e.g. &lt;a href="https://medium.com/feed/@cjolowicz/"&gt;&lt;code&gt;https://medium.com/feed/@verygoodblogger/&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I used &lt;a href="https://opml-gen.ovh/"&gt;this site&lt;/a&gt; to convert a list feeds into an OPML file I could mass import to the various RSS feed reader apps.&lt;/li&gt;
&lt;li&gt;About a decade ago I used blogspot/blogger. It had a feed reader, but no export facility. Nostalgically, I thought I'd get the list from there. Here's a hack to export the list. First navigate to '&lt;a href="https://www.blogger.com/manage-blogs-following.g"&gt;Manage blogs I'm following&lt;/a&gt;', then open your browser dev tools and run the following JavaScript to get a list of the links.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="language-js"&gt;&lt;code class="language-js"&gt;&lt;span class="token keyword"&gt;const&lt;/span&gt; urls &lt;span class="token operator"&gt;=&lt;/span&gt; document&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;querySelectorAll&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token string"&gt;'.blogUrl'&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="token keyword"&gt;const&lt;/span&gt; url_list &lt;span class="token operator"&gt;=&lt;/span&gt; &lt;span class="token punctuation"&gt;[&lt;/span&gt;&lt;span class="token punctuation"&gt;]&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;urls&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;forEach&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;&lt;span class="token parameter"&gt;url&lt;/span&gt; &lt;span class="token operator"&gt;=&gt;&lt;/span&gt; &lt;span class="token punctuation"&gt;{&lt;/span&gt;&lt;br /&gt;  url_list&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;push&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;url&lt;span class="token punctuation"&gt;.&lt;/span&gt;innerText&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class="token punctuation"&gt;}&lt;/span&gt;&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;br /&gt;console&lt;span class="token punctuation"&gt;.&lt;/span&gt;&lt;span class="token function"&gt;log&lt;/span&gt;&lt;span class="token punctuation"&gt;(&lt;/span&gt;url_list&lt;span class="token punctuation"&gt;)&lt;/span&gt;&lt;span class="token punctuation"&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="related-interesting-projects"&gt;Related Interesting Projects &lt;a class="direct-link" href="https://lukesingham.com/rss-feed-reader/#related-interesting-projects"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RSS-Bridge/rss-bridge"&gt;RSS-Bridge&lt;/a&gt; - Create RSS feeds for websites without a feed.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wallabag/wallabag"&gt;Wallabag&lt;/a&gt; - Save articles from RSS feeds.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://archivebox.io/"&gt;Archivebox&lt;/a&gt; - Save all content e.g. videos, entire web pages and configure that save in multiple format. Solves link rot issues.&lt;/li&gt;
&lt;/ul&gt;</description><author>Luke Singham</author><pubDate>Sun, 31 May 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://lukesingham.com/rss-feed-reader/</guid></item><item><title>Pandemics intensify robotization of people</title><link>https://stop.zona-m.net/2020/05/pandemics-intensify-robotization-of-people/</link><description>&lt;p&gt;Too bad we already knew that&amp;hellip;&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Sat, 30 May 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/05/pandemics-intensify-robotization-of-people/</guid></item><item><title>Experimenting with developing a GTK app from scratch - Badgie</title><link>https://rajkumaar.co.in/posts/badgie/</link><description/><author>Online Home of Rajkumar</author><pubDate>Sat, 30 May 2020 17:17:00 GMT</pubDate><guid isPermaLink="true">https://rajkumaar.co.in/posts/badgie/</guid></item><item><title>A suite of apps to improve productivity of my peers - Amrita Repository</title><link>https://rajkumaar.co.in/posts/amrita-repository/</link><description/><author>Online Home of Rajkumar</author><pubDate>Sat, 30 May 2020 16:04:00 GMT</pubDate><guid isPermaLink="true">https://rajkumaar.co.in/posts/amrita-repository/</guid></item><item><title>Processing data mined from instagram-scraper with Python and Pandas</title><link>https://geo.rocks/post/processing-data-from-instagram-scraper/</link><description>&lt;p&gt;&lt;img alt="Picture by Polina Razorilova" src="https://images.unsplash.com/photo-1591630866811-eceedf667541?ixlib=rb-1.2.1&amp;amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;amp;auto=format&amp;amp;fit=crop&amp;amp;w=1867&amp;amp;q=80" title="Picture by Polina Razorilova" /&gt;
Photo by &lt;a href="https://unsplash.com/@poink?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Polina Razorilova&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/panda-snake?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Making use of Python and Pandas to quickly process mined social media data of instagram-scraper. Get most common hashtags!&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Sat, 30 May 2020 11:35:50 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/processing-data-from-instagram-scraper/</guid></item><item><title>Social Media Mining</title><link>https://geo.rocks/post/social-media-mining/</link><description>&lt;p&gt;A personal shortlist of well-working Python-based scrapers in 2020.&lt;/p&gt;</description><author>Geography &amp;amp; Coding</author><pubDate>Sat, 30 May 2020 11:35:50 GMT</pubDate><guid isPermaLink="true">https://geo.rocks/post/social-media-mining/</guid></item><item><title>Pont</title><link>https://mattkeeter.com/projects/pont</link><description>A multiplayer board game in Rust and WebAssembly</description><author>Matt Keeter</author><pubDate>Sat, 30 May 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://mattkeeter.com/projects/pont</guid></item><item><title>Welcome to Mataroa!</title><link>https://nutcroft.mataroa.blog/blog/welcome-to-mataroa/</link><description>&lt;p&gt;I am really happy to announce this new project!&lt;/p&gt;
&lt;p&gt;Created out of authentic admiration of Herman's genius idea of &lt;a href="https://bearblog.dev/"&gt;Bear Blog&lt;/a&gt;, &lt;a href="//mataroa.blog"&gt;Mataroa.blog&lt;/a&gt; is like Bear Blog but also a bit different. Namely, it has built-in first-class support to export your blog, and it also supports image hosting.&lt;/p&gt;
&lt;p&gt;The core philosophy, however, remains the same: dead simple blogging.&lt;/p&gt;
&lt;p&gt;Why would one create another service with minimal differences? Bear Blog is great indeed and by having another option the personal blogging ecosystem is enhanced. The space of no-tracking no-ads websites gets bigger. Faster, lighter web wins. At the end of the day, I really enjoyed building and thinking this project, so time well spent in my book!&lt;/p&gt;
&lt;p&gt;Hope you too will enjoy &lt;a href="//mataroa.blog"&gt;Mataroa.blog&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;– Theodore&lt;/p&gt;
&lt;p&gt;&lt;img alt="logo" src="https://mataroa.blog/images/896f9b41.png" /&gt;&lt;/p&gt;</description><author>nutcroft</author><pubDate>Sat, 30 May 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://nutcroft.mataroa.blog/blog/welcome-to-mataroa/</guid></item><item><title>Quick: who was banned from Wikipedia 11 years ago?</title><link>https://stop.zona-m.net/2020/05/quick-who-was-banned-from-wikipedia-11-years-ago/</link><description>&lt;p&gt;Which church banned which?&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Fri, 29 May 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/05/quick-who-was-banned-from-wikipedia-11-years-ago/</guid></item><item><title>Bringing AWS to App Developers</title><link>https://www.swyx.io/hello-aws</link><description>Where Amplify fits in AWS' trajectory, and why I am joining</description><author>swyx's site RSS Feed</author><pubDate>Fri, 29 May 2020 15:35:53 GMT</pubDate><guid isPermaLink="true">https://www.swyx.io/hello-aws</guid></item><item><title>initLogs 2: Sercret Life of Ifs</title><link>https://www.unsungnovelty.org/posts/05/2020/initlogs-2-sercret-life-of-ifs/</link><description>&lt;p&gt;&lt;code&gt;If&lt;/code&gt; statement is one of the conditional statements in JavaScript. But &lt;code&gt;if&lt;/code&gt; is not the most commonly used conditional statement, at least not when you are new to JavaScript. That would be the &lt;code&gt;if-else&lt;/code&gt; or &lt;code&gt;nested if else&lt;/code&gt; statement. As a person who is new to JS, the learning materials or the execrises never teach you the real world use cases of an &lt;code&gt;if&lt;/code&gt; statement. It is always a basic explanation with a basic example after which the materials often move to &lt;code&gt;if-else&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This has bothered me because I always wonder about the use of an &lt;code&gt;if&lt;/code&gt; statement is in JavaScript. I mean, we always need a &lt;code&gt;else&lt;/code&gt; part while writing the &lt;code&gt;if&lt;/code&gt; statements right?&lt;/p&gt;
&lt;p&gt;So, what are the usecases for an &lt;code&gt;if&lt;/code&gt; statement?
Here are some.&lt;/p&gt;
&lt;h2 id="1-as-a-minimal-version-of-if-else"&gt;1. As a minimal version of if-else&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-js"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;function&lt;/span&gt; &lt;span style="color: #a6e22e;"&gt;biggest&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;a&lt;/span&gt;, &lt;span style="color: #a6e22e;"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;a&lt;/span&gt; &lt;span style="color: #f92672;"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color: #a6e22e;"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;"A is greater"&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #e6db74;"&gt;"B is greater"&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #a6e22e;"&gt;biggest&lt;/span&gt; (&lt;span style="color: #ae81ff;"&gt;5&lt;/span&gt;, &lt;span style="color: #ae81ff;"&gt;6&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;// -&amp;gt; B is greater.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above example is for checking &lt;code&gt;if a &amp;gt; b&lt;/code&gt; or not. Here, you don&amp;rsquo;t need to add an &lt;code&gt;else&lt;/code&gt; part to check &lt;code&gt;if a &amp;lt; b&lt;/code&gt;. It is known that if &lt;code&gt;a &amp;gt; b&lt;/code&gt; is true what to execute and if it is false, what to execute. This is one way to use &lt;code&gt;if&lt;/code&gt; statements. But this technically has an &lt;code&gt;else&lt;/code&gt; part to execute when the initial condition is not satisfied. So where else can we use &lt;code&gt;if&lt;/code&gt; statements?&lt;/p&gt;
&lt;h2 id="2-to-replace-switch-statements"&gt;2. To replace switch statements&lt;/h2&gt;
&lt;p&gt;You can essentially write &lt;code&gt;if&lt;/code&gt; statements instead of writing &lt;code&gt;switch&lt;/code&gt; statements. &lt;code&gt;if&lt;/code&gt; statements are easier to write and easier to understand compared to &lt;code&gt;switch&lt;/code&gt; statements.&lt;/p&gt;
&lt;p&gt;Here is a &lt;code&gt;switch&lt;/code&gt; statement:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-js"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;function&lt;/span&gt; &lt;span style="color: #a6e22e;"&gt;howMuchFor&lt;/span&gt;(&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;switch&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;case&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Oranges'&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Oranges are $0.59 a pound.'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;case&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Apples'&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Apples are $0.32 a pound.'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;case&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Bananas'&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Bananas are $0.48 a pound.'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;case&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Cherries'&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Cherries are $3.00 a pound.'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;case&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Mangoes'&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;case&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Papayas'&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Mangoes and papayas are $2.79 a pound.'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;break&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #66d9ef;"&gt;default&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Sorry, we are out of '&lt;/span&gt; &lt;span style="color: #f92672;"&gt;+&lt;/span&gt; &lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;+&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'.'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;"Is there anything else you'd like?"&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #a6e22e;"&gt;howMuchFor&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Cherries'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;// -&amp;gt; Cherries are $3.00 a pound.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;// Is there anything else you'd like?
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be replaced with &lt;code&gt;if&lt;/code&gt; statements like&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-js"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;function&lt;/span&gt; &lt;span style="color: #a6e22e;"&gt;howMuchFor&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;===&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Oranges'&lt;/span&gt;) { &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;+&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;' are $0.59 a pound.'&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;===&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Apples'&lt;/span&gt;) { &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;+&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;' are $0.32 a pound.'&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;===&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Bananas'&lt;/span&gt;) { &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;+&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;' are $0.48 a pound.'&lt;/span&gt;);}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;===&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Cherries'&lt;/span&gt;) { &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;+&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;' are $3.00 a pound.'&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt; (&lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;===&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Mangoes'&lt;/span&gt; &lt;span style="color: #f92672;"&gt;||&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Papayas'&lt;/span&gt;) { &lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #a6e22e;"&gt;expr&lt;/span&gt; &lt;span style="color: #f92672;"&gt;+&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;' are $2.79 a pound'&lt;/span&gt;); }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #a6e22e;"&gt;howMuchFor&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;'Mangoes'&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;// -&amp;gt; Mangoes are $2.79 a pound.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Which do you think is easier to write and easier to understand? The one with &lt;code&gt;switch&lt;/code&gt; or the one with &lt;code&gt;if&lt;/code&gt;?&lt;/p&gt;
&lt;h2 id="3-then-there-is-another-usecase-validating"&gt;3. Then there is another usecase&amp;hellip; validating!&lt;/h2&gt;
&lt;figure&gt;&lt;img alt="Tony stark demonstrates Jericho range of missiles in Ironman movie." src="https://dev-to-uploads.s3.amazonaws.com/i/ovm8kcuyj6881aexwqp9.gif" /&gt;
&lt;/figure&gt;

&lt;p&gt;This is something I learnt while doing a side project (R.I.P) and thought was really interesting. This is the reason I wrote this blog post, because I was not sure if all the people who have just started to learn JavaScript knows about this.&lt;/p&gt;
&lt;p&gt;The function I wrote in the project was essentially doing some CRUD (Create, Read, Update, Delete) operations. My friend told me to use &lt;code&gt;if&lt;/code&gt; statements to validate the user inputs and I was like wow, &lt;em&gt;this is a great usecase for an &lt;code&gt;if&lt;/code&gt; statement!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s see how to validate using &lt;code&gt;if&lt;/code&gt; statement&amp;hellip;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-js"&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;let&lt;/span&gt; &lt;span style="color: #a6e22e;"&gt;infoDB&lt;/span&gt; &lt;span style="color: #f92672;"&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #a6e22e;"&gt;firstName&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;'Bob'&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #a6e22e;"&gt;lastName&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt; &lt;span style="color: #e6db74;"&gt;''&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;	&lt;span style="color: #a6e22e;"&gt;age&lt;/span&gt;&lt;span style="color: #f92672;"&gt;:&lt;/span&gt; &lt;span style="color: #ae81ff;"&gt;37&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt;(&lt;span style="color: #f92672;"&gt;!&lt;/span&gt;&lt;span style="color: #a6e22e;"&gt;infoDB&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;firstName&lt;/span&gt;) {&lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #e6db74;"&gt;"Please provide a first name to add your complete information."&lt;/span&gt;);} 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt;(&lt;span style="color: #f92672;"&gt;!&lt;/span&gt;&lt;span style="color: #a6e22e;"&gt;infoDB&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;lastName&lt;/span&gt;) {&lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #e6db74;"&gt;"Please provide a last name to add your complete information."&lt;/span&gt;);}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #66d9ef;"&gt;if&lt;/span&gt;(&lt;span style="color: #f92672;"&gt;!&lt;/span&gt;&lt;span style="color: #a6e22e;"&gt;infoDB&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;age&lt;/span&gt;) {&lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;( &lt;span style="color: #e6db74;"&gt;"Please provide a first name to add your complete information."&lt;/span&gt;);}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #a6e22e;"&gt;console&lt;/span&gt;.&lt;span style="color: #a6e22e;"&gt;log&lt;/span&gt;(&lt;span style="color: #a6e22e;"&gt;infoDB&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;// -&amp;gt; Please provide a last name to add your complete information.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display: flex;"&gt;&lt;span&gt;&lt;span style="color: #75715e;"&gt;// Final infoDB object -&amp;gt; { firstName: 'Bob', lastName: '', age: 37 }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The way to read the above statement is &lt;code&gt;if NO (for !) first name in myCompleteInfoDB&lt;/code&gt;, do something. Or &lt;code&gt;if NO last name in myCompleteInfoDV&lt;/code&gt;, do something and &lt;code&gt;if NO age in myCompleteInfoDB&lt;/code&gt;, do something. Although this is very simple and somewhat not a very useful program, this shows how you can validate things using an &lt;code&gt;if&lt;/code&gt; statement.&lt;/p&gt;
&lt;p&gt;That is it! These are some use cases for using &lt;code&gt;if&lt;/code&gt; statements in JavaScript. I know this is just a very basic thing for most of the people. But since it was not covered in the learning resources I used, it really was fascinating to me to know that we can use an &lt;code&gt;if&lt;/code&gt; statement in all these ways!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Found this article interesting or found a mistake/room for improvement? Please DM/Tweet me &lt;a href="https://twitter.com/unsungNovelty"&gt;@unsungNovelty&lt;/a&gt;. This is a part of a series of blogs called &lt;code&gt;#initlogs&lt;/code&gt; which shares some interesting things I found while learning to code.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This post was first published under the title &lt;a href="https://www.unsungnovelty.org/blog/secret-life-of-ifs/"&gt;&amp;ldquo;Secret life of ifs&amp;rdquo;&lt;/a&gt; in &lt;a href="https://www.unsungnovelty.org"&gt;https://www.unsungnovelty.org&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description><author>unsungNovelty</author><pubDate>Fri, 29 May 2020 15:19:00 GMT</pubDate><guid isPermaLink="true">https://www.unsungnovelty.org/posts/05/2020/initlogs-2-sercret-life-of-ifs/</guid></item><item><title>A first encounter with sketchnoting</title><link>https://ilearnt.com/blog/sketchnoting/</link><description>&lt;p&gt;One of the talks I attended at the Microsoft Build conference was called &amp;ldquo;Sketchnoting 101&amp;rdquo; and given by Nitya Narasimhan. It gave a very high level view of the approach and how anyone can quickly pick it up.&lt;/p&gt;</description><author>I Learnt</author><pubDate>Fri, 29 May 2020 14:00:00 GMT</pubDate><guid isPermaLink="true">https://ilearnt.com/blog/sketchnoting/</guid></item><item><title>Double Friday roundup for 2020-05-22, 2020-05-29</title><link>https://rjp.is/blogging/posts/2020/05/belated-friday/</link><description>Various things, links, and excitement.</description><author>infrequent oscillations</author><pubDate>Fri, 29 May 2020 11:53:30 GMT</pubDate><guid isPermaLink="true">https://rjp.is/blogging/posts/2020/05/belated-friday/</guid></item><item><title>ZZT in Go (using a Pascal-to-Go converter)</title><link>https://benhoyt.com/writings/zzt-in-go/</link><description>Describes my port of Adrian Siekierka's "Reconstruction of ZZT" to Go, done in a semi-automated way using a Pascal-to-Go converter.</description><author>Ben Hoyt's technical writing</author><pubDate>Fri, 29 May 2020 08:25:00 GMT</pubDate><guid isPermaLink="true">https://benhoyt.com/writings/zzt-in-go/</guid></item><item><title>Flask in Production</title><link>https://trigonaminima.github.io/2020/05/flask-prod/</link><description>After coding your flask app, when you do flask run, you get the following warning:</description><author>Playground</author><pubDate>Fri, 29 May 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://trigonaminima.github.io/2020/05/flask-prod/</guid></item><item><title>How to Use Linode Object Storage as a Terraform Backend</title><link>https://adriano.fyi/posts/2020-05-29-how-to-use-linode-object-storage-as-a-terraform-backend/</link><description>&lt;p&gt;This is mostly a note to my future self since I couldn&amp;rsquo;t find any documentation on using Terraform with
&lt;a href="https://linode.com"&gt;Linode Object Storage&lt;/a&gt; as a Terraform state backend. With that said, I hope to save other intrepid Linode users some
time if they&amp;rsquo;re lucky enough to come across this post. While I&amp;rsquo;ve explained the problem in terms of Linode, the solution here applies to any non-S3 object store compatible with the S3 API. Swap in the appropriate &lt;code&gt;endpoint&lt;/code&gt; for your provider.&lt;/p&gt;
&lt;p&gt;Chances are, if you&amp;rsquo;ve ever tried using Terraform&amp;rsquo;s S3 backend with a non-S3 object store, you&amp;rsquo;ve seen an error similar to the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Error: error using credentials to get account ID: error calling sts:GetCallerIdentity: InvalidClientTokenId: The security token included in the request is invalid.
status code: 403, request id: 60a33ac0-e460-4745-89dc-668d72413df3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Linode&amp;rsquo;s Object Storage is S3-compatible, which means anywhere you&amp;rsquo;d typically use Amazon&amp;rsquo;s S3 object storage &amp;ndash; as long
as you can swap in a custom endpoint URL &amp;ndash; you can use Linode Object Storage instead. Which, by the way, is really cheap.
So you should do it. Think of all the non-Bezos pockets you&amp;rsquo;ll be lining.&lt;/p&gt;
&lt;h2 id="change-your-backend"&gt;Change Your Backend&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s time to update your Terraform backend. First of all, you can &lt;em&gt;mostly&lt;/em&gt; refer to &lt;a href="https://www.terraform.io/docs/backends/types/s3.html"&gt;Terraform&amp;rsquo;s S3
documentation&lt;/a&gt; for this, but there are two key changes you&amp;rsquo;ll want
to make.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;endpoint&lt;/code&gt;: This is the hostname that Terraform uses to connect to Linode&amp;rsquo;s Object Store API. Terraform thinks
it&amp;rsquo;s talking to S3 but &amp;ndash; S3-compatibility to the rescue &amp;ndash; we&amp;rsquo;re dropping Linode into place.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;skip_credentials_validation&lt;/code&gt;: According to Terraform&amp;rsquo;s documentation: &lt;em&gt;(Optional) Skip the credentials validation
via the STS API.&lt;/em&gt; Presumably this is referring to &lt;a href="https://docs.aws.amazon.com/STS"&gt;Amazon
STS&lt;/a&gt;, but I&amp;rsquo;ll be honest; I don&amp;rsquo;t care. If this isn&amp;rsquo;t set to true, Terraform will ask
Amazon if you Linode credentials are valid S3 credentials. You don&amp;rsquo;t want that.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="example-backend-config"&gt;Example Backend Config&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;terraform {
  backend "s3" {
    bucket = "&amp;lt;YOUR LINODE BUCKET NAME&amp;gt;"
    key    = "/path/to/your/tfstate"
    region = "&amp;lt;LINODE REGION&amp;gt;"                        # e.g. us-east-1
    endpoint = "&amp;lt;LINODE REGION&amp;gt;.linodeobjects.com"    # e.g. us-east-1.linodeobjects.com
    skip_credentials_validation = true                # don't validate linode credentials with AWS's STS service
    access_key = "&amp;lt;LINODE OBJECT STORE ACCESS KEY&amp;gt;"
    secret_key = "&amp;lt;LINODE OBJECT STORE SECRET ACCESS KEY&amp;gt;"
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That should get you all set up using Linode Object Storage as your Terraform state backend.&lt;/p&gt;
&lt;p&gt;Cheers, AC&lt;/p&gt;</description><author>Adriano Caloiaro's personal blog</author><pubDate>Fri, 29 May 2020 03:00:00 GMT</pubDate><guid isPermaLink="true">https://adriano.fyi/posts/2020-05-29-how-to-use-linode-object-storage-as-a-terraform-backend/</guid></item><item><title>An electric motor in EVERY vehicle!</title><link>https://stop.zona-m.net/2020/05/an-electric-motor-in-every-vehicle/</link><description>&lt;p&gt;Like &amp;ldquo;a computer on every desktop&amp;rdquo;, but probably better. Much better.&lt;/p&gt;</description><author>Welcome to Marco Fioretti's website! on Stop at Zona-M</author><pubDate>Thu, 28 May 2020 21:00:00 GMT</pubDate><guid isPermaLink="true">https://stop.zona-m.net/2020/05/an-electric-motor-in-every-vehicle/</guid></item><item><title>From C to exec</title><link>https://dorotac.eu/posts/linking/</link><description>&lt;h1&gt;From C to exec&lt;/h1&gt;
&lt;p&gt;As the idea of having a technical blog grew in my mind and came closer to reality, it became obvious that it needs to host some kind of useful content apart from fluff and opinions. For this, I asked a few of my many technical friends:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What can I write about for you?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The suggestion that I liked the most was to write about the process that turns a C source file into an executable. The topic seems quite opaque, and indeed I don't recall seeing many ways to get into it without already having some background knowing about linking, translation units, and symbols.&lt;/p&gt;
&lt;p&gt;The goal of this post is to establish this background for a reader who has a passing familiarity with C.&lt;/p&gt;
&lt;p&gt;The seasoned reader should be warned that this is not a rigorous summary of the C standard, but rather a gentle introduction to the practical world of linking ELF files on GNU/Linux with GCC. Simplicity prevails, so while the C standard gives some room for different results, we'll explore only the case of unoptimized code and GCC version 9.&lt;/p&gt;
&lt;h2&gt;Act 1: Hello World&lt;/h2&gt;
&lt;p&gt;If you've dealt with C before, you're probably familiar with the &lt;code&gt;hello.c&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
int main(void) {
  puts("Hello World!");
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The process of turning code into an executable usually consists of at least 2 main steps: &lt;em&gt;compilation&lt;/em&gt; and &lt;em&gt;static linking&lt;/em&gt;. Depending on how you've usually done your programming, you may be familiar with different ways of performing those two steps. Let's take a look at two most popular ones.&lt;/p&gt;
&lt;h3&gt;Scene 1: Executable&lt;/h3&gt;
&lt;p&gt;This unsuspecting source file is about to undergo transformations that push it through the entire pipeline, changing it beyond recognition into a dynamic executable. Prepare your terminals:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc hello.c -o hello
# ./hello
Hello World!
# file hello
hello.o: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c1b39511769ab152611cd8ad83983dc724333b7a, not stripped
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Congratulations, we've turned code into an excutable!&lt;/p&gt;
&lt;h3&gt;Scene 2: Linking&lt;/h3&gt;
&lt;p&gt;But wait, wasn't this supposed to be 2 steps? Indeed, gcc does them both at the same time when not passed the &lt;code&gt;-c&lt;/code&gt; flag. Let's try again:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c hello.c -o hello.o
# ./hello.o
bash: ./hello.o: Permission denied
# file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's not the same kind of file as before! What we got is an object file instead: a compiled version of the source code, without any linking applied. Notice the "relocatable" instead of "executable".&lt;/p&gt;
&lt;p&gt;Let's link it now:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc hello.o -o hello
# ./hello
Hello World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's an executable again!&lt;/p&gt;
&lt;p&gt;You may wonder: what happened? how is the intermediate file different from the executable? why is it useful? Let's move on to the second act...&lt;/p&gt;
&lt;h2&gt;Act 2: Symbols&lt;/h2&gt;
&lt;p&gt;Here we discover why linking is useful and necessary.&lt;/p&gt;
&lt;p&gt;Our project is growing more complicated. It's composed of two source files now.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hello.c&lt;/code&gt; morphs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include "print.h"
int main(void) {
  print_hello();
  return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;printer.c&lt;/code&gt; contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
void print_hello(void) {
  puts("Hello World!");
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, they are joined by &lt;code&gt;print.h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void print_hello(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Scene 1: Object files&lt;/h3&gt;
&lt;p&gt;This is a more complicated project. A function from one file is referenced in another! And there's a new header file as well. How do we turn this into an executable? Of course, we could just use &lt;code&gt;gcc&lt;/code&gt; without the &lt;code&gt;-c&lt;/code&gt; flag, and hope that it figures out everything on its own. But that's not why we're here, so let's go step by step:&lt;/p&gt;
&lt;p&gt;This compiles the &lt;code&gt;printer.c&lt;/code&gt; file into an object file &lt;code&gt;printer.o&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gcc -c printer.c -o printer.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far so good. This produces the &lt;code&gt;hello.o&lt;/code&gt; file, which is compiled &lt;code&gt;hello.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gcc -c hello.c -o hello.o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wait a minute… &lt;code&gt;hello.c&lt;/code&gt; calls a function in &lt;code&gt;printer.c&lt;/code&gt;, but neither the command, nor &lt;code&gt;hello.c&lt;/code&gt; reference &lt;code&gt;printer.c&lt;/code&gt; anywhere! All they have is the name &lt;code&gt;print_hello&lt;/code&gt;, but not the body of the function. How does the compiler know what call to insert?&lt;/p&gt;
&lt;p&gt;Turns out that the compiler doesn't actually need to resolve all names to function bodies immediately. What it does instead is use &lt;em&gt;symbols&lt;/em&gt; to step around the problem. When a source file containing a function (or a global variable) named &lt;code&gt;print_hello&lt;/code&gt; gets compiled, the resulting object file (or a library) gets a symbol called &lt;code&gt;print_hello&lt;/code&gt;. On the other hand, any object file &lt;em&gt;using&lt;/em&gt; that symbol creates a reference to it (in the &lt;em&gt;relocation table&lt;/em&gt;), to be filled later: at linking time.&lt;/p&gt;
&lt;p&gt;Let's see it for ourselves:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# nm printer.o
0000000000000000 T print_hello
                 U puts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;According to &lt;code&gt;man nm&lt;/code&gt;, &lt;code&gt;T&lt;/code&gt; means the symbol is defined and in the &lt;em&gt;Text&lt;/em&gt; section. What about the other object file?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# nm hello.o
0000000000000000 T main
                 U print_hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As expected, &lt;code&gt;print_hello&lt;/code&gt; is referenced, but &lt;code&gt;U&lt;/code&gt; for "Undefined". It's simply not in this file.&lt;/p&gt;
&lt;p&gt;To fill in the vacancy, let's do the final step, and link both files together:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc hello.o print.o -o hello
# nm hello
[...]
0000000000401126 T main
0000000000401136 T print_hello
[...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are many more symbols, but the one we're interested in is there: &lt;code&gt;print_hello&lt;/code&gt; is now present. Notice that &lt;code&gt;main&lt;/code&gt; is present as well, meaning that we have the bodies of &lt;em&gt;both&lt;/em&gt; of our source files in the same compiled file now.&lt;/p&gt;
&lt;p&gt;The linker has performed &lt;em&gt;relocation&lt;/em&gt;. If you remember from before, the &lt;em&gt;object file&lt;/em&gt; type returned by the &lt;em&gt;file&lt;/em&gt; command was &lt;code&gt;relocatable&lt;/code&gt;. Our binary is now &lt;em&gt;executable&lt;/em&gt;, meaning that we can't repeat the same operation again to add some symbols we forgot about any more. But the linker will not let you forget anything anyway:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc hello.o -o hello
/usr/bin/ld: hello.o: in function `main':
hello.c:(.text+0x5): undefined reference to `print_hello'
collect2: error: ld returned 1 exit status
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Scene 2: Header files&lt;/h3&gt;
&lt;p&gt;The other anomaly introduced in this example is the header file. It contains only one line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void print_hello(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What is it for? Suppose we didn't have it. The only information about &lt;code&gt;print_hello&lt;/code&gt; would come from its call, which looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  print_hello();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Can you guess the type of the function? Well, sort of: it takes no arguments, but it may return anything. And if we made a mistake, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  print_hello("world");
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;a compiler guessing the type of arguments would happily go on trusting what we wrote, instead of warning us of the extra argument. The line in the header file, called &lt;em&gt;prototype&lt;/em&gt;, informs the compiler about which functions are available, and what type they have.&lt;/p&gt;
&lt;p&gt;As an aside, you might notice that this was already partially covered by the linker: when function &lt;code&gt;print_hello&lt;/code&gt; was unavailable in our example, we received am "undefined reference" message from the linker. Couldn't we get rid of headers and let the linker catch those errors? Indeed, gcc-c++ uses some additional information to store function type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# cp printer.c printer.cpp
# g++ -c printer.cpp -o printerpp.o
# nm printerpp.o 
                 U puts
0000000000000000 T _Z11print_hellov
# c++filt _Z11print_hellov
print_hello()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is called &lt;em&gt;symbol mangling&lt;/em&gt;, and C compilers don't generally use it, leaving us with obligatory prototypes, and, in practice, header files.&lt;/p&gt;
&lt;p&gt;Despite this, C++ still requires prototypes inside the header files, for reasons that are not clear to me. I suspect compatibility with C, or even IDE suggestions.&lt;/p&gt;
&lt;h3&gt;Scene 3: Static libraries&lt;/h3&gt;
&lt;p&gt;Static libraries are used when additional functionality provided by third party is needed. They also provide symbols, and may depend on other libraries. If this sounds familiar, it's because it is! That's the same core functionality as object files.&lt;/p&gt;
&lt;p&gt;In fact, if you look at a shared library on Linux (file name ending with &lt;code&gt;.a&lt;/code&gt;), it's just an &lt;em&gt;ar&lt;/em&gt; archive containing multiple object files.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ar -t /usr/lib64/libm-2.29.a
s_lib_version.o
s_matherr.o
s_signgam.o
fclrexcpt.o
fgetexcptflg.o
fraiseexcpt.o
[...]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's turn our printer into a static library and see for ourselves:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# gcc -c -o printer.o printer.c
# ar rcs libprinter.a printer.o
# nm libprinter.a

printer.o:
0000000000000000 T print_hello
                 U puts
# gcc hello.o libprinter.a -o hello
# ./hello
Hello World!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Intermission&lt;/h2&gt;
&lt;p&gt;Those steps are sufficient if you need to create a binary for the bare metal, for example for an Arduino with an AVR microcontroller, or if you're creating a basic operating system yourself. The executable needs to be provided in the final form, taking minimal advantage of libraries present on the system. Anything with an operating system permitting &lt;em&gt;dynamic (shared) libraries&lt;/em&gt; (like Windows or Linux) is likely to have a 3rd step, which happens immediately before execution: &lt;em&gt;dynamic linking&lt;/em&gt;. We will cover that in a future chapter, together with various gotchas related to how C emits symbols.&lt;/p&gt;
&lt;h2&gt;Glossary&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;compilation&lt;/em&gt;: turning a &lt;em&gt;source&lt;/em&gt; representation of a program into &lt;em&gt;machine code&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;executable&lt;/em&gt;: a runnable program&lt;/li&gt;
&lt;li&gt;&lt;em&gt;header file&lt;/em&gt;: a file in the C language containing, among others, &lt;em&gt;prototypes&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;linking&lt;/em&gt;: combining different &lt;em&gt;object files&lt;/em&gt; together&lt;/li&gt;
&lt;li&gt;&lt;em&gt;object file&lt;/em&gt;: a &lt;em&gt;compiled&lt;/em&gt; form of the &lt;em&gt;source&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;prototype&lt;/em&gt;: a piece of