<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Code Reading]]></title><description><![CDATA[Your weekly {} of interesting code and Delyan's commentary on it!]]></description><link>https://www.codereading.org</link><image><url>https://www.codereading.org/img/substack.png</url><title>Code Reading</title><link>https://www.codereading.org</link></image><generator>Substack</generator><lastBuildDate>Fri, 01 May 2026 01:20:16 GMT</lastBuildDate><atom:link href="https://www.codereading.org/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Delyan Raychev]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[codereading@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[codereading@substack.com]]></itunes:email><itunes:name><![CDATA[Delyan Raychev]]></itunes:name></itunes:owner><itunes:author><![CDATA[Delyan Raychev]]></itunes:author><googleplay:owner><![CDATA[codereading@substack.com]]></googleplay:owner><googleplay:email><![CDATA[codereading@substack.com]]></googleplay:email><googleplay:author><![CDATA[Delyan Raychev]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Reading the OpenSolaris Kernel: A Linked List Worth Studying]]></title><description><![CDATA[Practical lessons in software design from the OpenSolaris kernel]]></description><link>https://www.codereading.org/p/reading-the-opensolaris-kernel-a</link><guid isPermaLink="false">https://www.codereading.org/p/reading-the-opensolaris-kernel-a</guid><dc:creator><![CDATA[Delyan Raychev]]></dc:creator><pubDate>Tue, 31 Mar 2026 00:34:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ERQX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Today we are looking at the <a href="https://github.com/kofemann/opensolaris/tree/master/usr/src">OpenSolaris kernel</a>, and we are analyzing an implementation of a <a href="https://en.wikipedia.org/wiki/Linked_list">linked list</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qhDx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qhDx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 424w, https://substackcdn.com/image/fetch/$s_!qhDx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 848w, https://substackcdn.com/image/fetch/$s_!qhDx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!qhDx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qhDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg" width="200" height="300" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:300,&quot;width&quot;:200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;opensolaris-logo&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="opensolaris-logo" title="opensolaris-logo" srcset="https://substackcdn.com/image/fetch/$s_!qhDx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 424w, https://substackcdn.com/image/fetch/$s_!qhDx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 848w, https://substackcdn.com/image/fetch/$s_!qhDx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!qhDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2992f18-69c0-44bd-b34c-db5fb52a6821_200x300.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Most programmers are first introduced to linked lists in a classroom setting: a small struct with a <code>next</code> pointer, perhaps followed by a <code>prev</code> pointer, and a few insertion and deletion functions written by the professor on a whiteboard. Those examples are useful, but they are not how the idea becomes real-world-truly-interesting. To see this, study a linked list in a real operating system - albeit a dead one.</p><p>The <a href="https://web.archive.org/web/20080403044047/http://www.opensolaris.org/os/">OpenSolaris</a> kernel offers exactly that: a generic linked list implementation that is compact, carefully crafted, and revealing. It lives in <a href="https://github.com/kofemann/opensolaris/blob/80192cd83bf665e708269dae856f9145f7190f74/usr/src/uts/common/sys/list_impl.h#L38-L47">usr/src/uts/common/sys/list_impl.h</a> and <a href="https://github.com/kofemann/opensolaris/blob/80192cd83bf665e708269dae856f9145f7190f74/usr/src/uts/common/os/list.c#L64">usr/src/uts/common/os/list.c</a>, and it truly rewards <strong>slow reading</strong>.</p><p>The first surprise is that the list is <a href="https://chatgpt.com/share/69cb14e5-ca30-83e8-90fd-4e66b54850d1">intrusive</a>. In a <a href="https://www3.cs.stonybrook.edu/~skiena/373/newlectures/lecture4.pdf">textbook implementation</a>, the list node often wraps the payload: a node contains <em>data</em> and <em>links</em>. Here, the payload object only contains the links. The fundamental node type is only this:</p><p><code>struct list_node {</code></p><p><code>    struct list_node *list_next;</code></p><p><code>    struct list_node *list_prev;</code></p><p><code>};</code></p><p>And the list itself looks like this:</p><p><code>struct list {</code></p><p><code>    size_t  list_size;</code></p><p><code>    size_t  list_offset;</code></p><p><code>    struct list_node list_head;</code></p><p><code>};</code></p><p>That <code>list_offset</code> field is the key to the whole design. It tells the list code where, inside a larger object, the embedded <code>list_node</code> lives. This allows the same implementation to manage lists of many different object types without allocating wrapper nodes. In kernel code, that is an excellent trade: fewer allocations, less indirection, and tighter control over memory layout.</p><p>Once you understand that design, two small macros become the bridge between &#8220;user object&#8221; and &#8220;list node&#8221;:</p><p><code>#define list_d2l(a, obj) ((list_node_t *)(((char *)obj) + (a)-&gt;list_offset))</code></p><p><code>#define list_object(a, node) ((void *)(((char *)node) - (a)-&gt;list_offset))</code></p><p>The first takes an object and finds its embedded link field. The second takes a link field and reconstructs the object that contains it. This is a classic systems-programming move: keep the abstraction generic, but make the cost explicit and low.</p><p>The second thing worth noticing is the use of a sentinel head node. When the list is created, the head&#8217;s next and prev pointers both point back to the head itself:</p><p><code>list-&gt;list_head.list_next = list-&gt;list_head.list_prev = &amp;list-&gt;list_head;</code></p><p>This means an empty list is represented not by a <code>NULL</code>, but by a tiny circular structure. That choice simplifies the rest of the code - insertion and removal do not need separate &#8220;empty list&#8221; logic and head &amp; tail operations become ordinary pointer updates around the sentinel.</p><p>The insertion code is a nice example of how much clarity can fit in a few lines. Here is the essence of inserting after a node:</p><p><code>lnew-&gt;list_prev = node;</code></p><p><code>lnew-&gt;list_next = node-&gt;list_next;</code></p><p><code>node-&gt;list_next-&gt;list_prev = lnew;</code></p><p><code>node-&gt;list_next = lnew;</code></p><p>This is the kind of source code worth reading - it is short, but it encodes a structural invariant: <strong>every forward link must have a matching backward link</strong>, and every update must preserve that symmetry. There are only four assignments.</p><p>Removal is equally direct:</p><p><code>node-&gt;list_prev-&gt;list_next = node-&gt;list_next;</code></p><p><code>node-&gt;list_next-&gt;list_prev = node-&gt;list_prev;</code></p><p><code>node-&gt;list_next = node-&gt;list_prev = NULL;</code></p><p>The last line is especially telling. The implementation deliberately clears the removed node&#8217;s pointers. That is not strictly necessary for the list to function, but it is good engineering practice. A removed node is now visibly inactive. If somebody tries to remove it again, or mistakes it for a live element - the bug would be easier to detect.</p><p>Traversal is built on the same sentinel idea. Internally, the list is circular. Externally, the API presents a simpler interface: once iteration reaches the head again, it returns NULL. So client code gets the clean, familiar form:</p><p><code>for (p = list_head(listp); p != NULL; p = list_next(listp, p)) {/* use p */}</code></p><p>That pattern appears in real OpenSolaris code. In <a href="https://github.com/kofemann/opensolaris/blob/80192cd83bf665e708269dae856f9145f7190f74/usr/src/uts/intel/io/pci/pci_boot.c#L349">pci_boot.c</a>, for example, the kernel walks a list of cached PCI unit-address entries <a href="https://github.com/kofemann/opensolaris/blob/80192cd83bf665e708269dae856f9145f7190f74/usr/src/uts/intel/io/pci/pci_boot.c#L350">using</a> <code>list_head()</code> and <code>list_next()</code>. This is such simple abstraction!</p><p>What, then, does this implementation teach us about linked lists?</p><p><strong>First</strong>, linked lists are less about the shape of a node than about the invariants that govern mutation. Good list code makes those invariants easy to see and hard to violate.</p><p><strong>Second</strong>, production systems code often chooses intrusive structures because they are efficient and flexible. A beginner may think of this as an advanced trick but in reality, it is an expression of a basic principle: put the machinery where it costs the least.</p><p><strong>Third</strong>, elegance in low-level code often means <strong>removing special cases</strong>. The sentinel node is not decorative. It exists because it simplifies every operation around it.</p><p>And <strong>finally</strong>, reading code like this reminds us that &#8220;data structures&#8221; are not just academic exercises. In a kernel, a linked list is not there to illustrate a concept. It is there because someone needed a generic, reusable, predictable mechanism, and this was the design that best satisfied those constraints.</p><p>If you want to get better at reading systems software, this is an ideal specimen. Start with the structures. Then read the conversion macros. Then insertion, removal, and traversal.  With this you learn more than just how a linked list works - you get an intuition of how experienced engineers turn a familiar idea into robust infrastructure.</p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ERQX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ERQX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!ERQX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!ERQX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!ERQX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ERQX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png" width="1280" height="800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:800,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;OpenSolaris Desktop Screenshot&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="OpenSolaris Desktop Screenshot" title="OpenSolaris Desktop Screenshot" srcset="https://substackcdn.com/image/fetch/$s_!ERQX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 424w, https://substackcdn.com/image/fetch/$s_!ERQX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 848w, https://substackcdn.com/image/fetch/$s_!ERQX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 1272w, https://substackcdn.com/image/fetch/$s_!ERQX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd3feb74-e4ad-4416-9066-3e0d2e13d727_1280x800.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">OpenSolaris was very pretty! (and functional)</figcaption></figure></div>]]></content:encoded></item><item><title><![CDATA[ed is the standard text editor]]></title><description><![CDATA[Reading GNU ed's source code from 1993]]></description><link>https://www.codereading.org/p/ed-is-the-standard-text-editor</link><guid isPermaLink="false">https://www.codereading.org/p/ed-is-the-standard-text-editor</guid><dc:creator><![CDATA[Delyan Raychev]]></dc:creator><pubDate>Wed, 03 Jan 2024 07:06:14 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ec219fce-5fb5-4893-9672-f4bd56abf0fe_450x200.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I really enjoy <a href="https://craphound.com/">Cory Doctorow's writings</a>. <a href="https://craphound.com/category/lostcause/">Lost Cause</a> was great! I'm rereading <a href="https://craphound.com/category/attacksurface/">Attack Surface</a>. Cory is prolific, thorough, and deliberate. It is worth looking at his <a href="https://usesthis.com/interviews/cory.doctorow/">toolbox</a> to get a glimpse of how he works. When I realized that he uses GNOME&#8217;s <a href="https://gedit-technology.github.io/apps/gedit/">Gedit</a> text editor I was surprised. How do you write a book every year plus hundreds of articles and use such a primitive tool? </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AEw5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AEw5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 424w, https://substackcdn.com/image/fetch/$s_!AEw5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 848w, https://substackcdn.com/image/fetch/$s_!AEw5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 1272w, https://substackcdn.com/image/fetch/$s_!AEw5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AEw5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png" width="48" height="48" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:128,&quot;width&quot;:128,&quot;resizeWidth&quot;:48,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;gedit&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="gedit" title="gedit" srcset="https://substackcdn.com/image/fetch/$s_!AEw5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 424w, https://substackcdn.com/image/fetch/$s_!AEw5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 848w, https://substackcdn.com/image/fetch/$s_!AEw5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 1272w, https://substackcdn.com/image/fetch/$s_!AEw5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbbca812e-8a9b-436a-be4c-f3c4d2ab6af8_128x128.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>I found the answer in the "<a href="http://www.locusmag.com/Features/2009/01/cory-doctorow-writing-in-age-of.html">Writing in the Age of Distraction</a>" article published in the January 2009 issue of Locus magazine. Turns out Cory is so productive not despite of, but because of the choice of minimalist tooling. In the article Cory advises other writers: "Kill your word-processor" and "use a text-editor, like vi, <a href="https://www.gnu.org/software/emacs/">Emacs</a>, <a href="https://www.textpad.com/">TextPad</a>, <a href="https://www.barebones.com/products/bbedit/">BBEdit</a>, <a href="https://gedit-text-editor.org/">Gedit</a>, <a href="https://apps.kde.org/kwrite/">KWrite</a> or any of a host of editors."</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.codereading.org/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Code Reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p><a href="https://craphound.com/">Doctorow</a> recommends these text editors because they are "some of the most venerable, reliable, powerful tools in the history of software (since they're at the core of all other software) and they have almost no distracting features &#8212; but they do have powerful search-and-replace functions."</p><p>Now that I understand the principles behind Cory&#8217;s preference for <a href="https://gedit-text-editor.org/">Gedit</a>, I wondered if there is some other robust, OSS, UNIX tool out there that is even more minimal than Gedit.</p><p><strong><a href="https://en.wikipedia.org/wiki/Ed_(text_editor)">ed</a></strong> came to mind. As it is well understood, <a href="https://www.gnu.org/fun/jokes/ed-msg.en.html">ed is the standard text editor</a>. Presumably, if you want to call your operating system a UNIX, you need to conform to <a href="https://en.wikipedia.org/wiki/Single_UNIX_Specification">the Single UNIX Specification (SUS)</a>. That would oblige you to include some version of ed in your <a href="https://distrowatch.com/">Linux distribution</a> too. And so ed runs on everything &#8212; even <a href="https://www.ibm.com/docs/en/zos/3.1.0?topic=files-using-ed-editor">IBM zOS</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://commons.wikimedia.org/w/index.php?curid=4031065" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!96KP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 424w, https://substackcdn.com/image/fetch/$s_!96KP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 848w, https://substackcdn.com/image/fetch/$s_!96KP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!96KP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!96KP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg" width="450" height="200" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/306737f4-203d-4965-b90b-7606443de472_450x200.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:200,&quot;width&quot;:450,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;undefined&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:&quot;https://commons.wikimedia.org/w/index.php?curid=4031065&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="undefined" title="undefined" srcset="https://substackcdn.com/image/fetch/$s_!96KP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 424w, https://substackcdn.com/image/fetch/$s_!96KP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 848w, https://substackcdn.com/image/fetch/$s_!96KP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!96KP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306737f4-203d-4965-b90b-7606443de472_450x200.jpeg 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>ed was created by <a href="https://en.wikipedia.org/wiki/Ken_Thompson">Ken Thompson</a> in 1969 at AT&amp;T Bell Labs. The first version was written in assembler. Later versions of ed were implemented in C.</p><p>In 1993 Andrew Moore was inspired by the &#8220;ed algorithm&#8221; as described in Brian W. Kernighan and P. J. Plauger's book "<a href="https://www.biblio.com/9780201103427">Software Tools in Pascal</a>" (Addison-Wesley, 1981) recreated the editor within <a href="https://www.gnu.org/software/ed/">the GNU ecosystem</a>. The 1993 version is the one Apple includes in macOS as well. The 1993 version by Andrew Moore is what we'll explore here.</p><p>Taking a cursory look at the source code - the editor is essentially 8 fairly small C files:</p><ol><li><p> <a href="https://delyan.org/ed/html/buf.c.html">buf.c</a> - 6,682 bytes</p></li><li><p> <a href="https://delyan.org/ed/html/cbc.c.html">cbc.c</a> - 10,066 bytes</p></li><li><p> <a href="https://delyan.org/ed/html/glbl.c.html">glbl.c</a> - 6,107 bytes</p></li><li><p> <a href="https://delyan.org/ed/html/io.c.html">io.c</a> - 8,486 bytes</p></li><li><p> <a href="https://delyan.org/ed/html/main.c.html">main.c</a> - 33,050 bytes</p></li><li><p> <a href="https://delyan.org/ed/html/re.c.html">re.c</a> - 3,721 bytes</p></li><li><p> <a href="https://delyan.org/ed/html/sub.c.html">sub.c</a> - 6,859 bytes</p></li><li><p> <a href="https://delyan.org/ed/html/undo.c.html">undo.c</a> - 4,313 bytes</p></li></ol><p>Before we jump into <a href="https://delyan.org/ed/html/main.c.html">main.c</a>, which is the largest one (33K) let's go over a few ed sample commands to get a feel of how this works. Much like vi, which originates from ed, ed has 2 modes: command and input. Once launched (<strong>ed article.txt</strong> to open a file) it is in command mode.</p><ol><li><p><strong>1p</strong> &#8212; prints the first line of the opened file</p></li><li><p><strong>1i</strong> &#8212; inserts a new first line</p></li><li><p><strong>.</strong> &#8212; when in edit mode completes the text insertion</p></li><li><p><strong>,n</strong> &#8212; prints all lines by prepending a line number</p></li><li><p><strong>2s/foo/bar/g</strong> &#8212; replace foo with bar on the second line</p></li></ol><p>Classic C opening:</p><pre><code>/* ed: line editor */
int
main(int argc, char *argv[])
{</code></pre><p>The comments are fantastic. The clarity of the comments rivals that of <a href="https://en.wikipedia.org/wiki/A_Commentary_on_the_UNIX_Operating_System">Lion's Commentary</a>. Here are the declarations of <a href="https://delyan.org/ed/html/main.c.html#globals">global variables</a> as an example:</p><pre><code>/* static buffers */
char stdinbuf[1];&#9;&#9;          /* stdin buffer */
char *shcmd;&#9;&#9;&#9;/* shell command buffer */
int shcmdsz;&#9;&#9;&#9;/* shell command buffer size */
int shcmdi;&#9;&#9;&#9;/* shell command buffer index */
char *ibuf;&#9;&#9;&#9;/* ed command-line buffer */
int ibufsz;&#9;&#9;&#9;/* ed command-line buffer size */
char *ibufp;&#9;&#9;&#9;/* pointer to ed command-line buffer */

/* global flags */
int des = 0;&#9;&#9;&#9;/* if set, use crypt(3) for i/o */
...
int sigactive = 0;&#9;&#9;/* if set, signal handlers are enabled */
int posixly_correct = 0;&#9;/* if set, POSIX behavior as per */
/* <a href="http://www.opengroup.org/onlinepubs/009695399/utilities/ed.html">http://www.opengroup.org/onlinepubs/009695399/utilities/ed.html</a> */

...
int lineno;&#9;&#9;&#9;/* script line number */
const char *prompt;&#9;&#9;/* command-line prompt */
const char *dps = "*";&#9;&#9;/* default command-line prompt */
</code></pre><p>One interesting find &#8212; early into <a href="https://delyan.org/ed/html/main.c.html">main()</a> we see the <strong><a href="https://delyan.org/ed/html/main.c.html#goto-top">top:</a></strong> label. And of course further down in the source is the "<strong><a href="https://delyan.org/ed/html/main.c.html#goto-top">goto top;</a></strong>" statement. Many of us have been taught that GOTO should not be used. This started in 1968 with a letter by Edsger Dijkstra called "<a href="https://en.wikipedia.org/wiki/Goto#Criticism">Go-to statement considered harmful</a>". But <strong>goto top;</strong> is here nevertheless. It seems fairly safe and unambiguous as it is used in the context of parsing command line arguments.</p><p>After the buffer is initialized and the file is checked, there comes <a href="https://delyan.org/ed/html/main.c.html#infinite-loop">the infinite loop</a>:</p><pre><code>for (;;) {</code></pre><p>Within the loop there is the inevitable invocation of <strong><a href="https://delyan.org/ed/html/main.c.html#exec-command">exec_command()</a></strong>.</p><p>And as the comment indicates - this is where the command we have given ed is executed. One such example would be "<strong>,n</strong>", which asks ed to print all lines with a leading line number.</p><p>The <strong><a href="https://delyan.org/ed/html/main.c.html#exec-command">exec_command()</a></strong> function is one giant case statement. What does ed do when we enter "<strong>,n</strong>"? Let's search for "<strong><a href="https://delyan.org/ed/html/main.c.html#case-n">case 'n':</a></strong>" in the code:</p><pre><code>case 'n':
&#9;if (<strong>check_addr_range</strong>(current_addr, current_addr) &lt; 0)
&#9;&#9;return ERR;
&#9;GET_COMMAND_SUFFIX();
&#9;if (<strong>display_lines</strong>(first_addr, second_addr, gflag | GNP) &lt; 0)
&#9;&#9;return ERR;
&#9;gflag = 0;
&#9;break;</code></pre><p>The essence here seems to be the <strong><a href="https://delyan.org/ed/html/main.c.html#display-lines">display_lines()</a></strong> function. Presumably by the time we detected the 'n' command, we had already collected the <strong>first_addr</strong> and <strong>second_addr</strong>, so now we know the begin and end lines of the range we want to print with line numbers.</p><p>The function <strong><a href="https://delyan.org/ed/html/main.c.html#display-lines">display_lines()</a></strong> is tiny and a well structured one:</p><pre><code>/* display_lines: print a range of lines to stdout */
int
display_lines(long from, long to, int gflag)
{
&#9;line_t *bp;
&#9;line_t *ep;
&#9;char *s;
&#9;if (!from) {
&#9;&#9;errmsg = "invalid address";
&#9;&#9;return ERR;
&#9;}
&#9;ep = get_addressed_line_node(INC_MOD(to, addr_last));
&#9;bp = get_addressed_line_node(from);
&#9;for (; bp != ep; bp = bp-&gt;q_forw) {
&#9;&#9;if ((s = get_sbuf_line(bp)) == NULL)
&#9;&#9;&#9;return ERR;
&#9;&#9;if (put_tty_line(s, bp-&gt;len, current_addr = from++, gflag) &lt; 0)
&#9;&#9;&#9;return ERR;
&#9;}
&#9;return 0;
}</code></pre><p>The function is given a from and to lines. It will print the range of lines between to and from and will show the line number for each one. In my case, when I entered ",n", ed showed me the full contents of my test file:</p><pre><code>,n
1       this is the new first line
2       this was the first line, but NOW it is the second one
3       two
4       three</code></pre><p>Despite the excellent comments, in typical C fashion, we have some extremely short variable names. I am not a fan of single or even double-letter variable names. In some cases, when the pattern is well known it is acceptable, for example &#8220;<strong>for (i=0; ...</strong>&#8221; But in the case of <strong>bp</strong> and <strong>ep</strong> &#8212; we are left guessing what these may mean. Since bp is a struct for the "from" line and ep for the "to" line we could assume these perhaps mean:</p><ul><li><p>bp = Beginning Point (from)</p></li><li><p>ep = Eng Point (to)</p></li></ul><p>The loop "<strong><a href="https://delyan.org/ed/html/main.c.html#forbpep">for (; bp != ep; bp = bp-&gt;q_forw) {</a></strong>" then is going to move the beginning point forward until it overlaps with the end point. That makes sense as we want to start with <em>from</em> and print all the lines until <em>to</em>.</p><p>The function "<strong>s = get_sbuf_line(bp)</strong>" will fetch a pointer to a null terminated string for each line we 'step' on. And <strong><a href="https://delyan.org/ed/html/io.c.html#put-tty-line">put_tty_line(s...)</a></strong> would print it.</p><p>Let's take a look at the printer:</p><pre><code>/* put_tty_line: print text to stdout */
int
put_tty_line(const char *s, int l, long n, int gflag)
{</code></pre><p>This is defined in the <strong><a href="https://delyan.org/ed/html/io.c.html#put-tty-line">io.c</a></strong> file (we were in <a href="https://delyan.org/ed/html/main.c.html#infinite-loop">main.c</a> until now).</p><p>The function <strong><a href="https://delyan.org/ed/html/io.c.html#put-tty-line">put_tty_line()</a></strong> is generic and used by a few ed commands. So when we use '<strong>,n</strong>' - the first if statement will know that this is an 'n' and not just a 'p' (print without line numbers) and will prepend the line number for each line:</p><pre><code>&#9;&#9;printf("%ld\t", n);</code></pre><p>The loop "<strong><a href="https://delyan.org/ed/html/io.c.html#looplminusminus">for (; l--; s++) {</a></strong>" is where the line's characters are printed. We don't need a loop counter or index variable (i) here. Because of the single-letter variable, it is not crystal clear, but "l" in this case is the length of the current line we are working on. So our loop will continue as long as the value of l is greater than 0. The <strong>--</strong> operator decrements l by 1 after each iteration, which is actually the output of a character to the <a href="https://en.wikipedia.org/wiki/Tty_(Unix)">TTY</a>.</p><p>The several indentation levels of if statements will perform some minimal sanitation to ensure we don't print control characters or stuff our TTY can't handle and will eventually resort to putchar().</p><p>And <strong><a href="https://linux.die.net/man/3/putchar">putchar()</a></strong> is a C library function, which writes a character specified by the specified by the "int char" argument char to <code>stdout</code>.</p><p>The function will also make sure that we don't go beyond the 72 columns as defined back in main.c</p><pre><code>int cols = 72;                          /* wrap column */</code></pre><p></p><div><hr></div><p></p><p>There is so much more interesting and well written code in this <a href="https://delyan.org/ed/">tiny repo</a>. The ed editor is truly a masterpiece. We will come back to this source code when we examine some of the modern editors and look at how these have been influenced by ed.</p><p></p><p>Happy Code Reading!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.codereading.org/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Code Reading! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Reading wireguard-go]]></title><description><![CDATA[minima primer on Go CLI and daemonization]]></description><link>https://www.codereading.org/p/reading-wireguard-go</link><guid isPermaLink="false">https://www.codereading.org/p/reading-wireguard-go</guid><dc:creator><![CDATA[Delyan Raychev]]></dc:creator><pubDate>Mon, 11 Jan 2021 03:11:26 GMT</pubDate><content:encoded><![CDATA[<p>Well, hi there, friends!</p><p>Today, a calm Sunday, I decided to spend some time with a project that has been on my mind for a while. Ever since I found out that Brad Fitzpatrick, an engineer I have great respect for, <a href="https://twitter.com/bradfitz/status/1222297949041905664">left Google</a> and joined Tailscale - I have been looking for an opportunity to try the Tailscale product. I couldn&#8217;t carve out time for this until recently, when I needed to setup <a href="https://No-IP.org">No-IP</a> for a computer at home so I can access it while away. The pain of reconfiguring home routers, installing the dynamic IP update client (<a href="https://www.noip.com/download?page=mac">DUC</a>), and exposing a machine to the Internet wilderness seemed like a significant time commitment and a security risk. Then I remembered something I had used 15 years ago - a great product called <a href="https://en.wikipedia.org/wiki/LogMeIn_Hamachi">Hamachi</a>. I was pleasantly surprised to discover that Hamachi is still around and has a great domain - VPN.net. Then I remembered reading about Tailscale and thinking how similar it is to Hamachi. Time to learn about Tailscale and read its code!</p><p>No surprise - Brad and team have done an incredible job. Tailscale is a breeze to install on macOS, OpenBSD, and Windows. The product solved my remote access problem immediately, without exposing my machines to the Internet.</p><p>Tailscale is built on top of a new VPN software, called <a href="https://www.wireguard.com/protocol/">Wireguard</a>, which was created by <a href="https://www.zx2c4.com/">Jason Donenfeld</a>. I&#8217;ve heard great things about it. I decided to dedicate this Sunday afternoon to casually perusing through the source code of the Go implementation of <a href="https://git.zx2c4.com/wireguard-go/tree/main.go">Wireguard</a>.</p><p>There is a great amount of complexity in the Wireguard repository inherent to encryption, networking, and systems software. This despite the fact that Wireguard prides itself on being simple as compared to incumbent VPN tech.</p><p>For this post we'll look at the beautiful simplicity of the entry point into wireguard-go. The <a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n56">main.go</a> file of the <a href="https://git.zx2c4.com/wireguard-go/about/">wireguard-go project</a> is an excellent primer on writing minimal Go CLIs and also daemons.</p><p>I've used Go for many a year and yet I found some interesting new tricks I had not run into before. The very first line, for instance, is something I had not seen in the past:</p><pre><code>// +build !windows</code></pre><p>This is self-explanatory, but nevertheless - a good thing to have in one&#8217;s toolbox when dealing with multi-OS projects. Adding this <a href="https://golang.org/pkg/go/build/#hdr-Build_Constraints">build constraint (or build tag)</a> is done when one needs to exclude a file when building on Windows.</p><p>Scrolling through the source code, I found it interesting that the license Jason had chosen for this repo is <a href="https://en.wikipedia.org/wiki/MIT_License">MIT</a>, which differs from the <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html">GPLv2 license</a> used for the Linux kernel implementation of Wireguard. Later browsing <a href="https://www.wireguard.com/">wireguard.com</a> I noticed <a href="https://www.wireguard.com/#license">the License section</a>, where the multi-license use is explained: "The kernel components are released under the GPLv2, as is the Linux kernel itself. Other projects are licensed[...] depending on context."</p><p>Continuing my linear walk through the Go code, I found the <em><a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n39">warning</a></em><a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n39"> function</a> really interesting. It is such great news to know that <a href="https://lwn.net/Articles/816309/">Jason added wireguard to the 5.6 version of the Linux kernel</a>. The <em>warning</em> function shares w/ the Linux user the fact that Wireguard may already be in their kernel. You&#8217;ll notice, as of this writing, there is no check for the version of the Linux kernel. The message may be inaccurate for folks running older kernels. I have not needed to check the OS within a Go binary, and so the <em><a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n40">"runtime.GOOS != "linux"</a></em> statement (runtime.GOOS in particular) is something new I learned today and will use in a project I am working on.</p><p>I love the attention to detail and <a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n44">the usage of unicode characters (&#8220;&#9484;&#8221; (U+250C) for instance) around the message</a>. The border definitely makes the message stand out and brought nostalgic memories of <a href="https://en.wikipedia.org/wiki/Ncurses">the ncurses library</a> - a topic for a future post.</p><p>Another interesting choice is the exclusive use of the <em><a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n57">os.Args</a></em> to parse the CLI arguments. In Go there is a plethora of libraries and methods to parse command line arguments and flags. The author of wireguard-go chose the minimal rudimentary option available - a choice I appreciate.</p><p>I find <a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n180">the block related to daemonization of the process</a> also interesting and worth looking into to learn from. We'll save the deeper analysis of this block for another time, but it it is definitely worth examining the use of <em>os.Executable()</em>, <em>os.StartProcess()</em>, and <em>process.Release()</em>.</p><p>If you haven't been exposed to handling operating system signals with Go, the <em><a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n231">term</a></em> channel would be interesting to learn from:</p><pre><code>term := make(chan os.Signal, 1)</code></pre><p>Once the channel is initialized, wireguard-go registers with the OS, which will send SIGTERM and interrupt (Control-C) to this channel. A <a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n257">few lines below</a> wireguard-go will wait and block on either one of these, or for a device release before it cleans up and shuts down:</p><pre><code>select {
case &lt;-term:
case &lt;-errs:
case &lt;-device.Wait():
}</code></pre><p></p><p>The minimalistic approach adopted in creating the wireguard-go CLI and daemon is a great primer and I encourage you to bookmark this repository and leverage it when creating simple Go CLI tools or daemons. One area of improvement, in my opinion, would be to further <a href="https://git.zx2c4.com/wireguard-go/tree/main.go#n180">carve out code</a> out of <em>main()</em> and into smaller functions. This would make the code testable and <em>main()</em> smaller and easier to comprehend. I encourage you, and will attempt this myself, to submit patches to the repository with this and any other improvements possible.</p><p>See you next time!</p>]]></content:encoded></item><item><title><![CDATA[10 PRINT]]></title><description><![CDATA[we learn to read before we write]]></description><link>https://www.codereading.org/p/10-print</link><guid isPermaLink="false">https://www.codereading.org/p/10-print</guid><dc:creator><![CDATA[Delyan Raychev]]></dc:creator><pubDate>Sat, 02 Jan 2021 00:09:49 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Z99J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Well, Hi there!<br><br>My name is Delyan Raychev, today is January 1st, 2021 and it feels like the right time to start something new.</p><p>One winter day in the late 1980s my parents dropped me (a kindergartener) off at my grandparents&#8217; house in southern <a href="https://en.wikipedia.org/wiki/Bulgaria">Bulgaria</a>. Left me and one of these:<br> </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LeRw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LeRw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 424w, https://substackcdn.com/image/fetch/$s_!LeRw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 848w, https://substackcdn.com/image/fetch/$s_!LeRw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 1272w, https://substackcdn.com/image/fetch/$s_!LeRw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LeRw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png" width="298" height="280" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:280,&quot;width&quot;:298,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:98364,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LeRw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 424w, https://substackcdn.com/image/fetch/$s_!LeRw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 848w, https://substackcdn.com/image/fetch/$s_!LeRw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 1272w, https://substackcdn.com/image/fetch/$s_!LeRw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb489683e-e74d-467a-bc9d-f7761f272f6c_298x280.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><a href="http://www.pravetz.bg/history">Pravetz 8</a></figcaption></figure></div><p>This plastic <a href="https://en.wikipedia.org/wiki/Pravetz_computers#:~:text=From%20Wikipedia%2C%20the%20free%20encyclopedia%20Pravetz%20%28%D0%9F%D1%80%D0%B0%D0%B2%D0%B5%D1%86%20in,in%20Stara%20Zagora%2C%20Plovdiv%2C%20and%20other%20Bulgarian%20cities.">Pravetz box</a> came with a book on <a href="https://www.c64-wiki.com/wiki/BASIC">BASIC</a> - full of short snippets of sample code. I had fun trying to type out various short <a href="https://www.c64-wiki.com/wiki/LIST">LIST</a>ings from the book.</p><p>The best part of the Pravetz computer was - the first thing you saw when you turned the box on - the name of the machine (&#1055;&#1056;&#1040;&#1042;&#1045;&#1062;) and a cursor:<strong> ]</strong>&#9608;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!M4fO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!M4fO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 424w, https://substackcdn.com/image/fetch/$s_!M4fO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 848w, https://substackcdn.com/image/fetch/$s_!M4fO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 1272w, https://substackcdn.com/image/fetch/$s_!M4fO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!M4fO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png" width="1032" height="244" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/ef818a48-1867-427e-a345-8c53703446c2_1032x244.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:244,&quot;width&quot;:1032,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:174917,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!M4fO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 424w, https://substackcdn.com/image/fetch/$s_!M4fO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 848w, https://substackcdn.com/image/fetch/$s_!M4fO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 1272w, https://substackcdn.com/image/fetch/$s_!M4fO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fef818a48-1867-427e-a345-8c53703446c2_1032x244.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption">(source <a href="https://bulgarianhistory.org/wp-content/uploads/2017/12/%D0%BF%D1%80%D0%B0%D0%B2%D0%B5%D1%8682.jpg">BulgarianHistory.org</a>)</figcaption></figure></div><p>The blinking green box invited you to type out your first BASIC command.</p><div><hr></div><p>Jumping from the late 1980&#8217;s to July 2020 when I saw <a href="https://twitter.com/salcollora/status/1287188052763217920">a tweet from Sal Collora</a>, who had a freshly refurbished a working Commodore 64&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z99J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z99J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Z99J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Z99J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Z99J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z99J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg" width="456" height="224.86813186813185" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/b4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:718,&quot;width&quot;:1456,&quot;resizeWidth&quot;:456,&quot;bytes&quot;:560181,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Z99J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Z99J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Z99J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Z99J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fb4e185e8-b5cf-4e58-897f-0460ddd462c3_2048x1010.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I got an opportunity to rekindle that old feeling of typing out my first line of source code - so I embraced it. My Commodore 64 arrived, I plugged it in, turned it on and there it was - the BASIC prompt again.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N7ws!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N7ws!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 424w, https://substackcdn.com/image/fetch/$s_!N7ws!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 848w, https://substackcdn.com/image/fetch/$s_!N7ws!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 1272w, https://substackcdn.com/image/fetch/$s_!N7ws!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N7ws!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png" width="502" height="163" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/c23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:163,&quot;width&quot;:502,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:62326,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!N7ws!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 424w, https://substackcdn.com/image/fetch/$s_!N7ws!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 848w, https://substackcdn.com/image/fetch/$s_!N7ws!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 1272w, https://substackcdn.com/image/fetch/$s_!N7ws!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fc23a9477-99f5-4641-ba55-e89ecef3db56_502x163.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">(source: <a href="https://www.c64-wiki.com/images/c/c9/Einschaltmeldung_C64.jpg">c64-wiki.com</a>)</figcaption></figure></div><p>It is so incredible - flip the switch and you are dropped in a BASIC world. All you have at your disposal are <a href="https://www.c64-wiki.com/wiki/C64-Commands#BASIC-Keywords_Overview">71 keywords</a>. It seem like a tiny and suffocating space and yet it is <strong>a fascinating world of endless exploration</strong>. Here is one line of code, my favorite, to prove this with an example:</p><p></p><pre><code>10 PRINT CHR$(205.5+RND(1)); : GOTO 10</code></pre><p></p><p>In the 1980s this extremely concise BASIC program appeared in so many <strong>printed</strong> sources - it became a cultural phenomenon. <a href="http://nickm.com/">Nick Montfort</a> and colleagues wrote <a href="https://10print.org/">an incredible book on the topic</a>.</p><p>While I do aspire to analyze word by word every snippet of code I post here, and I intend to do this weekly, the <em>10 PRINT</em> has already been elaborately studied in <a href="https://10print.org/10_PRINT_121114.pdf">the 10 PRINT book (PDF)</a>.</p><p>Very peculiar (to me) is the <strong>205.5</strong> number in the code. This number plus a random float between 0 and 1 results in printing either <a href="https://en.wikipedia.org/wiki/PETSCII">PETSCII</a> character 205 (\) or 206 (/):</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Eh0_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Eh0_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 424w, https://substackcdn.com/image/fetch/$s_!Eh0_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 848w, https://substackcdn.com/image/fetch/$s_!Eh0_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 1272w, https://substackcdn.com/image/fetch/$s_!Eh0_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Eh0_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png" width="355" height="178" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:178,&quot;width&quot;:355,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17130,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Eh0_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 424w, https://substackcdn.com/image/fetch/$s_!Eh0_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 848w, https://substackcdn.com/image/fetch/$s_!Eh0_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 1272w, https://substackcdn.com/image/fetch/$s_!Eh0_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F7c72ee66-f39a-447b-ab20-393d96cd9b3b_355x178.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The maze with the 205.5 and a random sub-1 float would look like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p201!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p201!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 424w, https://substackcdn.com/image/fetch/$s_!p201!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 848w, https://substackcdn.com/image/fetch/$s_!p201!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 1272w, https://substackcdn.com/image/fetch/$s_!p201!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p201!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png" width="929" height="539" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/dd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:539,&quot;width&quot;:929,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:195747,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p201!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 424w, https://substackcdn.com/image/fetch/$s_!p201!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 848w, https://substackcdn.com/image/fetch/$s_!p201!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 1272w, https://substackcdn.com/image/fetch/$s_!p201!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdd74e2bb-7713-47e2-af5a-266c783323f1_929x539.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>But my second-grade daughter wanted to see what happens if the numbers change, so she tried tweaking the 205.5 to all sorts of other numbers. Here is the same program with 215.5 instead:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4TGG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4TGG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 424w, https://substackcdn.com/image/fetch/$s_!4TGG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 848w, https://substackcdn.com/image/fetch/$s_!4TGG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 1272w, https://substackcdn.com/image/fetch/$s_!4TGG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4TGG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png" width="927" height="537" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/dcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:537,&quot;width&quot;:927,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:106770,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4TGG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 424w, https://substackcdn.com/image/fetch/$s_!4TGG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 848w, https://substackcdn.com/image/fetch/$s_!4TGG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 1272w, https://substackcdn.com/image/fetch/$s_!4TGG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fdcba8ddf-fda2-46f4-8699-3e170f0ca84d_927x537.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The instant feedback from changing a number and then <a href="https://www.c64-wiki.com/wiki/RUN_(BASIC)">RUN</a>ning the program gave my daughter hours of entertainment, exploring <a href="https://www.c64-wiki.com/wiki/Character_set">Commodore 64 character sets</a>. This reminded me of the great times I had exploring all the things the <a href="http://www.pravetz.bg/history">Pravetz 8c</a> can do.</p><div><hr></div><p><a href="https://www.codereading.org/">This is a blog</a> about reading code and we did just that today. This is one simple line of BASIC code but it sparked the imagination of many kids and adults who in turn created great software. This great software is what we will examine scrutinously in this forum here!</p><p><br>Tune in and <a href="http://www.codereading.org/subscribe">subscribe</a> for more of our code reading adventures weekly!</p>]]></content:encoded></item></channel></rss>