<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Nabeel Valley</title><description>Software develpment, Photography and Design</description><link>https://nabeelvalley.co.za/</link><item><title>HTML in WebGPU Shaders in Canvas</title><link>https://nabeelvalley.co.za/blog/2026/12-04/html-in-canvas/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/12-04/html-in-canvas/</guid><description>A little experimet with Web GPU Shaders with HTML</description><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Example from &apos;./Example.astro&apos;&lt;/p&gt;
&lt;p&gt;I made some minor updates to my &lt;a href=&quot;/blog/2025/09-11/shader-web-component&quot;&gt;Shader Web Component&lt;/a&gt; to add support for the &lt;a href=&quot;https://github.com/WICG/html-in-canvas&quot;&gt;proposed HTML-in-Canvas API&lt;/a&gt;. So you can see the following in a Chromium based browser with the flag &lt;code&gt;chrome://flags/#canvas-draw-element&lt;/code&gt; enabled&lt;/p&gt;
&lt;p&gt;&amp;lt;Example /&amp;gt;&lt;/p&gt;
&lt;h2&gt;How Does It Work?&lt;/h2&gt;
&lt;p&gt;The HTML in the above example is rendered within the canvas and is - if/when supported - exposed to the accessibility tree&lt;/p&gt;
&lt;p&gt;As per the documentation, this makes use of the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;layoutsubtree&lt;/code&gt; attribute on the &lt;code&gt;canvas&lt;/code&gt; element to tell the browser that we want to render the contents&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;copyElementImageToTexture&lt;/code&gt; function on the WebGPU &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/GPUDevice/queue&quot;&gt;&lt;code&gt;GPUDevice.queue&lt;/code&gt;&lt;/a&gt; to copy the texture&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;canvas.onpaint&lt;/code&gt; handler to run the &lt;code&gt;copyElementImageToTexture&lt;/code&gt; function with the contents&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Usability Issues&lt;/h2&gt;
&lt;p&gt;The proposal is still just that - a proposal - so it has some issues and is still very experimental.&lt;/p&gt;
&lt;p&gt;The above example should show the inner content if supported. I&apos;ve noticed that there are some quirks around how the content focus, etc. work since the click targets aren&apos;t aligned as expected, etc. which creates some weird usability issues&lt;/p&gt;
&lt;p&gt;Some challenges I see here are around keeping positions in sync so that interactive elements remain correctly interactive and that basic parts of the web continue to work as users expect&lt;/p&gt;
&lt;p&gt;The example above originally suffered from the fact that the size of the canvas content doesn&apos;t match the canvas and so things are not quite in the right place. &lt;a href=&quot;https://mattrothenberg.com/&quot;&gt;Matt Rothenberg&lt;/a&gt; also points this out in their &lt;a href=&quot;https://mattrothenberg.com/notes/html-in-canvas/&quot;&gt;HTML in Canvas&lt;/a&gt; post and while it&apos;s definitely doable it does require a fair amount of wrangling to make work nicely&lt;/p&gt;
&lt;p&gt;I&apos;ve solved the resizing issue in the above example using CSS but it&apos;s also possible to do using the &lt;code&gt;drawElementImage&lt;/code&gt; function as per the API to do the necessary alignment&lt;/p&gt;
&lt;h2&gt;Technical Challenges&lt;/h2&gt;
&lt;p&gt;I also ran into some VERY annoying bugs (or is this just how WebGPU is meant to work - I don&apos;t know) along the way, the main one was to do with figuring out how to use the GPU bindings&lt;/p&gt;
&lt;p&gt;In particular, I saw the following error about a million times:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;In entries[0], binding index 0 not present in the bind group layout.
Expected layout: []
 - While validating [BindGroupDescriptor &amp;quot;&amp;quot;textures&amp;quot;&amp;quot;] against [BindGroupLayout (unlabeled)]
 - While calling [Device].CreateBindGroup([BindGroupDescriptor &amp;quot;&amp;quot;textures&amp;quot;&amp;quot;]).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was because the bindings in my shader related to the textures were not used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgsl&quot;&gt;// unused
@group(0) @binding(0) var htmlSampler: sampler;
@group(0) @binding(1) var htmlTexture: texture_2d&amp;lt;f32&amp;gt;;

// used
@group(1) @binding(0) var&amp;lt;uniform&amp;gt; uTime: f32;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The respective texture and sampler were not used, and so the &lt;code&gt;auto&lt;/code&gt; layout for the shader doesn&apos;t seem to detect that they exist. I find this very confusing - the error here could be better&lt;/p&gt;
&lt;p&gt;There&apos;s a good example on explicitly defining the layouts on &lt;a href=&quot;https://webgpufundamentals.org/webgpu/lessons/webgpu-bind-group-layouts.html&quot;&gt;this WebGPU Bind Group Layouts article&lt;/a&gt; and &lt;a href=&quot;https://webgpufundamentals.org/webgpu/lessons/resources/wgsl-offset-computer.html&quot;&gt;a handy calculator for providing the bind group layout config&lt;/a&gt;. This ended up eventually being how I realized the bind group was being left out since for some reason the entries in &lt;code&gt;@group(0)&lt;/code&gt; were being left out even though their example - when updated to use &amp;quot;my&amp;quot; bindings for the texture and sampler - worked just fine.&lt;/p&gt;
&lt;p&gt;Anyways, ensuring that the sampler and texture are used meant that everything worked fine again. So conditionally adding the bindgroup works which adds some ugliness to my shader rendering code but I think it&apos;s fine for what it makes possible&lt;/p&gt;
&lt;p&gt;The snippet for the above example can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;site-shader-canvas&amp;gt;
  &amp;lt;canvas width=&amp;quot;1000&amp;quot; height=&amp;quot;1000&amp;quot; style=&amp;quot;width: 100%&amp;quot; layoutsubtree&amp;gt;
    &amp;lt;div class=&amp;quot;html-in-canvas&amp;quot; style=&amp;quot;width: 100%; height: 100%; color: green; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;&amp;quot;&amp;gt;
      &amp;lt;h2 style=&amp;quot;margin: 0;&amp;quot;&amp;gt;Hello from HTML!&amp;lt;/h2&amp;gt;      

      &amp;lt;label for=&amp;quot;input-in-canvas&amp;quot;&amp;gt;Input in canvas&amp;lt;/label&amp;gt;
      &amp;lt;input style=&amp;quot;display: block;&amp;quot; id=&amp;quot;input-in-canvas&amp;quot; /&amp;gt;      
    &amp;lt;/div&amp;gt;
  &amp;lt;/canvas&amp;gt;

  &amp;lt;script type=&amp;quot;text/wgsl&amp;quot;&amp;gt;
    struct VertexOutput {
      @builtin(position) position: vec4f,
      @location(0) texcoord: vec2f,
    };

    @vertex fn vs(
      @builtin(vertex_index) vertexIndex : u32
    ) -&amp;gt; VertexOutput {
      const pos = array(
        vec2( 1.0,  1.0),
        vec2( 1.0, -1.0),
        vec2(-1.0, -1.0),
        vec2( 1.0,  1.0),
        vec2(-1.0, -1.0),
        vec2(-1.0,  1.0),
      );

      var vsOutput: VertexOutput;
  
      let xy = pos[vertexIndex];
      vsOutput.texcoord = pos[vertexIndex] * vec2f(0.5, 0.5) + vec2f(0.5);
      vsOutput.position = vec4f(pos[vertexIndex], 0, 1);

      return vsOutput;
    }

    @group(0) @binding(0) var htmlSampler: sampler;
    @group(0) @binding(1) var htmlTexture: texture_2d&amp;lt;f32&amp;gt;;

    @group(1) @binding(0) var&amp;lt;uniform&amp;gt; uTime: f32;

    fn flipSample(fsInput: VertexOutput) -&amp;gt; vec4f {
      // the texture must be flipped since the shader coord system is the
      // opposite of the HTML one
      var pos = vec2f(fsInput.texcoord.x, 1 - fsInput.texcoord.y);
      return textureSample(htmlTexture, htmlSampler, pos);
    }
    
    @fragment fn fs(fsInput: VertexOutput) -&amp;gt; @location(0) vec4f {
      var red = abs(sin(uTime/10.0)) * fsInput.texcoord.x;
      var blue = abs(cos(uTime/5.0)) * fsInput.texcoord.y;

      return vec4f(red, 0.0, blue, 1.0) + flipSample(fsInput);
    }
  &amp;lt;/script&amp;gt;
&amp;lt;/site-shader-canvas&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also take a look at the &lt;a href=&quot;/web-components/shader-canvas.js&quot;&gt;source of the web component&lt;/a&gt; and respective &lt;a href=&quot;/web-components/shader.js&quot;&gt;shader renderer&lt;/a&gt; if you&apos;re interested&lt;/p&gt;
</content:encoded></item><item><title>Bad Bots</title><link>https://nabeelvalley.co.za/blog/2026/03-04/bad-bots/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/03-04/bad-bots/</guid><description>Some light reading on blocking AI crawlers</description><pubDate>Fri, 03 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Shh ... you&apos;ve found an &lt;a href=&quot;https://daverupert.com/rss-club/&quot;&gt;RSS Club&lt;/a&gt; post. I&apos;ll be using this to post small ideas or share things from around the web that I find interesting but don&apos;t intend to write an entire post about&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have a website that kept randomly going down every few weeks - turned out that I hadn&apos;t enabled a healthcheck so the auto-restart didn&apos;t know to that it had to restart. So after some annoyance I added a basic check and I think it&apos;s fine now - probably ...&lt;/p&gt;
&lt;p&gt;Anyways, not the point - I looked into why it kept going down and seemed like it would randomly get thousands of simultaneous requests from bots and I decided that I don&apos;t want that anymore?&lt;/p&gt;
&lt;p&gt;I remembered reading a post a while back about blocking AI crawlers which upon some searching turned out to be by &lt;a href=&quot;https://matthiasott.com&quot;&gt;Matthais Ott&lt;/a&gt;. And so I did some reading and here&apos;s a list of some related content on how to stop the LLMs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://matthiasott.com/articles/webspace-invaders&quot;&gt;Webspace Invaders - Matthias Ott&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://heydonworks.com/article/poisoning-well/&quot;&gt;Poisoning Well - Heydon Works&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rknight.me/blog/blocking-bots-with-nginx/&quot;&gt;Blocking Bots - Robb Knight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.coryd.dev/posts/2024/go-ahead-and-block-ai-web-crawlers&quot;&gt;Go ahead and block AI web crawlers - Cory Dransfeldt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://drewdevault.com/2025/03/17/2025-03-17-Stop-externalizing-your-costs-on-me.html&quot;&gt;Please stop externalizing your costs directly into my face - Drew DeVault&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I particularly resonate with the last paragraph of the last link in that list:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;If you personally work on developing LLMs et al, know this: I will never work with you again, and I will remember which side you picked when the bubble bursts.&amp;quot; - Please stop externalizing your costs directly into my face - Drew DeVault&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;None of these are Traefik so I&apos;ll probably put together a bit of an implementation once I settle on something and put in in &lt;a href=&quot;/docs/random/traefik&quot;&gt;my Traefik notes&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Symbols on the Ground</title><link>https://nabeelvalley.co.za/blog/2026/31-03/mural-on-the-ground/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/31-03/mural-on-the-ground/</guid><pubDate>Tue, 31 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Gallery from &apos;../../../../components/Gallery.astro&apos;&lt;/p&gt;
&lt;p&gt;I came across some random murals on the along the path in Utrecht today. A while later when walking by I stopped to take some pictures of them - I saw 15. But according to &lt;a href=&quot;https://mozaiekmonumenten.nl/portfolio/exclusief-in-opdracht/&quot;&gt;Mozaiek Monumenten&lt;/a&gt; there are 17 - I guess I the remaining two were in the construction site just past the 15th&lt;/p&gt;
&lt;p&gt;They&apos;re a reference to the &lt;em&gt;Sustainable Development Goals&lt;/em&gt;. The reference from Mozaiek Monmumenten can be seen below with the descriptions of each of them:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2026/31-03/sdg-legend.jpeg&quot; alt=&quot;Sustainable Development Goals Legend&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can see the pictures I took of them below:&lt;/p&gt;
&lt;p&gt;&amp;lt;Gallery reverse caption path=&amp;quot;blog/2026-03-31 - symbols on the ground&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;The two that I don&apos;t have are:&lt;/p&gt;
&lt;ol start=&quot;16&quot;&gt;
&lt;li&gt;Freedom, Safety, and Strong Public Services&lt;/li&gt;
&lt;li&gt;Partnership for the Goals&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Okay that&apos;s it, I should walk around with my eyes open more often&lt;/p&gt;
</content:encoded></item><item><title>Photos from the Nederlands Fotomuseum</title><link>https://nabeelvalley.co.za/blog/2026/28-03/nederlands-fotomuseum/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/28-03/nederlands-fotomuseum/</guid><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Gallery from &apos;../../../../components/Gallery.astro&apos;&lt;/p&gt;
&lt;p&gt;We went to the &lt;a href=&quot;https://nederlandsfotomuseum.nl&quot;&gt;Nederlands Fotomuseum&lt;/a&gt; which was really great. I resisted the urge to take any pictures in the museum but when I got to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cyanotype&quot;&gt;Cyanotype&lt;/a&gt; exhibit I couldn&apos;t resist. You can see some of the pictures below&lt;/p&gt;
&lt;p&gt;Also, they had this really cool digital gallery thingy so here&apos;s a video of that!&lt;/p&gt;
&lt;p&gt;&amp;lt;video controls muted alt=&amp;quot;2026-03-28 - Nederlands Fotomuseum Gallery Lens Demo&amp;quot; width=&amp;quot;100%&amp;quot;&amp;gt;
&amp;lt;source src=&amp;quot;/content/blog/2026/28-03/2026-03-28 - Nederlands Fotomuseum Gallery Lens Demo.MOV&amp;quot; /&amp;gt;
&amp;lt;/video&amp;gt;&lt;/p&gt;
&lt;p&gt;I also saw this silly bus which turned out to be one of &lt;a href=&quot;https://nl.wikipedia.org/wiki/Splashtours&quot;&gt;these water bus things&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2026/28-03/2023-03-28%20-%20Water%20bus.JPG&quot; alt=&quot;Water bus&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then on the train ride home I watched about 8 people look at a seat, have a weird facial expression and walk away, not sitting on the chair&lt;/p&gt;
&lt;p&gt;Zahrah pointed out that there was a sticky note on the chair saying it was wet (I couldn’t see the note)&lt;/p&gt;
&lt;p&gt;At some point an old man came along, looked perplexingly at the note, and decided to touch it and was like - this is not wet?&lt;/p&gt;
&lt;p&gt;The man across said, yeah it doesn&apos;t look wet but I don’t know&lt;/p&gt;
&lt;p&gt;The old man sat on the seat next to the labeled-as-wet one&lt;/p&gt;
&lt;p&gt;People continued to walk past and look at the sticky note and walk away&lt;/p&gt;
&lt;p&gt;The old man moved the sticky note away, this was either to state that the seat is in fact not wet - or as an effort to prank someone by making them sit on a wet seat&lt;/p&gt;
&lt;p&gt;We do not know&lt;/p&gt;
&lt;p&gt;Zahrah had some comments about how everyone was appealing to the authority of the sticky note and how much that says about the fragility of the social contract&lt;/p&gt;
&lt;p&gt;IDK I was just sitting and laughing every time anyone walked past because it was funny&lt;/p&gt;
&lt;p&gt;Anyways ... here are the pictures then!&lt;/p&gt;
&lt;p&gt;&amp;lt;Gallery caption path=&amp;quot;blog/2026-03-28 - nederlands fotomuseum&amp;quot; /&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Quick and Dirty Object Access in Go</title><link>https://nabeelvalley.co.za/blog/2026/27-03/deep-dynamic-access/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/27-03/deep-dynamic-access/</guid><pubDate>Fri, 27 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Assumed audience: Developers/technical people who use Go as a programming language&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This probably isn&apos;t too difficult to write but it&apos;s recursive and I had fun putting it together so here it is&lt;/p&gt;
&lt;p&gt;Basically, I was trying to access a deeply nested object that was parsed from &lt;a href=&quot;https://pkg.go.dev/github.com/BurntSushi/toml&quot;&gt;BurntSushi/toml&lt;/a&gt; in some generic fashion and it was getting annoying to constantly cast things and do the necessary checks at every level so I made two utilities that can access nested data a bit more conveniently&lt;/p&gt;
&lt;p&gt;First off, here&apos;s a helper type to sprinkle around:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type dynamic = map[string]any
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, here&apos;s the version that will panic if it hits something it&apos;s not expecting:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func unsafeIndex(data dynamic, path ...string) any {
	if len(path) == 0 {
		return data
	}

	inner := data[path[0]]
	if len(path) == 1 {
		return inner
	}

	return unsafeIndex(inner.(dynamic), path[1:]...)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the version that returns the appropriate errors along the way:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func safeIndex(data dynamic, path ...string) (any, error) {
	if len(path) == 0 {
		return data, nil
	}

	inner, ok := data[path[0]]
	if !ok {
		return data, fmt.Errorf(&amp;quot;Error indexing path %v for %v&amp;quot;, path, data)
	}

	if len(path) == 1 {
		return inner, nil
	}

	dyn, ok := inner.(dynamic)
	if !ok {
		return dyn, fmt.Errorf(&amp;quot;Error indexing into inner struct %v for %v&amp;quot;, path, inner)
	}

	return safeIndex(dyn, path[1:]...)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using them is also fairly normal, as seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// whatever you&apos;re doing to decode the data. e.g. JSON/TOML parser
var output dynamic
decodeData(FILE_CONTENT, &amp;amp;output)

dynamicSources, err := safeIndex(output, &amp;quot;some&amp;quot;, &amp;quot;deeply&amp;quot;, &amp;quot;nested&amp;quot;, &amp;quot;property&amp;quot;)
if err != nil {
    panic(err)
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Async TUIs using Bubble Tea</title><link>https://nabeelvalley.co.za/blog/2026/26-03/bubbletea-commands/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/26-03/bubbletea-commands/</guid><description>Using Bubble Tea commands in Go for snappy TUIs</description><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Assumed audience: UI developers, people who program in Go, or anyone just generally interested in making computers to things using code&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There was a little bug I ran into a while back but hadn&apos;t been important enough for me to fix until yesterday when it started to slow me down&lt;/p&gt;
&lt;p&gt;On &lt;a href=&quot;https://github.com/sftsrv/tri&quot;&gt;Tri&lt;/a&gt; - a TUI app I built that is something like if &lt;code&gt;tree&lt;/code&gt; was searchable and had previews like&lt;code&gt;fzf&lt;/code&gt; - I (knowingly) didn&apos;t implement async tasks upfront. At the time I was mostly focused on getting the implementation to a good level of UX and free of bugs. As such, there was a clear slowness when navigating the UI while running slow tasks, such as a &lt;code&gt;git diff&lt;/code&gt; in a large repository&lt;/p&gt;
&lt;p&gt;I sat down yesterday to make the app run previews run in the background - this turned out to be really easy and I thought I&apos;d write about it just to mention why that was the case&lt;/p&gt;
&lt;p&gt;Most TUIs I write in Go use the excellent suite of libraries by &lt;a href=&quot;https://charm.sh/&quot;&gt;Charm&lt;/a&gt; - and in this particular case, the &lt;a href=&quot;https://github.com/charmbracelet/bubbletea&quot;&gt;Bubble Tea TUI framework&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Elm Architecture&lt;/h2&gt;
&lt;p&gt;The Bubble Tea framework is based on the &lt;a href=&quot;https://guide.elm-lang.org/architecture/&quot;&gt;Elm Architecture&lt;/a&gt; which is a functional style pattern for building UIs. I think understanding the Elm architecture is a generally useful and the documentation is worth a read for developers building any kind of user interface (even if it&apos;s not in Elm)&lt;/p&gt;
&lt;p&gt;The core idea is this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All UI flows from a Model&lt;/li&gt;
&lt;li&gt;Messages are used to perform Updates on the Model&lt;/li&gt;
&lt;li&gt;A View converts the Model into UI&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;This is also known as the MVU pattern (Model -&amp;gt; View -&amp;gt; Update)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using this pattern, we can build a simple implementation of an app that has two bits of independent UI - a counter that increments when the user presses &lt;code&gt;space&lt;/code&gt;, and a task runner that runs some heavy tasks triggered by pressing &lt;code&gt;enter&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;A Sad Implementation&lt;/h2&gt;
&lt;p&gt;A naive implementation of this using Bubble Tea has the following bits that matter for discussion:&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;Update&lt;/code&gt; function, when we press &lt;code&gt;space&lt;/code&gt; we increment the counter, and when we press &lt;code&gt;enter&lt;/code&gt; we run some tasks:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {

	case tea.KeyPressMsg:
		switch msg.String() {
		case &amp;quot;ctrl+c&amp;quot;, &amp;quot;q&amp;quot;:
			return m, tea.Quit

		case &amp;quot;space&amp;quot;:
			m.counter++
			return m, nil

		case &amp;quot;enter&amp;quot;:
			m.running = true
			m.tasks = doTasks()
			return m, nil
		}
	}

	return m, nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method then updates the model and returns the updated model - for context, the &lt;code&gt;doTasks&lt;/code&gt; function looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func doHeavyWork() {
	t := rand.IntN(5)

  // irl we&apos;d do something other than sleep
	time.Sleep(time.Duration(t) * time.Second)
}

func doTasks() []task {
	var tasks []task

	for i := range 10 {
		doHeavyWork()
		tasks = append(tasks, task{i, true})
	}

	return tasks
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see this running below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2026/26-03/bubbletea-commands-v1.gif&quot; alt=&quot;V1 implementation in action&quot;&gt;&lt;/p&gt;
&lt;p&gt;The problem with the above implementation is twofold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bad performance - The UI is blocked while the tasks are running, so the counter doesn&apos;t update until after the tasks are run&lt;/li&gt;
&lt;li&gt;Sad UX - There isn&apos;t a way to update an in-progress task, would be nice to not have to wait&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;You can see the full V1 implementation if you&apos;d like&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package v1

import (
	&amp;quot;fmt&amp;quot;
	&amp;quot;os&amp;quot;
	&amp;quot;time&amp;quot;

	tea &amp;quot;charm.land/bubbletea/v2&amp;quot;
	rand &amp;quot;math/rand/v2&amp;quot;
)

type task struct {
	index int
	done  bool
}

type model struct {
	counter int
	running bool
	tasks   []task
}

func (t task) string() string {
	status := &amp;quot;busy&amp;quot;
	if t.done {
		status = &amp;quot;done&amp;quot;
	}

	return fmt.Sprintf(&amp;quot;Task %d [%s]&amp;quot;, t.index, status)
}

func sleepRandomly() {
	t := rand.IntN(5)
	time.Sleep(time.Duration(t) * time.Second)
}

func doTasks() []task {
	var tasks []task

	for i := range 10 {
		sleepRandomly()
		tasks = append(tasks, task{i, true})
	}

	return tasks
}

func initialModel() model {
	return model{
		counter: 0,
		running: false,
		tasks:   []task{},
	}
}

func (m model) Init() tea.Cmd {
	return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {

	case tea.KeyPressMsg:
		switch msg.String() {
		case &amp;quot;ctrl+c&amp;quot;, &amp;quot;q&amp;quot;:
			return m, tea.Quit

		case &amp;quot;space&amp;quot;:
			m.counter++
			return m, nil

		case &amp;quot;enter&amp;quot;:
			m.running = true
			m.tasks = doTasks()
			return m, nil
		}
	}

	return m, nil
}

func (m model) View() tea.View {
	count := fmt.Sprintf(&amp;quot;count = %d&amp;quot;, m.counter)
	if !m.running {
		return tea.NewView(count + &amp;quot;\nPress space to increment counter\nPress enter to start tasks&amp;quot;)
	}

	tasks := &amp;quot;&amp;quot;
	done := true
	for _, t := range m.tasks {
		if !t.done {
			done = false
		}
		tasks += &amp;quot;\n&amp;quot; + t.string()
	}

	title := &amp;quot;Running Tasks&amp;quot;
	if done {
		title = &amp;quot;All done&amp;quot;
	}

	return tea.NewView(count + &amp;quot;\n&amp;quot; + title + &amp;quot;\n&amp;quot; + tasks)
}

func Run() {
	p := tea.NewProgram(initialModel())
	if _, err := p.Run(); err != nil {
		fmt.Printf(&amp;quot;Alas, there&apos;s been an error: %v&amp;quot;, err)
		os.Exit(1)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;A Happy Implementation&lt;/h2&gt;
&lt;p&gt;The solution that&apos;s provided by Bubble Tea is to move the IO based work into a &lt;a href=&quot;https://charm.land/blog/commands-in-bubbletea/&quot;&gt;Command&lt;/a&gt;. A command is used to make things async and is handled by the framework&lt;/p&gt;
&lt;p&gt;A command looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;// its type is tea.Cmd
var cmd tea.Cmd

// its value is a function that returns tea.Msg
cmd = func () tea.Msg {
  return  SomeMessage{}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So in order to make our work async, we simply need to return a &lt;code&gt;tea.Cmd&lt;/code&gt; in our &lt;code&gt;Update&lt;/code&gt; function instead of actually doing all the work&lt;/p&gt;
&lt;p&gt;Instead of defining a function that does the work, we can define one that returns a &lt;code&gt;tea.Cmd&lt;/code&gt; that will do the work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;type taskDoneMsg struct {
	index int
}

func makeTasks() ([]task, []tea.Cmd) {
	var cmds []tea.Cmd
	var tasks []task

	for i := range 10 {
		tasks = append(tasks, task{i, false})
		cmds = append(cmds, func() tea.Msg {
			doHeavyWork()
			return taskDoneMsg{i}
		})
	}

	return tasks, cmds
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will offload the work and we&apos;ll receive a &lt;code&gt;taskDoneMsg&lt;/code&gt; message when the work is done. This also has a nice side effect - by decoupling the creation of the &lt;code&gt;task&lt;/code&gt; and the actual execution of it, we can now track the status of each task as it completes&lt;/p&gt;
&lt;p&gt;We can do that in the &lt;code&gt;Update&lt;/code&gt; function by handling the &lt;code&gt;taskDoneMsg&lt;/code&gt; message as well as returning the &lt;code&gt;[]tea.Cmds&lt;/code&gt; that comes from the &lt;code&gt;makeTasks&lt;/code&gt; function instead of actually doing the work upfront&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {

  // handle updating the model when the task is done
	case taskDoneMsg:
		m.tasks[msg.index].done = true
    return m, nil

	case tea.KeyPressMsg:
		switch msg.String() {
		case &amp;quot;ctrl+c&amp;quot;, &amp;quot;q&amp;quot;:
			return m, tea.Quit

		case &amp;quot;space&amp;quot;:
			m.counter++
			return m, nil

		case &amp;quot;enter&amp;quot;:
			m.running = true
			tasks, cmds := makeTasks()
			m.tasks = tasks

      // batch the new cmds for bubbletea to handle
			return m, tea.Batch(cmds...)
		}
	}

	return m, nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And with that, we&apos;ve now got a responsive UI that lets the counter work even while the tasks are running as well as makes it possible for us to track task state:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2026/26-03/bubbletea-commands-v2.gif&quot; alt=&quot;V2 implementation in action&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;You can see the full V2 implementation if you&apos;d like&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;package v2

import (
	&amp;quot;fmt&amp;quot;
	&amp;quot;os&amp;quot;
	&amp;quot;time&amp;quot;

	tea &amp;quot;charm.land/bubbletea/v2&amp;quot;
	rand &amp;quot;math/rand/v2&amp;quot;
)

type task struct {
	index int
	done  bool
}

type taskDoneMsg struct {
	index int
}

func (t task) string() string {
	status := &amp;quot;busy&amp;quot;
	if t.done {
		status = &amp;quot;done&amp;quot;
	}

	return fmt.Sprintf(&amp;quot;Task %d [%s]&amp;quot;, t.index, status)
}

func doHeavyWork() {
	t := rand.IntN(5)
	time.Sleep(time.Duration(t) * time.Second)
}

func makeTasks() ([]task, []tea.Cmd) {
	var cmds []tea.Cmd
	var tasks []task

	for i := range 10 {
		tasks = append(tasks, task{i, false})
		cmds = append(cmds, func() tea.Msg {
			doHeavyWork()
			return taskDoneMsg{i}
		})
	}

	return tasks, cmds
}

type model struct {
	counter int
	running bool
	tasks   []task
}

func initialModel() model {
	return model{
		counter: 0,
		running: false,
		tasks:   []task{},
	}
}

func (m model) Init() tea.Cmd {
	return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
	switch msg := msg.(type) {

	case taskDoneMsg:
		m.tasks[msg.index].done = true
		return m, nil

	case tea.KeyPressMsg:
		switch msg.String() {
		case &amp;quot;ctrl+c&amp;quot;, &amp;quot;q&amp;quot;:
			return m, tea.Quit

		case &amp;quot;space&amp;quot;:
			m.counter++
			return m, nil

		case &amp;quot;enter&amp;quot;:
			m.running = true
			tasks, cmds := makeTasks()
			m.tasks = tasks

			return m, tea.Batch(cmds...)
		}
	}

	return m, nil
}

func (m model) View() tea.View {
	count := fmt.Sprintf(&amp;quot;count = %d&amp;quot;, m.counter)
	if !m.running {
		return tea.NewView(count + &amp;quot;\nPress space to increment counter\nPress enter to start tasks&amp;quot;)
	}

	tasks := &amp;quot;&amp;quot;
	done := true
	for _, t := range m.tasks {
		if !t.done {
			done = false
		}
		tasks += &amp;quot;\n&amp;quot; + t.string()
	}

	title := &amp;quot;Running Tasks&amp;quot;
	if done {
		title = &amp;quot;All done&amp;quot;
	}

	return tea.NewView(count + &amp;quot;\n&amp;quot; + title + &amp;quot;\n&amp;quot; + tasks)
}

func Run() {
	p := tea.NewProgram(initialModel())
	if _, err := p.Run(); err != nil {
		fmt.Printf(&amp;quot;Alas, there&apos;s been an error: %v&amp;quot;, err)
		os.Exit(1)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&apos;s it - no Goroutines or channels needed, a pretty good abstraction on the side of the framework - and minimal effort needed from us&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A small aside, I&apos;ve started working on what will probably be a fairly sizeable side project. As such, I&apos;ve gotten absolutely nothing done on that while somehow managing to put together a few blog posts (this one + &lt;a href=&quot;/blog/2026/22-03/mildly-interesting-eid&quot;&gt;another one about eid&lt;/a&gt; + &lt;a href=&quot;/blog/2026/26-03/tri-x-git-tricks&quot;&gt;another one about tri&lt;/a&gt;), update my photo galleries (&lt;a href=&quot;/photography/places/netherlands&quot;&gt;general nl&lt;/a&gt; and &lt;a href=&quot;/photography/places/2026-winter-netherlands&quot;&gt;stuff from last winter&lt;/a&gt;) on my site, and fix a bunch of random things in other random side projects just this week - oh the power of procrastination&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Murder Mystery in Git</title><link>https://nabeelvalley.co.za/blog/2026/26-03/murder-mystery-git-game/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/26-03/murder-mystery-git-game/</guid><description>A dumb idea</description><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Shh ... you&apos;ve found an &lt;a href=&quot;https://daverupert.com/rss-club/&quot;&gt;RSS Club&lt;/a&gt; post. I&apos;ll be using this to post small ideas or share things from around the web that I find interesting but don&apos;t intend to write an entire post about&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I had a dumb idea, what if you could make a game in a git repo. First thought is some kind of text-based murder mystery where you have to follow git tags as evidence in some silly way to find the killer&lt;/p&gt;
&lt;p&gt;Could be funny, someone who&apos;s more creative than me could probably make it work. But yeah free idea, use it if you want&lt;/p&gt;
</content:encoded></item><item><title>Git Tricks with Tri and Difft</title><link>https://nabeelvalley.co.za/blog/2026/26-03/tri-x-git-tricks/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/26-03/tri-x-git-tricks/</guid><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Assumed audience: Developers/technical people who use git and/or enjoy terminal UIs (TUIs)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So I finally got &lt;a href=&quot;https://github.com/sftsrv/tri&quot;&gt;&lt;code&gt;tri&lt;/code&gt;&lt;/a&gt; running super fast which &lt;a href=&quot;/blog/2026/26-03/bubbletea-commands&quot;&gt;I already talked about today&lt;/a&gt; and I came across something mildly annoying but not all bad so thought it would be nice to write down&lt;/p&gt;
&lt;p&gt;I use &lt;a href=&quot;https://difftastic.wilfred.me.uk/introduction.html&quot;&gt;&lt;code&gt;difft&lt;/code&gt;&lt;/a&gt; for my &lt;a href=&quot;https://git-scm.com/&quot;&gt;&lt;code&gt;git&lt;/code&gt;&lt;/a&gt; diffs. This works really nicely as it&apos;s got some syntax awareness and integrates really well into other tools I use such as &lt;a href=&quot;https://github.com/jesseduffield/lazygit/tree/master&quot;&gt;&lt;code&gt;lazygit&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now, I&apos;m a &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_philosophy&quot;&gt;Unix Philosophy&lt;/a&gt; dude so I build &lt;a href=&quot;https://github.com/sftsrv&quot;&gt;my tools&lt;/a&gt; to do the same - so naturally I wanted to use &lt;code&gt;difft&lt;/code&gt; with &lt;code&gt;tri&lt;/code&gt; - so, here&apos;s how to do that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The below examples are using &lt;a href=&quot;https://www.nushell.sh/&quot;&gt;Nushell&lt;/a&gt; so your shell&apos;s exact syntax may vary but the idea is the same&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git diff HEAD --name-only | GIT_EXTERNAL_DIFF=&amp;quot;difft --color=always --display=inline&amp;quot; tri --preview `git diff HEAD -- `
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, braindump definitely. Realistically, since I want &lt;code&gt;difft&lt;/code&gt; to always behave like this, It&apos;s probably worth setting the environment variable elsewhere, but the steps are basically:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use the &lt;code&gt;GIT_EXTERNAL_DIFF&lt;/code&gt; environment variable to have the &lt;code&gt;difft&lt;/code&gt; command, this causes git to use the entire command and not just execute the binary provided as with &lt;a href=&quot;https://git-scm.com/docs/diff-config#Documentation/diff-config.txt-diffexternal&quot;&gt;&lt;code&gt;diff.external&lt;/code&gt;&lt;/a&gt;, so I can provide the flags to format &lt;code&gt;difft&lt;/code&gt; as desired&lt;/li&gt;
&lt;li&gt;Then just use &lt;code&gt;tri&lt;/code&gt; as normal&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Assuming you&apos;ve set step 1. within your shell, the command is more simply:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;# step 1.
$env.GIT_EXTERNAL_DIFF = &amp;quot;difft --color=always --display=inline&amp;quot;

#step 2.
git diff HEAD --name-only | tri --preview `git diff HEAD -- `
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is just the normal way that &lt;code&gt;tri&lt;/code&gt; works so yay&lt;/p&gt;
&lt;p&gt;And that&apos;s it okbye&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Update 14 April 2026&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&apos;ve added this function to my nu config which basically do the above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-nu&quot;&gt;def &amp;quot;g diff tri&amp;quot; [range = &amp;quot;HEAD..master&amp;quot;] {
  git diff ($range) --name-only
  | GIT_EXTERNAL_DIFF=&amp;quot;difft --color=always --display=inline&amp;quot; tri --preview $&amp;quot;git diff ($range) -- &amp;quot; --flat
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Update 04 May 2026&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&apos;ve wanted to do more complex preview behavior with &lt;code&gt;tri&lt;/code&gt; - particularly making it possible to generate custom commands. I&apos;ve recently added support for that so it now makes for some really interesting stuff, like a command for example the below command which lets you browse the input files&apos; history&lt;/p&gt;
&lt;p&gt;Using it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-nu&quot;&gt;^find **/*.go | g log tri
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the definition is a bit messy, but not too complicated I hope:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-nu&quot;&gt;# Expects a list of paths as an input
def &amp;quot;g log tri&amp;quot; [] {
  $in
  | lines
  | par-each {|p| git log --pretty=format:&amp;quot;%as %h %f&amp;quot; -- $p | str replace -m -a --regex ^ $&amp;quot;($p)/&amp;quot; }
  | to text
  | GIT_EXTERNAL_DIFF=&amp;quot;difft --color=always --display=inline&amp;quot; tri --preview &amp;quot;git diff $4..$4^ -- $1&amp;quot; --pattern `^(.*)/((\d|-)+) (\w+)`
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;This is also probably very inefficient. So be selective about the paths you provide since this does a log for all given paths and can be very slow on a large repository&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Mildly interesting photos from Eid</title><link>https://nabeelvalley.co.za/blog/2026/22-03/mildly-interesting-eid/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/22-03/mildly-interesting-eid/</guid><pubDate>Sun, 22 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Gallery from &apos;../../../../components/Gallery.astro&apos;&lt;/p&gt;
&lt;p&gt;It was Eid on Friday (20 March). We spent it with some friends which is so different to when living near family. It&apos;s quieter and far less chaotic. The Cherry Blossoms are in bloom and the sun was out though - so I took some pictures&lt;/p&gt;
&lt;p&gt;Also a few fairly random things happened so I figured I&apos;d list them for amusement&apos;s sake&lt;/p&gt;
&lt;p&gt;When we went to the Masjid for the &lt;a href=&quot;https://en.wikipedia.org/wiki/Eid_prayers&quot;&gt;Eid Salaah&lt;/a&gt; Shaheed thought that the drink being served was &lt;a href=&quot;https://en.wikipedia.org/wiki/Boeber&quot;&gt;Boeber&lt;/a&gt; (which of course, it wasn&apos;t - because why would it be at a Moroccan Masjid in the Netherlands?). Anyways - it was fun watching him realize it was in fact just a cup of milk.&lt;/p&gt;
&lt;p&gt;In the afternoon, on the way to &lt;a href=&quot;https://en.wikipedia.org/wiki/Friday_prayer&quot;&gt;Jummah&lt;/a&gt; I saw a giant hole being dug next to the shopping center so I made a mental note to take a picture of it on my way home&lt;/p&gt;
&lt;p&gt;On the way to the Masjid still, my path was blocked by a school of kids cycling with bright orange vests and teachers shouting &amp;quot;Trappen voor je leven!&amp;quot;. There were like a lot of them&lt;/p&gt;
&lt;p&gt;Then on the way back from the Masjid, after taking my picture of the giant hole - I stopped and took a few of the cherry blossoms. The old man sitting outside his apartment building in the sun shouted at me to get some from the other side where the sun was coming from to which I obliged&lt;/p&gt;
&lt;p&gt;Anyways, all that to say - here are some random pictures from the past week&lt;/p&gt;
&lt;p&gt;&amp;lt;Gallery path=&amp;quot;blog/2026-03-22 - eid&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Update 27 March - I was cycling back from the masjid today and saw an old man stop to take a picture of the big hole. &apos;tis truly universal innit&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Join the Webring!</title><link>https://nabeelvalley.co.za/blog/2026/12-03/webring/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/12-03/webring/</guid><description>I&apos;m starting a Webring!</description><pubDate>Thu, 12 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Assumed audience: People with a personal website or anyone interested in the indie web&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&apos;ve wanted to start a &lt;a href=&quot;https://en.wikipedia.org/wiki/Webring&quot;&gt;Webring&lt;/a&gt; for a while now and finally got around to it. Click the links in the footer to explore!&lt;/p&gt;
&lt;h2&gt;Would You like to Join?&lt;/h2&gt;
&lt;p&gt;That&apos;s great! You need to do two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add the following HTML to your site&apos;s footer (or some variation of those 4 links) - style it however you like!&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;section&amp;gt;
  &amp;lt;a href=&amp;quot;https://webring.nabeelvalley.co.za&amp;quot;&amp;gt;&amp;lt;em&amp;gt;Webring&amp;lt;/em&amp;gt;&amp;lt;/a&amp;gt;

  &amp;lt;ul class=&amp;quot;links&amp;quot;&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://webring.nabeelvalley.co.za/previous&amp;quot;&amp;gt;Previous&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://webring.nabeelvalley.co.za/random&amp;quot;&amp;gt;Random&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://webring.nabeelvalley.co.za/next&amp;quot;&amp;gt;Next&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Make a pull request adding your site to the &lt;a href=&quot;https://github.com/nabeelvalley/webring&quot;&gt;webring repo&lt;/a&gt; at &lt;a href=&quot;https://github.com/nabeelvalley/webring/blob/main/src/config.gleam&quot;&gt;&lt;code&gt;src/config.gleam&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that should do it! Welcome to the web&lt;/p&gt;
</content:encoded></item><item><title>Web Component for Making Patterns</title><link>https://nabeelvalley.co.za/blog/2026/17-02/pattern-web-component/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/17-02/pattern-web-component/</guid><description>A web component for defining geometric patterns</description><pubDate>Tue, 17 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I made a small web component for defining geometric patterns, you can see the component in action here:&lt;/p&gt;
&lt;p&gt;(inspect the JS if you&apos;d like to see what&apos;s happening, though it&apos;s just some bad SVG stuff)&lt;/p&gt;
&lt;p&gt;&amp;lt;script src=&amp;quot;/web-components/pattern.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;site-pattern scale=&amp;quot;20&amp;quot; pattern-x=&amp;quot;0 1 0 0 1 0 1 1&amp;quot; pattern-y=&amp;quot;1 0 0&amp;quot;&amp;gt;
&amp;lt;svg style=&amp;quot;width: 100%; aspect-ratio: 3/2&amp;quot;&amp;gt;&amp;lt;/svg&amp;gt;
&amp;lt;/site-pattern&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>CSS Anchor Positioning</title><link>https://nabeelvalley.co.za/blog/2026/11-02/css-anchor-positioning/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2026/11-02/css-anchor-positioning/</guid><description>Positining CSS elements and some other interesting CSS</description><pubDate>Wed, 11 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was reading a pull request the other day and someone suggested the use of &lt;code&gt;position-anchor&lt;/code&gt; which was something I hadn&apos;t seen before and so I thought I&apos;d write something small about it&lt;/p&gt;
&lt;p&gt;In putting together this example, I came across a few interesting points that I wanted to talk about - but before getting into those, here&apos;s a small example first&lt;/p&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;p&gt;For the example we&apos;ll use some HTML and CSS in order to place some content relative to some specific anchor. The result we see is that the &amp;quot;Content for Anchor N&amp;quot; is placed at the top right of the &amp;quot;Anchor N&amp;quot; element, but this could be many other placements or layouts as desired&lt;/p&gt;
&lt;p&gt;&amp;lt;section&amp;gt;
&amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-1&amp;quot;&amp;gt;Anchor 1&amp;lt;/h3&amp;gt;
&amp;lt;p class=&amp;quot;anchored&amp;quot; anchor-name=&amp;quot;--anchor-1&amp;quot;&amp;gt;Content for Anchor 1&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-2&amp;quot;&amp;gt;Anchor 2&amp;lt;/h3&amp;gt;
&amp;lt;p class=&amp;quot;anchored&amp;quot; anchor-name=&amp;quot;--anchor-2&amp;quot;&amp;gt;Content for Anchor 2&amp;lt;/p&amp;gt;
&amp;lt;/section&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;style&amp;gt;
.anchor {
anchor-name: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
margin: 50px;
}&lt;/p&gt;
&lt;p&gt;.anchored {
position-anchor: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
position: fixed;
bottom: anchor(bottom);
right: anchor(right);
}
&amp;lt;/style&amp;gt;&lt;/p&gt;
&lt;p&gt;The above example uses a few interesting bits that I&apos;d like to discuss before throwing a wall of code at you&lt;/p&gt;
&lt;h2&gt;CSS Identifiers&lt;/h2&gt;
&lt;p&gt;Though it does a pretty good job of making everything look like a string - CSS does indeed have data types (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/Data_types&quot;&gt;CSS Data Types - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;). Usually we don&apos;t need to think too hard about these but they end up being necessary in the above example when using the &lt;code&gt;position-anchor&lt;/code&gt; attribute and &lt;code&gt;attr&lt;/code&gt; function&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt; is the type used to represent an identifier in CSS (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/ident&quot;&gt;CSS &lt;code&gt;&amp;lt;ident&amp;gt;&lt;/code&gt; - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;)&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt; is a case-sensitive string that can be user-defined and used as CSS identifier (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/custom-ident&quot;&gt;CSS &lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt; - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;)&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;position-anchor&lt;/code&gt; attribute requires a &lt;code&gt;&amp;lt;dashed-ident&amp;gt;&lt;/code&gt; which is a &lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt; that starts with &lt;code&gt;--&lt;/code&gt; (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/dashed-ident&quot;&gt;CSS &lt;code&gt;&amp;lt;dashed-ident&amp;gt;&lt;/code&gt; - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;). These will never be defined by CSS and are only ever defined by the user&lt;/p&gt;
&lt;p&gt;In our example, we&apos;re receiving our &lt;code&gt;&amp;lt;dashed-ident&amp;gt;&lt;/code&gt; via &lt;code&gt;attr()&lt;/code&gt;. Since a &lt;code&gt;&amp;lt;dashed-ident&amp;gt;&lt;/code&gt; cannot be defined by CSS, the type we will receive from &lt;code&gt;attr()&lt;/code&gt; is a &lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt;. Note that this &lt;strong&gt;must&lt;/strong&gt; start with &lt;code&gt;--&lt;/code&gt; in order to work in the place of a &lt;code&gt;&amp;lt;dashed-ident&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Reading Attributes in CSS&lt;/h2&gt;
&lt;p&gt;The CSS &lt;code&gt;attr()&lt;/code&gt; function lets us read the value of an element attribute and use it in CSS (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/attr&quot;&gt;CSS &lt;code&gt;attr()&lt;/code&gt; - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;). This means that we can effectively provide variables for use within CSS by way of HTML attributes. This is really handy and has tons of use cases&lt;/p&gt;
&lt;p&gt;In the example above, we&apos;re using the &lt;code&gt;attr()&lt;/code&gt; to read the value of the &lt;code&gt;anchor&lt;/code&gt; attribute. Some ways of using &lt;code&gt;attr()&lt;/code&gt; can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* basic */
attr(attribute-name)

/* with a unit or type*/
attr(attribute-name unit)
attr(attribute-name type(&amp;lt;css-type&amp;gt;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To actually use this, we can specify an attribute on an HTML element like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-1&amp;quot;&amp;gt;Anchor 1&amp;lt;/h3&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can then read an attribute, for example - the &lt;code&gt;anchor-name&lt;/code&gt; attribute as a &lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt;, using &lt;code&gt;attr()&lt;/code&gt; as seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.anchor {
  anchor-name: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;attr()&lt;/code&gt; can be used to read data from an attribute and use it in CSS pretty much anywhere that we&apos;d normally use hard-coded data&lt;/p&gt;
&lt;h2&gt;Anchor Positioning&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve covered what the &lt;code&gt;attr&lt;/code&gt; and &lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt; syntax is all about, we can dive into anchor positioning&lt;/p&gt;
&lt;p&gt;Anchor positioning is a set of CSS attributes and behaviors that make it possible to connect the positions and sizes of different elements (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Anchor_positioning&quot;&gt;CSS anchor positioning - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;). For the sake of this example, we&apos;ll use the different parts of the anchor positioning module to place an element at the top-right of another element. Making this work requires us to define the anchor element. This is done using the &lt;code&gt;anchor-name&lt;/code&gt; property on said element (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/anchor-name&quot;&gt;CSS anchor-name - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h3 class=&amp;quot;anchor-1&amp;quot;&amp;gt;Anchor 1&amp;lt;/h3&amp;gt;

&amp;lt;style&amp;gt;
.anchor-1 {
  anchor-name: --anchor-1
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then, we can reference this &lt;code&gt;anchor-name&lt;/code&gt; from any elements that want to position themselves relative to this with the &lt;code&gt;position-anchor&lt;/code&gt; property which specifies the name of the anchor element (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/position-anchor&quot;&gt;CSS position-anchor - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;p class=&amp;quot;anchored-1&amp;quot;&amp;gt;Content for Anchor 1&amp;lt;/p&amp;gt;

&amp;lt;style&amp;gt;
.anchored-1 {
  position-anchor: --anchor-1;
  position: fixed;

  bottom: anchor(bottom);
  right: anchor(right);
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above, we specify &lt;code&gt;position: fixed&lt;/code&gt; to place this element relative to the &lt;code&gt;position-anchor&lt;/code&gt; and out of the normal document flow (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/position&quot;&gt;CSS position - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;)&lt;/p&gt;
&lt;p&gt;The CSS &lt;code&gt;anchor()&lt;/code&gt; function is used to return the length relative to the anchor element and allows us to position the anchored element relative to the anchor (&amp;lt;cite&amp;gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/anchor&quot;&gt;CSS &lt;code&gt;anchor()&lt;/code&gt; - MDN&lt;/a&gt;&amp;lt;/cite&amp;gt;)&lt;/p&gt;
&lt;h2&gt;Putting It Together&lt;/h2&gt;
&lt;p&gt;The example above is fairly repetitive. For each element having to redefine a CSS rule sets the &lt;code&gt;anchor-name&lt;/code&gt; and &lt;code&gt;position-anchor&lt;/code&gt; can become tedious. There are two solutions that will give us some kind of reusability here, namely:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using a CSS custom property that is set on the element&lt;/li&gt;
&lt;li&gt;Using a custom HTML attribute and reading that in the CSS&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Lately I&apos;ve been liking the use of custom HTML attributes as a hook for styling - this is inspired by the &lt;a href=&quot;https://jordanbrennan.hashnode.dev/tac-a-new-css-methodology&quot;&gt;TAC CSS Methodology&lt;/a&gt; which uses Tags, Attributes, and Classes - in that order - as styling hooks&lt;/p&gt;
&lt;p&gt;As such, the below example uses the &lt;code&gt;anchor-name&lt;/code&gt; attribute on the HTML element to define the values to use for &lt;code&gt;anchor-name&lt;/code&gt; and &lt;code&gt;position-anchor&lt;/code&gt;, which we then read in the CSS using &lt;code&gt;attr()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-1&amp;quot;&amp;gt;Anchor 1&amp;lt;/h3&amp;gt;
&amp;lt;p class=&amp;quot;anchored&amp;quot; anchor-name=&amp;quot;--anchor-1&amp;quot;&amp;gt;Content for Anchor 1&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then, define generic CSS rules that can work with any provided &lt;code&gt;anchor-name&lt;/code&gt; attribute and read them accordingly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.anchor {
  anchor-name: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
  margin: 50px;
}

.anchored {
  position-anchor: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
  position: fixed;
  bottom: anchor(bottom);
  right: anchor(right);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting that together gets the behavior we&apos;re after in a pretty neat and reusable way&lt;/p&gt;
&lt;h2&gt;The Big Example&lt;/h2&gt;
&lt;p&gt;Putting all the above together, we can get back to the code for the original example, which can be seen once more below:&lt;/p&gt;
&lt;p&gt;&amp;lt;section&amp;gt;
&amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-3&amp;quot;&amp;gt;Anchor 3&amp;lt;/h3&amp;gt;
&amp;lt;p class=&amp;quot;anchored&amp;quot; anchor-name=&amp;quot;--anchor-3&amp;quot;&amp;gt;Content for Anchor 3&amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-4&amp;quot;&amp;gt;Anchor 4&amp;lt;/h3&amp;gt;
&amp;lt;p class=&amp;quot;anchored&amp;quot; anchor-name=&amp;quot;--anchor-4&amp;quot;&amp;gt;Content for Anchor 4&amp;lt;/p&amp;gt;
&amp;lt;/section&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;style&amp;gt;
.anchor {
anchor-name: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
margin: 50px;
}&lt;/p&gt;
&lt;p&gt;.anchored {
position-anchor: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
position: fixed;
bottom: anchor(bottom);
right: anchor(right);
}
&amp;lt;/style&amp;gt;&lt;/p&gt;
&lt;p&gt;The respective HTML and CSS is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;section&amp;gt;
  &amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-3&amp;quot;&amp;gt;Anchor 3&amp;lt;/h3&amp;gt;
  &amp;lt;p class=&amp;quot;anchored&amp;quot; anchor-name=&amp;quot;--anchor-3&amp;quot;&amp;gt;Content for Anchor 3&amp;lt;/p&amp;gt;

  &amp;lt;h3 class=&amp;quot;anchor&amp;quot; anchor-name=&amp;quot;--anchor-4&amp;quot;&amp;gt;Anchor 4&amp;lt;/h3&amp;gt;
  &amp;lt;p class=&amp;quot;anchored&amp;quot; anchor-name=&amp;quot;--anchor-4&amp;quot;&amp;gt;Content for Anchor 4&amp;lt;/p&amp;gt;
&amp;lt;/section&amp;gt;

&amp;lt;style&amp;gt;
  .anchor {
    anchor-name: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
    margin: 50px;
  }

  .anchored {
    position-anchor: attr(anchor-name type(&amp;lt;custom-ident&amp;gt;));
    position: fixed;
    bottom: anchor(bottom);
    right: anchor(right);
  }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Accessibility Notes&lt;/h2&gt;
&lt;p&gt;Be careful with this idea, though it&apos;s useful to move elements around the screen arbitrarily but it&apos;s probably undesirable from an accessibility standpoint. Try to ensure that the elements are still related logically and ordered so that screen readers and other accessibility tools work as you&apos;d intend&lt;/p&gt;
&lt;h2&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;The above APIs can also be a handy addition to the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/popover&quot;&gt;HTML popover attribute&lt;/a&gt; and can lead to some nice JavaScript-free behaviors&lt;/p&gt;
</content:encoded></item><item><title>Generator Generation</title><link>https://nabeelvalley.co.za/blog/2025/17-12/generator-generation/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/17-12/generator-generation/</guid><description>Converting callback based APIs into Async Generators in JavaScript/Typescript</description><pubDate>Wed, 17 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So I was just going to write a short post about this handy function I made, but I thought it would be a nice opportunity to build a little bit more of an understanding around the topic of generators more broadly&lt;/p&gt;
&lt;p&gt;Our end goal is going to be to define an abstraction that will allow us to convert any Callback-Based API into an Async Generator. Now, if those words don’t mean much to you, then welcome to the other side of JavaScript. If you’re just here for the magic function, however, feel free to skip to the end&lt;/p&gt;
&lt;h2&gt;Promises&lt;/h2&gt;
&lt;p&gt;Before diving into the complexity of generators, we&apos;re going to quickly kick off with a little introduction to &lt;code&gt;Promises&lt;/code&gt; and how they relate to &lt;code&gt;async/await&lt;/code&gt; and callback-based code&lt;/p&gt;
&lt;p&gt;Promises are used to make async code easier to work with and JavaScript has some nice syntax - like &lt;code&gt;async/await&lt;/code&gt; that makes code using promises easier follow and understand. They&apos;re also the common way to represent async operations which is exactly what we&apos;re going to use them for&lt;/p&gt;
&lt;p&gt;Before we can dive right into implementing our function for creating an &lt;code&gt;AsyncGenerator&lt;/code&gt; from a callback based API, it&apos;s important to understand how we might go about wrapping a callback based API into a &lt;code&gt;Promise&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Creating Promises from Callbacks&lt;/h3&gt;
&lt;p&gt;Often we end up in cases where we&apos;ve got some code that is callback based - this is a function, for example &lt;code&gt;setTimeout&lt;/code&gt;, that will invoke the rest of our code asynchronously when some task is done or event is received&lt;/p&gt;
&lt;p&gt;A simple example of a callback based function is &lt;code&gt;setTimeout&lt;/code&gt; which will resume the execution of our code after some specified amount of time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;setTimeout(() =&amp;gt; {
  console.log(&apos;this runs after 1000ms&apos;)
}, 1000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A common usecase is to convert this to a &lt;code&gt;Promise&lt;/code&gt; so that consumers can work with this using &lt;code&gt;async&lt;/code&gt; functions and &lt;code&gt;await&lt;/code&gt;ing the relevant function call&lt;/p&gt;
&lt;p&gt;The basic method for doing this consists of returning a &lt;code&gt;Promise&lt;/code&gt; and handling the rejection or resolution within the callback. For example, we can create a promise-based version of &lt;code&gt;setTimeout&lt;/code&gt; using this approach:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function sleep(timeout: number) {
  return new Promise((resolve, _reject) =&amp;gt; {
    setTimeout(resolve, timeout)
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This promise will now resolve when &lt;code&gt;setTimeout&lt;/code&gt; calls the &lt;code&gt;resolve&lt;/code&gt; method that&apos;s been passed to it. This allows us to turn some callback based code like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;setTimeout(() =&amp;gt; {
  console.log(&apos;done&apos;)
}, 1000)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Into this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;await sleep(1000)
console.log(&apos;done&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Granted, this isn&apos;t a huge difference - the value of this comes from when we have multiple of these kinds of calls nested within each other. Callback code is notorious for its tendency towards chaos. My rule of thumb on this is basically &amp;quot;less indentation is easier to understand&amp;quot;. And if we can avoid indentation and keep our code flat we can focus on the essential complexity of our application and not the cognitive load that comes with confusing scope, syntax, and callbacks&lt;/p&gt;
&lt;p&gt;This is such a common problem in the JavaScript world, that Node.js even has a builtin function &lt;code&gt;node:util&lt;/code&gt; called &lt;code&gt;promisify&lt;/code&gt; that converts Node.js style callback functions into promise-based ones&lt;/p&gt;
&lt;h3&gt;Async/Await&lt;/h3&gt;
&lt;p&gt;When working with promises, it&apos;s useful to define our methods using the &lt;code&gt;async&lt;/code&gt; keyword, this allows us to work with a &lt;code&gt;Promise&lt;/code&gt; using &lt;code&gt;await&lt;/code&gt; and not have any callbacks&lt;/p&gt;
&lt;p&gt;So we can have our function below, which can &lt;code&gt;await&lt;/code&gt; the &lt;code&gt;sleep&lt;/code&gt; function and it would be defined like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;async function doWork(){
  await sleep(5000)
  console.log(&apos;fine, time to work now&apos;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;doWork&lt;/code&gt; function returns &lt;code&gt;Promise&lt;/code&gt;, this is because the &lt;code&gt;async&lt;/code&gt; keyword is some syntax sugar for creating a &lt;code&gt;Promise&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Promises Vs Async&lt;/h3&gt;
&lt;p&gt;For the sake of understanding, all that the &lt;code&gt;async&lt;/code&gt; keyword does allow us to remove the &lt;code&gt;Promise&lt;/code&gt; construction from our function - &lt;code&gt;async&lt;/code&gt; functions are simply functions that return a &lt;code&gt;Promise&lt;/code&gt; - these are alternative syntax for the same thing - so, the following two functions are the same:&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;async&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;async function getNumber() {
  return 5
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using an explicit &lt;code&gt;Promise&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function getNumber() {
  return new Promise((resolve) =&amp;gt; resolve(5))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Promise.withResolvers&lt;/h3&gt;
&lt;p&gt;Another pattern that often comes us is the need to reach into the &lt;code&gt;Promise&lt;/code&gt; constructor and grab onto its &lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt; methods and pass them around so that we can &amp;quot;remotely&amp;quot; compelete a &lt;code&gt;Promise&lt;/code&gt;, as per MDN, the common pattern for doing this looks something like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function withResolvers&amp;lt;T&amp;gt;() {
  let resolve: (v: T) =&amp;gt; void = () =&amp;gt; {}
  let reject: (error: unknown) =&amp;gt; void = () =&amp;gt; {}

  new Promise&amp;lt;T&amp;gt;((res, rej) =&amp;gt; {
    resolve = res
    reject = rej
  })

  return {
    resolve,
    reject,
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method is also a recent addition to the &lt;code&gt;Promise&lt;/code&gt; class via &lt;code&gt;Promise.withResolvers&lt;/code&gt;, but for cases where it&apos;s not - the above should serve the equivalent purpose&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve got an understanding of Promises, it&apos;s time to talk about Iterators and Generators&lt;/p&gt;
&lt;h2&gt;Iterators and Generators&lt;/h2&gt;
&lt;p&gt;Iterators and generators enable iteration to work in JavaScript and are what lies behind objects that are iterable by way of a &lt;code&gt;for ... of&lt;/code&gt; loop&lt;/p&gt;
&lt;h3&gt;Iterator&lt;/h3&gt;
&lt;p&gt;An iterator is basically an object that will return a new value whenever its &lt;code&gt;next&lt;/code&gt; method is called&lt;/p&gt;
&lt;p&gt;A simple iterator can be defined as an object that has a &lt;code&gt;next&lt;/code&gt; method that returns whether it&apos;s &lt;code&gt;done&lt;/code&gt; or not.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function countToIterator(max: number): Iterator&amp;lt;number&amp;gt; {
  let value = 0

  const iterator: Iterator&amp;lt;number&amp;gt; = {
    next() {
      value++
      return {
        value,
        done: value === max,
      }
    },
  }

  return iterator
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JavaScript uses the &lt;code&gt;Symbol.iterator&lt;/code&gt; property to reference this object and therefore makes it possible for the language &lt;code&gt;for ... of&lt;/code&gt; loop to iterate through this object. We can use the &lt;code&gt;countToIterator&lt;/code&gt;&apos;s returned &lt;code&gt;iterator&lt;/code&gt; to define an &lt;code&gt;Iterable&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;What a mouthful right?? - But the implementation is actually easier than the description:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function countTo(max: number): Iterable&amp;lt;number&amp;gt; {
  const iterator = countToIterator(max)

  return {
    [Symbol.iterator]() {
      return iterator
    },
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once we&apos;ve got this, we can use the &lt;code&gt;countTo&lt;/code&gt; in a loop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// counts from 1 to 5
for (const v of countTo(5)) {
  console.log(&apos;count&apos;, v)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Could this be an array? Maybe. Arrays are really just a special case of an iterator. More generally, iterators are cool because they don&apos;t have to have a fixed endpoint, or even a fixed list of values. For example, we can create a different iterator that counts until a random point by modifying how the &lt;code&gt;next&lt;/code&gt; function works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function randomlyStopCounting(): Iterable&amp;lt;number&amp;gt; {
  let value = 0

  const iterator: Iterator&amp;lt;number&amp;gt; = {
    next() {
      value++
      return {
        value,
        done: Math.random() &amp;gt; 0.8,
      }
    },
  }

  return {
    [Symbol.iterator]() {
      return iterator
    },
  }
}


for (const v of randomlyStopCounting()) {
  console.log(&apos;count&apos;, v)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is used the same as above, but the point at which this will return isn&apos;t really known beforehand. This dynamic behavior can come from lots of different places and not just from &lt;code&gt;Math.random&lt;/code&gt; and it can allow some really interesting behaviors&lt;/p&gt;
&lt;h3&gt;Generators&lt;/h3&gt;
&lt;p&gt;Defining the above iterators is fun and all, but it&apos;s quite messy. The higher-order syntax for defining these kinds of iterators is using &lt;code&gt;Generators&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;(I know, what&apos;s with all these words right??)&lt;/p&gt;
&lt;p&gt;Okay, so generator functions are functions that return a special iterator called a &lt;code&gt;Generator&lt;/code&gt;. If we weren&apos;t into the territory of weird syntax already - generators are defined using the &lt;code&gt;function*&lt;/code&gt; keyword, and use the &lt;code&gt;yield&lt;/code&gt; keyword to provide the next value. So we can rewrite our &lt;code&gt;countTo&lt;/code&gt; function using a generator function and it would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function* countTo(max: number): Generator&amp;lt;number&amp;gt; {
  let value = 0

  while (value &amp;lt; max) {
    value++
    yield value
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s actually way nicer to read right? When we &lt;code&gt;yield&lt;/code&gt; a value the flow is delegated to the loop body, just like in the case of a normal iterator, which means the consumer can actually end the iteration early, like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;for (const v of countTo(5)) {
  console.log(&apos;count&apos;, v)
  if (v == 3) {
    break
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This also applies for the iterators above, I just find it so much more interesting in this case because there&apos;s no concept that someone is going to &amp;quot;call the &lt;code&gt;next&lt;/code&gt; method again&amp;quot; which is so transparent in the iterator example above&lt;/p&gt;
&lt;h3&gt;Async Generators&lt;/h3&gt;
&lt;p&gt;Now, we&apos;re taking one more step - what if I wanted to do some long running task between each &lt;code&gt;yield&lt;/code&gt;? This could be anything from waiting for a &lt;code&gt;Promise&lt;/code&gt; to resolve, or a network request, or some user event (oh wow - there&apos;s an idea for multistep forms!)&lt;/p&gt;
&lt;p&gt;Async Generators enable us to use promises in our iterators. Let&apos;s take a look at how we might define an async version of our &lt;code&gt;countTo&lt;/code&gt; generator above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;async function* countToAsync(max: number): AsyncGenerator&amp;lt;number&amp;gt; {
  let value = 0

  while (value &amp;lt; max) {
    await sleep(1000)
    value++
    yield value
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Almost exactly the same right? Aside from the sneaky &lt;code&gt;async&lt;/code&gt; keyword and the &lt;code&gt;await&lt;/code&gt; in the loop, this is pretty similar to the sync version above. Using this also has a new little twist, can you spot it?:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;for await (const v of countToAsync(5)) {
  console.log(&apos;async count&apos;, v)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Interesting right? We&apos;re now using a &lt;code&gt;for await ... of&lt;/code&gt; loop. If you were to run this, you&apos;d also notice that there&apos;s a little pause between each value being logged&lt;/p&gt;
&lt;h2&gt;Unwrapping the Generator&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve seen what the inside of an iterator looks like - it&apos;s time to open the box and see what generators have inside&lt;/p&gt;
&lt;p&gt;Let&apos;s start with the sync version&lt;/p&gt;
&lt;h3&gt;Inside a Sync Generator&lt;/h3&gt;
&lt;p&gt;So if we redefine our &lt;code&gt;countTo&lt;/code&gt; generator without using the &lt;code&gt;function*&lt;/code&gt; and &lt;code&gt;yield&lt;/code&gt; syntax sugar, we&apos;ll see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function countTo(max: number): Generator&amp;lt;number&amp;gt; {
  let value = 0

  const generator: Generator&amp;lt;number&amp;gt; = {
    [Symbol.iterator]() {
      return generator
    },
    next() {
      value++
      return {
        value,
        done: value === max,
      }
    },
    return() {
      return undefined
    },
    throw(e) {
      throw e
    },
  }

  return generator
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks &lt;strong&gt;very&lt;/strong&gt; similar to an iterator - and that&apos;s because it is!&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Generator&lt;/code&gt; type inherits from the &lt;code&gt;Iterator&lt;/code&gt; and needs an additional &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;throw&lt;/code&gt; methods. The &lt;code&gt;return&lt;/code&gt; method allows the generator to handle any cleanup once the consumer is done iterating. The &lt;code&gt;throw&lt;/code&gt; allows any handling of errors and any other cleanup tasks&lt;/p&gt;
&lt;h3&gt;Inside an Async Generator&lt;/h3&gt;
&lt;p&gt;The async version of the above is almost identical - but we just sprinkle the &lt;code&gt;async&lt;/code&gt; keyword around to make the respective methods all return a &lt;code&gt;Promise&lt;/code&gt; as this is what the &lt;code&gt;AsyncGenerator&lt;/code&gt; requires:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;
function countToAsync(max: number): AsyncGenerator&amp;lt;number&amp;gt; {
  let value = 0

  const generator: AsyncGenerator&amp;lt;number&amp;gt; = {
    [Symbol.asyncIterator]() {
      return generator
    },
    async return() {
      return undefined
    },
    async next() {
      await sleep(1000)
      value++
      return {
        value,
        done: value === max,
      }
    },
    async throw(e) {
      throw e
    },
  }

  return generator
}

for await (const v of countToAsync(5)) {
  console.log(&apos;async count&apos;, v)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just like when defining the Async Generator before, we&apos;re just calling &lt;code&gt;sleep&lt;/code&gt; between each return value. We&apos;ve also made the &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;throw&lt;/code&gt; methods &lt;code&gt;async&lt;/code&gt; as well&lt;/p&gt;
&lt;h2&gt;Creating Generators from Callback Functions&lt;/h2&gt;
&lt;p&gt;Well, it&apos;s been a long way, but we finally have all the tools we need to turn a callback based method into an iterator. So far, we&apos;ve been using &lt;code&gt;setTimeout&lt;/code&gt; for our callbacks, but generators return multiple values. We&apos;re going to create a little modified version of &lt;code&gt;setInterval&lt;/code&gt; for this so that we can play around&lt;/p&gt;
&lt;p&gt;The version we&apos;ll define is called &lt;code&gt;countInterval&lt;/code&gt; and will emit a new number until the given value and then stop, this looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function countInterval(
  max: number,
  onValue: (num: number) =&amp;gt; void,
  onDone: () =&amp;gt; void,
) {
  let value = 0
  const interval = setInterval(() =&amp;gt; {
    if (value === max) {
      clearInterval(interval)
      onDone()
      return
    }

    value++
    onValue(value)
  }, 1000)
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the usage looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;countInterval(
  5,
  (v) =&amp;gt; console.log(&apos;count interval&apos;, v),
  () =&amp;gt; console.log(&apos;count interval done&apos;),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assume for whatever reason that we want to be able to take functions like this and turn them into generators. In general, we can go about the process of manually defining a generator, but that&apos;s a little tedious and requires managing a lot of internal state. It would be nice if we could do this without having to manage the intricate details of a custom generator. We basically want to define &lt;code&gt;countInterval&lt;/code&gt; such that it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function countIntervalGenerator(max: number): AsyncGenerator&amp;lt;number&amp;gt; {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For now, let&apos;s assume we&apos;ve got a method called &lt;code&gt;createGenerator&lt;/code&gt; that returns everything we need in order to hook up a generator and return it, this looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function countIntervalGenerator(max: number): AsyncGenerator&amp;lt;number&amp;gt; {
  const { generator, next, done } = createGenerator&amp;lt;number&amp;gt;()

  countInterval(max, next, done)

  return generator
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And our new generator can be used just as usual:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;for await (const value of countIntervalGenerator(5)) {
  console.log(&apos;count interval generator&apos;, value)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Defining this wonderful &lt;code&gt;createGenerator&lt;/code&gt; function combines what we&apos;ve learnt about promises and generators to get this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function createGenerator&amp;lt;T&amp;gt;() {
  let current = Promise.withResolvers&amp;lt;T&amp;gt;()
  let final = Promise.withResolvers&amp;lt;void&amp;gt;()

  const generator: AsyncGenerator&amp;lt;T&amp;gt; = {
    [Symbol.asyncIterator]() {
      return generator
    },

    async return() {
      const value = await final.promise

      return {
        done: true,
        value
      }
    },

    async next() {
      const value = await current.promise
      return {
        done: false,
        value,
      }
    },

    async throw(e) {
      throw e
    },
  }

  const next = (value: T) =&amp;gt; {
    current.resolve(value)
    current = Promise.withResolvers()
  }

  const done = () =&amp;gt; {
    final.resolve()
  }

  return {
    next,
    done,
    generator,
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn&apos;t doing anything that we haven&apos;t covered before. The only interesting bit (in my opinion) is how the &lt;code&gt;next&lt;/code&gt; handler creates a new promise on each iteration - this implementation probably has some weirdness due to that so in practice you probably want to handle that edge case somewhat. This could maybe be done by updating the &lt;code&gt;next&lt;/code&gt; function to take a parameter to indicate if it will emit a new value or not but in practice it&apos;s not always easy to figure that out - and in many cases you just don&apos;t know&lt;/p&gt;
&lt;p&gt;That all being said, I think this implementation should make it clear how these pieces all fit together - there&apos;s a lot more detail that can be had in this discussion since each of these topics are fairly deep - but I hope this post was - if not useful - then at least interesting&lt;/p&gt;
&lt;h2&gt;References and Further Reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;MDN: Promise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers&quot;&gt;MDN: Promise.withResolvers()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_generators&quot;&gt;MDN: Iterators and generators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols&quot;&gt;MDN: Iterator protocols&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield*&quot;&gt;MDN: yield*&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/api/util.html#utilpromisifyoriginal&quot;&gt;Node.js: util.promisify&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Parsing Helix logs in Nushell</title><link>https://nabeelvalley.co.za/blog/2025/16-12/helix-log-parsing/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/16-12/helix-log-parsing/</guid><pubDate>Tue, 16 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A super quick one today - I was doing some debugging on a &lt;a href=&quot;/blog/2025/26-03/the-language-server-protocol&quot;&gt;Language Server&lt;/a&gt; for &lt;a href=&quot;https://helix-editor.com/&quot;&gt;Helix&lt;/a&gt; and it was getting really annoying trying to find the data I was looking for so I wrote this quick &lt;a href=&quot;https://www.nushell.sh/&quot;&gt;Nushell&lt;/a&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cat ~/.cache/helix/helix.log | 
    lines | 
    parse &amp;quot;{date} helix_lsp::transport [{type}] {source} &amp;lt;- {data}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will parse the Helix logs using the given format.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;data&lt;/code&gt; portion is also JSON, so adding the JSON parsing can be done with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cat ~/.cache/helix/helix.log | 
    lines | 
    parse &amp;quot;{date} helix_lsp::transport [{type}] {source} &amp;lt;- {data}&amp;quot; |
    each {update data {|e| $e.data | from json}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also prefer normal JSON to the helix data view for this kind of data, so you can tac on &lt;code&gt;| to json | jq&lt;/code&gt; to pipe it to &lt;a href=&quot;https://jqlang.org/&quot;&gt;jq&lt;/a&gt; for some nice JSON rendering and querying:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;cat ~/.cache/helix/helix.log | 
    lines | 
    parse &amp;quot;{date} helix_lsp::transport [{type}] {source} &amp;lt;- {data}&amp;quot; |
    each {update data {|e| $e.data | from json}} |
    to json | jq
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Coat Rack</title><link>https://nabeelvalley.co.za/blog/2025/09-11/coat-rack/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/09-11/coat-rack/</guid><description>A cloud for people who don&apos;t like clouds</description><pubDate>Sun, 09 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Coat Rack is a platform that provides users with the necessary tools to own and share their data within their physical space. Enabling non-technical users to take control of their data ownership is the foundation on which the platform is built.&lt;/p&gt;
&lt;p&gt;This enables users to take their daily utilities off the cloud and move their data to something they own while providing a user experience that is on par with that of cloud-based applications.&lt;/p&gt;
&lt;p&gt;I&apos;ve been working on the project with &lt;a href=&quot;https://ldam.co.za/about&quot;&gt;Logan Dam&lt;/a&gt; since early 2024. I recently gave a presentation on the project and though this may be a good time to mention it on my site as well. You can also find the &lt;a href=&quot;https://github.com/coat-rack/app&quot;&gt;coat-rack repo on GitHub&lt;/a&gt; if you&apos;d like to contribute or just browse&lt;/p&gt;
&lt;p&gt;&amp;lt;embed type=&amp;quot;application/pdf&amp;quot; src=&amp;quot;/content/projects/coat-rack-presentation.pdf#zoom=FitH&amp;quot; style=&amp;quot;width: 100%; aspect-ratio: 3/2;&amp;quot;/&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Shader Web Component</title><link>https://nabeelvalley.co.za/blog/2025/09-11/shader-web-component/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/09-11/shader-web-component/</guid><description>Example of a web component for rendering Web GPU Shaders</description><pubDate>Sun, 09 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Example from &apos;./Example.astro&apos;&lt;/p&gt;
&lt;p&gt;So I want to use some more shaders and I want to also migrate everything over to use &lt;code&gt;wgsl&lt;/code&gt; instead of &lt;code&gt;glsl&lt;/code&gt; but it&apos;s kinda annoying to set them up every time so I made a little web component for using them, this is very much a work-in-progress, but here&apos;s it in action:&lt;/p&gt;
&lt;p&gt;&amp;lt;Example /&amp;gt;&lt;/p&gt;
&lt;p&gt;Using the component looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script type=&amp;quot;module&amp;quot; src=&amp;quot;/web-components/shader-canvas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;site-shader-canvas&amp;gt;
  &amp;lt;canvas /&amp;gt;
  &amp;lt;script type=&amp;quot;text/wgsl&amp;quot;&amp;gt;
    struct VertexOutput {
      @builtin(position) position: vec4f,
      @location(0) texcoord: vec2f,
    };

    @vertex fn vs(
      @builtin(vertex_index) vertexIndex : u32
    ) -&amp;gt; VertexOutput {
      const pos = array(
        vec2( 1.0,  1.0),
        vec2( 1.0, -1.0),
        vec2(-1.0, -1.0),
        vec2( 1.0,  1.0),
        vec2(-1.0, -1.0),
        vec2(-1.0,  1.0),
      );

      var vsOutput: VertexOutput;
  
      let xy = pos[vertexIndex];
      vsOutput.texcoord = pos[vertexIndex] * vec2f(0.5, 0.5) + vec2f(0.5);
      vsOutput.position = vec4f(pos[vertexIndex], 0, 1);

      return vsOutput;
    }

    @group(0) @binding(0) var&amp;lt;uniform&amp;gt; uTime: f32;
    
    @fragment fn fs(fsInput: VertexOutput) -&amp;gt; @location(0) vec4f {
      var red = abs(sin(uTime/10.0)) * fsInput.texcoord.x;
      var blue = abs(cos(uTime/5.0)) * fsInput.texcoord.y;
      return vec4f(red, 0.0, blue, 1.0);
    }
  &amp;lt;/script&amp;gt;
&amp;lt;/site-shader-canvas&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component code is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// @ts-check
import { setupCanvas } from &apos;./shader.js&apos;

class ShaderCanvas extends HTMLElement {
  static observedAttributes = [&apos;centered&apos;, &apos;highlight&apos;, &apos;large&apos;]

  /** @type {MutationObserver} */
  #observer

  /** @type {HTMLCanvasElement} */
  #canvas

  /** @type {HTMLScriptElement} */
  #script

  constructor() {
    super()
    this.#observer = new MutationObserver(() =&amp;gt; this.#initialize())
    this.#observer.observe(this, { childList: true })
  }

  disconnectedCallback() {
    this.#observer.disconnect()
  }

  connectedCallback() {
    this.#initialize()
  }

  async #initialize() {
    console.log(&apos;here&apos;)
    const initialized = this.#canvas &amp;amp;&amp;amp; this.#script
    if (initialized) {
      return
    }

    const canvas = this.querySelector(&apos;canvas&apos;)

    /** @type {HTMLScriptElement} */
    const script = this.querySelector(&apos;script[type=&amp;quot;text/wgsl&amp;quot;]&apos;)

    if (!(script &amp;amp;&amp;amp; canvas)) {
      return
    }

    this.#observer.disconnect()

    this.#canvas = canvas
    this.#script = script

    console.log(canvas, script)

    const render = await setupCanvas(this.#canvas, this.#script.innerText)

    function renderLoop() {
      requestAnimationFrame(() =&amp;gt; {
        render?.()
        renderLoop()
      })
    }

    renderLoop()
  }
}

customElements.define(&apos;site-shader-canvas&apos;, ShaderCanvas)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the code for actually doing the shader rendering pipeline is and is a heavily simplified version of what I&apos;m currently using for my &lt;a href=&quot;/blog/2024/24-08/unintentionally-made-a-programming-language&quot;&gt;Image Editor&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// @ts-check

/**
 * @param {HTMLCanvasElement} canvas
 * @param {string} shader - WebGPU Shader
 * @returns {Promise&amp;lt;((saveTo?: string) =&amp;gt; void) | undefined&amp;gt;} renderer function. Will be `undefined` if there is an instantiation error
 */
export async function setupCanvas(
  canvas,
  shader,
) {
  // @ts-ignore
  const adapter = await navigator.gpu?.requestAdapter()
  const device = await adapter?.requestDevice()
  if (!device) {
    return
  }


  /**
   * @type {any}
   */
  const ctx = canvas?.getContext(&apos;webgpu&apos;)
  if (!ctx) {
    return
  }

  // @ts-ignore
  const format = navigator.gpu.getPreferredCanvasFormat()
  ctx.configure({
    device,
    format,
  })

  const module = device.createShaderModule({
    label: &apos;base shader&apos;,
    code: shader,
  })

  const pipeline = device.createRenderPipeline({
    label: &apos;render pipeline&apos;,
    layout: &apos;auto&apos;,
    vertex: {
      module,
    },
    fragment: {
      module,
      targets: [
        {
          format,
        },
      ],
    },
  })

  const uTime = device.createBuffer({
    size: [4],
    // @ts-ignore
    usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
  })

  let curr = 1

  /**
   * @param {string} [saveTo]
   */
  function render(saveTo) {
    curr += 0.1


    // https://stackoverflow.com/questions/70284258/destroyed-texture-texture-used-in-a-submit-when-using-a-video-texture-in-ch
    // render pass descriptor needs to be recreated since this doesn&apos;t live very long on the GPU
    const renderPassDescriptor = {
      label: &apos;render pass descriptor&apos;,
      colorAttachments: [
        {
          loadOp: &apos;clear&apos;,
          storeOp: &apos;store&apos;,
          clearValue: [0, 0, 0, 0],
          view: ctx.getCurrentTexture().createView(),
        },
      ],
    }

    const bindGroup = device.createBindGroup({
      layout: pipeline.getBindGroupLayout(0),
      entries: [{
        binding: 0,
        resource: { buffer: uTime }
      }],
    })

    const encoder = device.createCommandEncoder({ label: &apos;command encoder&apos; })
    const pass = encoder.beginRenderPass(renderPassDescriptor)

    pass.setPipeline(pipeline)
    pass.setBindGroup(0, bindGroup)

    device.queue.writeBuffer(uTime, 0, new Float32Array([curr]));

    pass.draw(6) // call our vertex shader 6 times
    pass.end()

    const commandBuffer = encoder.finish()
    device.queue.submit([commandBuffer])
    if (saveTo) {
      // saving must be done during the render
      downloadCanvas(canvas, saveTo)
    }
  }

  return render
}

/**
 * @param {HTMLCanvasElement} canvas
 * @param {string} name
 */
function downloadCanvas(canvas, name) {
  const data = canvas.toDataURL(&apos;image/png&apos;)
  const link = document.createElement(&apos;a&apos;)

  link.download = name.split(&apos;.&apos;).slice(0, -1).join(&apos;.&apos;) + &apos;.png&apos;
  link.href = data
  link.click()
  link.parentNode?.removeChild(link)
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Snippet: Rachets, not Levers - Chris Krycho</title><link>https://nabeelvalley.co.za/blog/2025/03-11/rachets-not-levers/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/03-11/rachets-not-levers/</guid><description>Quote from Chris Krycho</description><pubDate>Mon, 03 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I came across this quote on &lt;a href=&quot;https://v5.chriskrycho.com/cv/#philosophy-ratchets-not-levers&quot;&gt;Chris Krycho&apos;s Website&lt;/a&gt; that I thought was worth sharing:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;The real wins, then, are tools which do not require everyone to be at their best at every moment: ratchets, not levers. Levers let you move things, but if you are holding something up with a lever, you have to keep holding it — forever. A ratchet lets you drive forward motion without slipping back as soon as you let up on the pressure.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Week 37, Server Management</title><link>https://nabeelvalley.co.za/blog/2025/14-09/week-37-server-management/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/14-09/week-37-server-management/</guid><description>Some utilities that simplify self hosting</description><pubDate>Sun, 14 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Off topic&lt;/h2&gt;
&lt;p&gt;Something off-topic but I just came across &lt;a href=&quot;https://biomousavi.com/difference-between-process-nexttick-setimmediate-and-settimeout-in-node-js&quot;&gt;this explainer&lt;/a&gt; on the different task queues and related methods in Node.js that I thought would be a nice share&lt;/p&gt;
&lt;h2&gt;What I Found&lt;/h2&gt;
&lt;p&gt;I&apos;ve been looking into/exploring some solutions for self hosting and had a little exploration/review of some tools with &lt;a href=&quot;https://kurtlourens.com/&quot;&gt;Kurt Lourens&lt;/a&gt; on some of the tech that&apos;s available&lt;/p&gt;
&lt;h3&gt;Proxies&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/traefik/traefik&quot;&gt;Traefik&lt;/a&gt; is a reverse proxy that integrates really nicely with Docker by letting you configure endpoints via the container configuration in your environment&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/caddyserver/caddy&quot;&gt;Caddy&lt;/a&gt; is a web server and reverse proxy that supports TLS out of the box and is really nice to configure&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Application Management&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/portainer/portainer&quot;&gt;Portainer&lt;/a&gt; is a management layer and UI for Docker and Kubernetes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/ofkm/arcane&quot;&gt;Arcane&lt;/a&gt; is another UI for managing Docker containers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/moghtech/komodo&quot;&gt;Komodo&lt;/a&gt; is a tool that simplifies the building and deployment of software across many servers&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Côte d&apos;Azur</title><link>https://nabeelvalley.co.za/blog/2025/10-09/cote-d-azure/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/10-09/cote-d-azure/</guid><description>Some photos from the South of France</description><pubDate>Wed, 10 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Layout from &apos;../../../../layouts/PhotographyPortfolio.astro&apos;
import Gallery from &apos;../../../../components/Gallery.astro&apos;
import PlacesLinks from &apos;../../../../components/PlacesLinks.astro&apos;
import ReadingWidth from &apos;../../../../layouts/ReadingWidth.astro&apos;&lt;/p&gt;
&lt;p&gt;&amp;lt;Layout title=&amp;quot;Côte d&apos;Azur, September 2025&amp;quot;&amp;gt;
&amp;lt;section slot=&amp;quot;gallery&amp;quot;&amp;gt;
&amp;lt;ReadingWidth&amp;gt;
&amp;lt;h2&amp;gt;Nice, France&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  &amp;lt;p&amp;gt;
    We spent some time in the South of France recently.
    The weather for the entire trip was pretty fabulous, warm, sunny, beachy days.
    Most of our trip was spent in Nice where we stayed right on the border of the old city, filled with lovely markets and great food.
    The short walk up to the waterfall - Cascade du Château - was also fantastic and had a wonderful view of the coastline
  &amp;lt;/p&amp;gt;
&amp;lt;/ReadingWidth&amp;gt;

&amp;lt;Gallery path=&amp;quot;places/2025-09-cote-d-azure/nice&amp;quot; /&amp;gt;

&amp;lt;ReadingWidth&amp;gt;
  &amp;lt;h2&amp;gt;Menton, France&amp;lt;/h2&amp;gt;

  &amp;lt;p&amp;gt;
    We also spent a little time exploring the region by train, my favourite stop was Menton - the entire city was pretty much just yellow and orange.
    Just a short train ride from Nice - lovely beaches and a lot less busy
  &amp;lt;/p&amp;gt;
&amp;lt;/ReadingWidth&amp;gt;

&amp;lt;Gallery path=&amp;quot;places/2025-09-cote-d-azure/menton&amp;quot; /&amp;gt;

&amp;lt;ReadingWidth&amp;gt;
  &amp;lt;h2&amp;gt;Monte Carlo, Monaco&amp;lt;/h2&amp;gt;

  &amp;lt;p&amp;gt;
    I wasn&apos;t a huge fan of Monaco. Not very pedestrian friendly. The architecture was really interesting though, and the water was clearer than anything I&apos;ve ever seen
  &amp;lt;/p&amp;gt;
&amp;lt;/ReadingWidth&amp;gt;

&amp;lt;Gallery path=&amp;quot;places/2025-09-cote-d-azure/monaco&amp;quot; /&amp;gt;

&amp;lt;ReadingWidth&amp;gt;
  &amp;lt;h2&amp;gt;Ventimiglia, Italy&amp;lt;/h2&amp;gt;

  &amp;lt;p&amp;gt;
    Deciding to explore a bit further we took the first stop in Italy, Ventimiglia. A quiet coastal town. It&apos;s weird how just crossing the border completely changes the vibe of a town
  &amp;lt;/p&amp;gt;
&amp;lt;/ReadingWidth&amp;gt;

&amp;lt;Gallery path=&amp;quot;places/2025-09-cote-d-azure/ventimiglia&amp;quot; /&amp;gt;

&amp;lt;ReadingWidth&amp;gt;
  &amp;lt;h2&amp;gt;A side quest&amp;lt;/h2&amp;gt;

  &amp;lt;p&amp;gt;
    I also wanted something to keep my eye on my surroundings so I could hunt for some interesting pictures,
    what drew my attention was the presence of laundry hanging on windowsills or balconies pretty much everywhere in the region -
    I suppose the sunny weather had something to do with that
  &amp;lt;/p&amp;gt;
&amp;lt;/ReadingWidth&amp;gt;

&amp;lt;Gallery path=&amp;quot;places/2025-09-cote-d-azure/laundry&amp;quot; /&amp;gt;

&amp;lt;ReadingWidth&amp;gt;
  &amp;lt;p&amp;gt;
    I also just want to say - damn, Fuji colours, amiright? -
    that&apos;s about it, thanks for reading!
  &amp;lt;/p&amp;gt;
&amp;lt;/ReadingWidth&amp;gt;

&amp;lt;br/&amp;gt;
&amp;lt;hr/&amp;gt;
&amp;lt;br/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/section&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;PlacesLinks slot=&amp;quot;links&amp;quot; /&amp;gt;
&amp;lt;/Layout&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Week 36, Creativity</title><link>https://nabeelvalley.co.za/blog/2025/07-09/week-36-creativity/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/07-09/week-36-creativity/</guid><description>Creative software and generative art</description><pubDate>Sun, 07 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve kind of always wondered how people make those crazy art installations with loads of lights and stuff, turns out there&apos;s software that exists for that&lt;/p&gt;
&lt;h1&gt;What I Found&lt;/h1&gt;
&lt;p&gt;Relatively obscure but here are a couple of generative art tools, one for music and one for everything?? They&apos;re both kinda fascinating, you should take a look&lt;/p&gt;
&lt;h2&gt;Strudel&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://strudel.cc/&quot;&gt;Strudel&lt;/a&gt; is an a programming based music performing software that also looks super sick&lt;/p&gt;
&lt;h2&gt;TouchDesigner&lt;/h2&gt;
&lt;p&gt;While diving into some art on the internet this name kept coming up. &lt;a href=&quot;https://derivative.ca/&quot;&gt;TouchDesigner&lt;/a&gt; is a node based application for creating generative art and art installations that work with loads of different input and output types&lt;/p&gt;
</content:encoded></item><item><title>Use a password manager, they said</title><link>https://nabeelvalley.co.za/blog/2025/01-10/use-a-password-manager-they-said/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/01-10/use-a-password-manager-they-said/</guid><description>A rant on how Microsoft is annoying</description><pubDate>Mon, 01 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I just had to boot up my computer to download &lt;em&gt;Microsoft Edge&lt;/em&gt; because half way through the day I found out that the &lt;em&gt;Passwords&lt;/em&gt; tab has been removed from the &lt;em&gt;Microsoft Authenticator&lt;/em&gt; app&lt;/p&gt;
&lt;p&gt;A few months ago the app notified me that &lt;em&gt;Autofill&lt;/em&gt; would stop working - I was okay with this, I just started copying and pasting passwords. Next, the ability to add passwords was removed altogether - well okay, I haven&apos;t added a new password in a while so that&apos;s also fine. But then today I see that the passwords tab has been straight up removed&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Turns out that &lt;em&gt;Autofill doesn&apos;t just refer to Autofill. But the entirety of password management&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://support.microsoft.com/en-us/account-billing/changes-to-microsoft-authenticator-autofill-09fd75df-dc04-4477-9619-811510805ab6&quot;&gt;This announcement&lt;/a&gt; outlines the details but I absolutely love the solution&lt;/p&gt;
&lt;p&gt;Basically, you have to download &lt;em&gt;Edge&lt;/em&gt; in order to get passwords to autofill at the OS level. But what if you don&apos;t want to use that but just want your passwords? Well you can still use &lt;em&gt;Edge&lt;/em&gt; since that&apos;s now where passwords live&lt;/p&gt;
&lt;p&gt;Okay. So I downloaded &lt;em&gt;Edge&lt;/em&gt; on my phone (where I was using &lt;em&gt;Authenticator&lt;/em&gt;) with the hope that I&apos;d be able to export my passwords. Nope.&lt;/p&gt;
&lt;p&gt;Get this - since &lt;a href=&quot;https://learn.microsoft.com/en-us/answers/questions/2389677/export-passwords-edge-for-androdi&quot;&gt;the Android app does not support password exporting&lt;/a&gt; you&apos;re going to have to do this on desktop&lt;/p&gt;
&lt;p&gt;So then I downloaded the desktop app, and after installing the malware that is &lt;em&gt;Microsoft Edge&lt;/em&gt; on my computer, I can now export my passwords.&lt;/p&gt;
&lt;p&gt;Okay. Got the passwords. All good.&lt;/p&gt;
&lt;p&gt;Technically, yes. But my issue here isn&apos;t just technical.&lt;/p&gt;
&lt;p&gt;Let&apos;s first address my reason for using &lt;em&gt;Authenticator&lt;/em&gt;. So when 2FA was becoming a thing, companies wanted you to have it. At some point, I had to install it so that corporate 2FA would work. And, well, I wasn&apos;t going to use multiple 2FA apps - and to be completely honest, I was just a lot less critical of the companies making some of these tools at the time&lt;/p&gt;
&lt;p&gt;So anyways, that&apos;s how everything got in there to begin with&lt;/p&gt;
&lt;p&gt;Well, my browser is where I&apos;m drawing the line. It&apos;s one thing to copy and paste passwords out of an app, it&apos;s something else for most of my online interactions to go through the giant data collection service that is &lt;em&gt;Edge&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The concern I share is broader though. I&apos;m technical enough to find the documentation and get my data migrated over. But what if you don&apos;t know how do do all that export/import jazz, or you don&apos;t even have a desktop. What if you don&apos;t really understand the implications of having a single organization tracking you across all your interactions&lt;/p&gt;
&lt;p&gt;It&apos;s as simple as pushing you towards a specific web browser, or search engine, or forcing you to log into &lt;em&gt;Windows&lt;/em&gt; with your &lt;em&gt;Microsoft Account&lt;/em&gt; - because that&apos;s the only way to use the computer that you own&lt;/p&gt;
&lt;p&gt;Let&apos;s also not forget about &lt;a href=&quot;https://www.bbc.com/news/articles/cpwwqp6nx14o&quot;&gt;&lt;em&gt;Copilot&lt;/em&gt; that was recording every action users did&lt;/a&gt; along with literal screenshots&lt;/p&gt;
&lt;p&gt;Passwords are pretty important these days. It kind of sucks that big organizations are continuously pulling us into these closed systems that become harder to escape at every step. I struggle to suggest a good solution at this point other that just finding another password manager that&apos;s not controlled by a big corp - or well, write all your passwords on a piece of paper I guess&lt;/p&gt;
&lt;p&gt;There are also some other solutions like &lt;a href=&quot;https://en.wikipedia.org/wiki/YubiKey&quot;&gt;Yubikeys&lt;/a&gt; or &lt;a href=&quot;https://en.wikipedia.org/wiki/WebAuthn&quot;&gt;WebAuthn&lt;/a&gt; or other &lt;a href=&quot;https://en.wikipedia.org/wiki/FIDO_Alliance&quot;&gt;FIDO stuff&lt;/a&gt; but they&apos;re going to be hit or miss depending on what services or devices you&apos;re accessing and I don&apos;t really know what support for these kinds of technologies is like so I don&apos;t think a 100% migration is even really possible&lt;/p&gt;
</content:encoded></item><item><title>Week 35, Documentation matters</title><link>https://nabeelvalley.co.za/blog/2025/31-08/week-35-trying-this-out-again/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/31-08/week-35-trying-this-out-again/</guid><description>Markdown, Golang, SwiftUI, and Corporates</description><pubDate>Sun, 31 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Trying to get back into some regular blogging rhythym since if I don&apos;t pay attention multiple months pass by between posts&lt;/p&gt;
&lt;h2&gt;What I&apos;m working on&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Wrote a bit about the &lt;a href=&quot;/blog/2025/27-08/problems-are-better-left-solved&quot;&gt;impact Go has had&lt;/a&gt; on how I write software recently&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wrapped up work on &lt;a href=&quot;https://github.com/sftsrv/dejavu&quot;&gt;Déjà vu&lt;/a&gt; which is a command line app to bring documentation to developers when they need it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Learning SwiftUI, basically watching pretty much everything &lt;a href=&quot;https://www.youtube.com/@twostraws&quot;&gt;Paul Hudson&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/@SwiftyPlace&quot;&gt;Karin Prater&lt;/a&gt; have made&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What I found&lt;/h2&gt;
&lt;h3&gt;Mask&lt;/h3&gt;
&lt;p&gt;Something I spotted a while back and kind of just skimmed over, &lt;a href=&quot;https://github.com/jacobdeichert/mask&quot;&gt;mask&lt;/a&gt; is a task runner (like &lt;code&gt;make&lt;/code&gt;) that uses markdown for documenting commands. It seems great and is something I&apos;d like to play around with in future&lt;/p&gt;
&lt;h3&gt;Gauge&lt;/h3&gt;
&lt;p&gt;On the topic of markdown, &lt;a href=&quot;https://gauge.org/&quot;&gt;Gauge&lt;/a&gt; uses markdown docs to specify test specifications that are then backed by framework/language specific implementations to actually run those specs&lt;/p&gt;
&lt;h3&gt;Pages CMS&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://pagescms.org/&quot;&gt;Pages CMS&lt;/a&gt; is a content management system I&apos;ve been using for a while that provides a nice UI for working with markdown and JSON content and is actually what I&apos;m writing this post on right now&lt;/p&gt;
</content:encoded></item><item><title>Problems are better left solved</title><link>https://nabeelvalley.co.za/blog/2025/27-08/problems-are-better-left-solved/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/27-08/problems-are-better-left-solved/</guid><description>Some thoughts on Go</description><pubDate>Wed, 27 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;/content/projects/dejavu.gif&quot; alt=&quot;dejavu cli usage&quot;&gt;&lt;/p&gt;
&lt;p&gt;I don&apos;t enjoy writing Go. I like languages that challenge me, that make me think about processes, model the domain, and force me to be as complete as possible in my thinking. Go does none of this, but it seems to be the only language I program in lately&lt;/p&gt;
&lt;p&gt;Corporate work, as you might imagine (or, more likely, understand to your core), is not fun. It tends to be a lot of talking around problems instead of solving them, and solving around metrics instead of people&lt;/p&gt;
&lt;p&gt;I&apos;ve been struggling to find ways to add value and have been moving my focus around a bit. Between people throwing AI at anything that will stick and pushing for MORE OUTPUT constantly, there&apos;s little room to make a meaningful impact. Most people are flooded with work and don&apos;t really have time to talk about big problems or to find solutions to anything real&lt;/p&gt;
&lt;p&gt;I think small frustrations are often undervalued - particularly ones that people think are unique to them. These tend to be quite easy to solve, but since they&apos;re perceived as isolated problems we don&apos;t really bother to solve them&lt;/p&gt;
&lt;p&gt;I&apos;ve recently noticed a lot of issues popping up where the solution is &amp;quot;read the documentation&amp;quot;&lt;/p&gt;
&lt;p&gt;It&apos;s something we emphasise a lot as technical people. What always falls by the wayside however, is what documentation? Where do I find it? How do I know what I&apos;m doing is even documented - why would it be if it&apos;s a problem I&apos;m only experiencing?&lt;/p&gt;
&lt;p&gt;At the moment I&apos;m on a team that develops and supports libraries that other teams use. A large chunk of this involves working with developers to help understand where and how to integrate with our libraries&lt;/p&gt;
&lt;p&gt;When working with lots of developers you start to notice patterns. In the way people work, how they use their tools, and the types of issues they run into&lt;/p&gt;
&lt;p&gt;Developers in some team may struggle with a bug for days, when across the hall, another team knows the fix&lt;/p&gt;
&lt;p&gt;Sure, community channels help, but if the message isn&apos;t phrased in a certain way or if the right person doesn&apos;t see it then it&apos;s of no use&lt;/p&gt;
&lt;p&gt;Often, we&apos;ve documented the solutions, but no one seems to know.&lt;/p&gt;
&lt;p&gt;The problem isn&apos;t that developers don&apos;t read the documentation, it&apos;s that we&apos;ve failed to show it to them at the right time and in the right place&lt;/p&gt;
&lt;p&gt;Usually when developers run into an issue, the first place they look is their terminal - do I see any errors? Is there a weird warning of some kind?&lt;/p&gt;
&lt;p&gt;I think this space that occupies so much of our time and energy is underutilized, searching for error messages online is hit or miss, and good luck if it&apos;s something to do with your company&apos;s specific setup&lt;/p&gt;
&lt;p&gt;Well, computers read faster than people. I had an idea that I could tie the terminal and documentation together - so I wrote an app that does just that&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sftsrv/dejavu&quot;&gt;Déjà vu&lt;/a&gt; is a little app that scans the output of terminal commands in real time to find documentation that may be relevant for issues that developers are facing&lt;/p&gt;
&lt;p&gt;It works using existing documentation and is a little program I put together in a few hours using Go&lt;/p&gt;
&lt;p&gt;So I&apos;m not a fan of Go.&lt;/p&gt;
&lt;p&gt;I&apos;ve been writing a lot of it recently though. It&apos;s easy to set up, has a great ecosystem, is pretty fast, and it just works. Things that would take days to solve in other languages are an evening of work with Go&lt;/p&gt;
&lt;p&gt;Recently, the problems I&apos;ve been trying to solve have revolved around other people. Hacky scripts and complex shell setups are not things they have. Solutions need to be free standing and &amp;quot;just work&amp;quot;&lt;/p&gt;
&lt;p&gt;When it comes to other people, I tend to prioritize getting a solution quickly. Small solutions become less valuable as time passes, and people become more annoyed too.&lt;/p&gt;
&lt;p&gt;Iterating across people is a lot slower than iterating with yourself, so being able to start conversations early is important.&lt;/p&gt;
&lt;p&gt;All of this basically to say - Go helps me solve problems quickly. So what if I don&apos;t like it.&lt;/p&gt;
</content:encoded></item><item><title>Scripting Text Manipulation</title><link>https://nabeelvalley.co.za/blog/2025/01-08/scripting-text-manipulation/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/01-08/scripting-text-manipulation/</guid><description>An idea for automating changes to text files</description><pubDate>Fri, 01 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;This is kind of just a brain dump of some things that I think would be interesting to explore&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, I&apos;ve been using &lt;a href=&quot;https://zed.dev&quot;&gt;Zed&lt;/a&gt; a bit recently and have particularly enjoyed how it&apos;s &lt;a href=&quot;https://zed.dev/docs/multibuffers&quot;&gt;MultiBuffers&lt;/a&gt; work. MultiBuffers basically allow you to simultaneously edit multiple files at once while also having things like syntax highlighting and language server support&lt;/p&gt;
&lt;p&gt;I really &lt;em&gt;wanted&lt;/em&gt; to add Zed to my toolchain because of this feature but it doesn&apos;t quite seem to be a good fit in lots of other ways&lt;/p&gt;
&lt;p&gt;That being said - I really want multi buffer editing now so naturally my mind has shifted to thinking about how building something like this that meshes well with my workflow could look&lt;/p&gt;
&lt;p&gt;There are two levels that I could see something like this working on and are basically what I&apos;d like to explore at some point, the ideas are basically:&lt;/p&gt;
&lt;h2&gt;1. Literally just implementing MultiBuffers&lt;/h2&gt;
&lt;p&gt;Yup. Basically have some kind of method that lets you do a search and open that using a utility that can the flush the changes back to the original files&lt;/p&gt;
&lt;p&gt;Imagine I want to edit all usages of the word &amp;quot;hello&amp;quot;, I could have a buffer that&apos;s opened in my code editor via &lt;code&gt;my-search &apos;hello&apos; | my-edit | my-save&lt;/code&gt; or something like that, where the result of the search command would give us something that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--- start my/file/path1.txt:120-122
some context lines
hello world
some more context
--- end my/file/path1.txt:120-122

--- start my/file/path2.txt:10-12
some context lines
hello world
some more context
--- end my/file/path2.txt:120-10-12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Making any changes to that would then update the ranges in the underlying files. This is nice because we can possibly do something like apply a macro to all instances of the word &lt;code&gt;hello&lt;/code&gt; across what looks like a single file. Which can then be saved an applied&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This could also be a simplified &lt;code&gt;git patch&lt;/code&gt; view which is tweaked to make editing nice, the advantage of this is that applying this patch could be done just using git if it can be normalized back to a patch when saving&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, there are still some challenges here that I&apos;d still like to solve, like searching but getting the containing function instead of just some random range of files, which is why I think the search tool for producing these ranges also needs to be sufficiently smart&lt;/p&gt;
&lt;p&gt;There are lots of other quality things that do come up, for example getting LSP support within these edit-blocks, but I think that&apos;s possibly doable. VSCode has something called &lt;a href=&quot;https://code.visualstudio.com/api/language-extensions/embedded-languages&quot;&gt;Embedded Programming Languages&lt;/a&gt; but if something like this could make it&apos;s way through to the Language Server Protocol at large there could be a really cool user experience. But anyways, that&apos;s not part of this solution&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that idea here isn&apos;t to solve this for any specific editor but rather to create a composable solution that can work with any text editor and provide a nice mechanism to efficiently enable multi file editing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;2. A language for text manipulation&lt;/h2&gt;
&lt;p&gt;I&apos;ve mentioned &lt;a href=&quot;https://en.wikipedia.org/wiki/Macro_(computer_science)&quot;&gt;macros&lt;/a&gt;, in the context of code editors this typically refers to some kind of key you can press that triggers a predefined set of other keypresses (hopefully not recursively) that enables some relatively complex editing behavior. This is really powerful with tools like &lt;a href=&quot;https://www.vim.org&quot;&gt;Vim&lt;/a&gt;,  &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt; , or Helix which allow users to repeat certain sets of changes, for example I may want to tell the editor to &lt;strong&gt;go to first word of line, change it to X, go to end of line, add semicolon&lt;/strong&gt; and then I&apos;d record a macro which may be interpreted as &lt;code&gt;I&amp;lt;esc&amp;gt;wdiX&amp;lt;space&amp;gt;&amp;lt;esc&amp;gt;A;&amp;lt;esc&amp;gt;&lt;/code&gt; in Helix&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The sequence can look scary but remember that it&apos;s an artifact of what we did, and not something we set out to create from the start&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, what if I wanted to create these sequences from scratch and have them applied to a file? Well, the Emacs people have solved this by the looks of it, there are two tools for doing it, namely:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nongnu.org/txr/&quot;&gt;TXR&lt;/a&gt; which seems really complicated? IDK how this is even meant to be used&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Silex/elmacro&quot;&gt;elmacro&lt;/a&gt; which looks like it&apos;s got a really nice API for writing macros but seems to run inside of Emacs which isn&apos;t what I&apos;m looking for&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The elmacros API seems really nice, here&apos;s the snippet from the docs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-emacs-lisp&quot;&gt;(defun upcase-last-word ()
  (interactive)
  (move-end-of-line 1)
  (backward-word 1)
  (upcase-word 1)
  (move-beginning-of-line 1)
  (next-line 1 1))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think this is a great example of a language for manipulating text&lt;/p&gt;
&lt;p&gt;So my proposal is then - can we make something like this that can be run in isolation and has context awareness to some extent while still being generic enough to avoid language-specific things (like &lt;a href=&quot;/docs/javascript/typescript-ast&quot;&gt;AST based text transformers&lt;/a&gt;)?&lt;/p&gt;
&lt;p&gt;Basically take some file like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h1&amp;gt;hello world&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;
  &amp;lt;span&amp;gt;hello bob&amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And use a script which in psuedo code may look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# assume the &amp;quot;cursor&amp;quot; is at the start of the file
for-each search `hello`
  # goes to &apos;world&apos; or &apos;bob&apos;
  go-to-next-word-start
  
  # selects &apos;world&apos; or &apos;bob&apos;
  select $id
    go-to-end-of-word
  end select

  # searches for the containing &apos;h1&apos; or &apos;p&apos; tag
  go-to (previous `&amp;lt;h1`) or (previous or `&amp;lt;p`)

  # writes some text using the previously selected text
  append `id=&amp;quot;$id&amp;quot;`
end for-each
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To turn it into this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h1 id=&amp;quot;world&amp;quot;&amp;gt;hello world&amp;lt;/h1&amp;gt;

&amp;lt;p id=&amp;quot;bob&amp;quot;&amp;gt;
  &amp;lt;span&amp;gt;hello bob&amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This would allow us to define a macro for doing the manipulation above and could allow us to make mass changes to a single file&lt;/p&gt;
&lt;p&gt;The code focus of this macro-style script would be that it&apos;s quick to write and modify, but doesn&apos;t have to scale since it&apos;s intended for on-the-fly, once-off modifications, much like how you&apos;d use macros normally&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It could also be really cool to make it possible to extract this from a Vim/Helix macro which can then be re-run in isolation or over a bunch of files&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Bringing it together&lt;/h2&gt;
&lt;p&gt;So these two ideas seem quite different. One of them provides a method for editing many files at once in an interactive manner, and the other automates edits to a single file. I&apos;ve proposed these two because I think that they&apos;ve both got some interesting strengths&lt;/p&gt;
&lt;p&gt;The first method for multi buffers allow us to do changes that may be more random or complex over multiple files and are great for where interventions are needed due to inconsistencies when doing large refactors&lt;/p&gt;
&lt;p&gt;The second method allows us to automate predictable changes - the goal with this is to minimize the time needed to write a script for manipulating text files, which is often quite time consuming and difficult to understand. In doing so, it should make large changes more efficient and approachable for teams while lowering the barrier to entry overall&lt;/p&gt;
&lt;p&gt;I think there&apos;s also room for composability between these two methods, and possibly even executing a script on a multi buffer using something like &lt;a href=&quot;https://docs.helix-editor.com/commands.html&quot;&gt;Helix&apos;s &lt;code&gt;:pipe&lt;/code&gt; command&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;Okay so sure, we can edit files in some weird ways &amp;quot;fast&amp;quot;. So what?&lt;/p&gt;
&lt;p&gt;My idea here is that this can be a neat way to automate large code changes. Especially if those changes are macro-able. And I think the extension of a general purpose language for working with these kinds of syntax-aware macros can be really powerful. It could also just be a neat find-and-replace tool which is always useful&lt;/p&gt;
&lt;p&gt;Also, it just sounds kind of fun to build and seems like it would fit well into my current text editing workflow. So even if there aren&apos;t any other users there would at least be one - which I think is perfectly fine for small software&lt;/p&gt;
&lt;h2&gt;but but but AI&lt;/h2&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;h2&gt;Update 14 April 2026&lt;/h2&gt;
&lt;p&gt;Just came across &lt;a href=&quot;https://ast-grep.github.io&quot;&gt;ast-grep&lt;/a&gt; which makes it possible to search in an AST aware way which could be very cool&lt;/p&gt;
&lt;h2&gt;Update 15 April 2026&lt;/h2&gt;
&lt;p&gt;Another interesting tool for this kind of text manipulation is &lt;a href=&quot;https://github.com/facebookincubator/fastmod&quot;&gt;fastmod&lt;/a&gt; which allows for regex based replacements in an interactive fashion for manual intervention&lt;/p&gt;
</content:encoded></item><item><title>Web Authentication API</title><link>https://nabeelvalley.co.za/blog/2025/29-07/web-authentication-api/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/29-07/web-authentication-api/</guid><description>Simple example of the Web Authentication API in action</description><pubDate>Tue, 29 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The Web Authentication API is a public/private key based authentication mechanism that is built into modern browsers and enables us to easily develop authentication solutions on the web&lt;/p&gt;
&lt;p&gt;It consists of a few simple APIs, namely &lt;code&gt;navigator.credentials.get&lt;/code&gt; and &lt;code&gt;navigatior.credentials.create&lt;/code&gt;. A simple example that uses these APIs can be seen below:&lt;/p&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;p&gt;&amp;lt;div id=&amp;quot;authn-example&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;script&amp;gt;
let creds;&lt;/p&gt;
&lt;p&gt;const createButton = document.createElement(&apos;button&apos;);
createButton.innerText = &amp;quot;Create Account&amp;quot;;
createButton.onclick = async () =&amp;gt; {
const newCreds = await createCredentials();
alert(&amp;quot;Created credentials are&amp;quot; + JSON.stringify(newCreds));
creds = newCreds;
};&lt;/p&gt;
&lt;p&gt;const loginButton = document.createElement(&apos;button&apos;);
loginButton.innerText = &amp;quot;Log In&amp;quot;;
loginButton.onclick = async () =&amp;gt; {
if (!creds) {
throw new Error(&amp;quot;Credentials not created&amp;quot;);
}
const gotCreds = await getCredentials(creds.rawId);
alert(&amp;quot;Loaded credentials are&amp;quot; + JSON.stringify(gotCreds));
};&lt;/p&gt;
&lt;p&gt;document.querySelector(&apos;#authn-example&apos;).appendChild(createButton);
document.querySelector(&apos;#authn-example&apos;).appendChild(loginButton);&lt;/p&gt;
&lt;p&gt;function getCredentials(id) {
return navigator.credentials.get({
publicKey: {
challenge: new Uint8Array([117, 61, 252, 231, 191, 241 /* … */]),
rpId: window.location.host,
allowCredentials: [
{
id,
type: &amp;quot;public-key&amp;quot;,
},
],
userVerification: &amp;quot;required&amp;quot;,
}
});
}&lt;/p&gt;
&lt;p&gt;function createCredentials() {
return navigator.credentials.create({
publicKey: {
challenge: new Uint8Array([117, 61, 252, 231, 191, 241 /* … */]),
rp: { id: window.location.host, name: &amp;quot;Nabeel Credential Testing&amp;quot; },
user: {
id: new Uint8Array([79, 252, 83, 72, 214, 7, 89, 26]),
name: &amp;quot;jamiedoe&amp;quot;,
displayName: &amp;quot;Jamie Doe&amp;quot;,
},
pubKeyCredParams: [{ type: &amp;quot;public-key&amp;quot;, alg: -7 }],
},
});
}&lt;/p&gt;
&lt;p&gt;function sleep(ms = 2000) {
return new Promise((res) =&amp;gt; setTimeout(res, ms));
}
&amp;lt;/script&amp;gt;&lt;/p&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;And the code that implements the above can be seen as follows&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;let creds: Credential | null

const createButton = document.createElement(&apos;button&apos;)
createButton.innerText = &amp;quot;Create Account&amp;quot;
createButton.onclick = async () =&amp;gt; {
  const newCreds = await createCredentials()
  alert(&amp;quot;Created credentials are&amp;quot; + JSON.stringify(newCreds))

  creds = newCreds
}

const loginButton = document.createElement(&apos;button&apos;)
loginButton.innerText = &amp;quot;Log In&amp;quot;
loginButton.onclick = async () =&amp;gt; {
  if (!creds) {
    throw new Error(&amp;quot;Credentials not created&amp;quot;)
  }

  const gotCreds = await getCredentials(creds.rawId)
  alert(&amp;quot;Loaded credentials are&amp;quot; + JSON.stringify(gotCreds))
}

document.querySelector&amp;lt;HTMLDivElement&amp;gt;(&apos;#authn-example&apos;)!.appendChild(createButton)
document.querySelector&amp;lt;HTMLDivElement&amp;gt;(&apos;#authn-example&apos;)!.appendChild(loginButton)

function getCredentials(id: BufferSource) {
  return navigator.credentials.get({
    publicKey: {
      challenge: new Uint8Array([117, 61, 252, 231, 191, 241 /* … */]),
      rpId: window.location.host,
      allowCredentials: [
        {
          id,
          type: &amp;quot;public-key&amp;quot;,
        },
      ],
      userVerification: &amp;quot;required&amp;quot;,
    }
  })
}

function createCredentials() {
  return navigator.credentials.create({
    publicKey: {
      challenge: new Uint8Array([117, 61, 252, 231, 191, 241 /* … */]),
      rp: { id: window.location.host, name: &amp;quot;Nabeel Credential Testing&amp;quot; },
      user: {
        id: new Uint8Array([79, 252, 83, 72, 214, 7, 89, 26]),
        name: &amp;quot;jamiedoe&amp;quot;,
        displayName: &amp;quot;Jamie Doe&amp;quot;,
      },
      pubKeyCredParams: [{ type: &amp;quot;public-key&amp;quot;, alg: -7 }],
    },
  });
}

function sleep(ms = 2000) {
  return new Promise((res) =&amp;gt; setTimeout(res, ms))
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Exploring the CSS Paint API</title><link>https://nabeelvalley.co.za/blog/2025/10-07/css-houdini-paint-api/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/10-07/css-houdini-paint-api/</guid><description>Walking through a simple example of using the CSS Houdini Paint API</description><pubDate>Thu, 10 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CSS_Painting_API&quot;&gt;The CSS Painting API&lt;/a&gt; is part of &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CSS_Painting_API&quot;&gt;the CSS Houdini group of APIs&lt;/a&gt; which provide low level access to the CSS engine&lt;/p&gt;
&lt;p&gt;The CSS Houdini APIs use the idea of &amp;quot;worklets&amp;quot; which are basically JS files that the CSS engine will use as part of it&apos;s rendering pipeline&lt;/p&gt;
&lt;p&gt;For the sake of this example, I&apos;ll be looking specifically at the CSS Painting API to build a custom CSS &lt;code&gt;paint&lt;/code&gt; worklet&lt;/p&gt;
&lt;h2&gt;The CSS &lt;code&gt;paint&lt;/code&gt; function&lt;/h2&gt;
&lt;p&gt;Before getting into specifics around how to implement a worklet, it&apos;s nice to see what we&apos;re trying to get to. Worklets are effectively JS functions that we can &amp;quot;call&amp;quot; from our CSS code to modify how an element is rendered. The CSS Painting API exposes a &lt;code&gt;paint&lt;/code&gt; function in CSS. Let&apos;s assume we have a worklet called &lt;code&gt;myCustomPainter&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We would be able to apply this to some &lt;code&gt;html&lt;/code&gt; code like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h1 class=&amp;quot;fancy&amp;quot;&amp;gt;Hello world&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can style this using the CSS &lt;code&gt;paint&lt;/code&gt; function with the name of our worklet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.fancy {
  background-image: paint(myCustomPainter);  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will invoke our worklet to &lt;code&gt;paint&lt;/code&gt; a custom background for our element&lt;/p&gt;
&lt;h2&gt;The Methods Available&lt;/h2&gt;
&lt;p&gt;The CSS Paint API exposes a few different methods and bits of functionality to us&lt;/p&gt;
&lt;p&gt;Firstly, we have the methods needed for defining a worklet, this is the global &lt;code&gt;CSS.paintWorklet.addModule&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;namespace CSS {
  declare const paintWorklet: {
    addModule(url: string): Promise&amp;lt;void&amp;gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we also have the &lt;code&gt;registerPaint&lt;/code&gt; function which is a global function in the Worklet scope that is used to register a class that handles painting:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;declare function registerPaint(name: string, paintCtor: PainterOptions): Promise&amp;lt;void&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The actual &lt;code&gt;PainterOptions&lt;/code&gt; consists of two parts, a &lt;code&gt;Paint&lt;/code&gt; class that handles the actual painting, and a static &lt;code&gt;PainterClassRef&lt;/code&gt; that specificies some metadata about the &lt;code&gt;Paint&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;declare interface Paint {
  paint(ctx: PaintRenderingContext, size: PaintSize, styleMap: StylePropertyMapReadOnly): void
}

type PaintCtor = new () =&amp;gt; Paint

declare interface PainterClassRef {
  /**
   * CSS Properties accessed by the `paint` function. These can be normal or custom properties.
   */
  inputProperties?: string[]

  /**
   * Specififes if the rendering context supports transparency
   */
  contextOptions?: { alpha: boolean }

  /**
   * Inputs to the `paint` function from CSS.
   * Not supported in any browsers I&apos;ve tested.
   * Chrome on MacOS will completely break rendering the `paint` function is passed
   * any values in the CSS
   */
  inputArguments?: string[]
}

type PainterOptions = PainterClassRef &amp;amp; PaintCtor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly, for the sake of completeness, the remaining types used by the above definitions are:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;/** Not exactly a Canvas but it&apos;s pretty similar */
declare type PaintRenderingContext = CanvasRenderingContext2D

declare type PaintSize = { height: number, width: number }
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Defining a Worklet&lt;/h2&gt;
&lt;p&gt;A simple Paint class without any input properties looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export class MyCustomPainter implements Paint {
  static get contextOptions() {
    return { alpha: true };
  }
  
  static registerPaint() {
    registerPaint(&amp;quot;myCustomPainter&amp;quot;, MyCustomPainter);
  }

  paint(ctx: PaintRenderingContext, _size: PaintSize, styleMap: StylePropertyMapReadOnly) { }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;registerPaint&lt;/code&gt; method isn&apos;t strictly necessary but it lets us keep the registration inside of the class which is nice&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Registering this as a worklet is done in two steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;From our main script, we need to run &lt;code&gt;CSS.paintWorklet.addModule&lt;/code&gt;. I&apos;m using the Vite &lt;code&gt;url&lt;/code&gt; param to get this directly from the path to my worklet file:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import workletUrl from &apos;./worklet?url&apos;

CSS.paintWorklet.addModule(workletUrl)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;From the worklet, you need to register the &lt;code&gt;MyCustomPainter&lt;/code&gt; as a &lt;code&gt;painter&lt;/code&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { MyCustomPainter } from &amp;quot;./my-painter&amp;quot;;

MyCustomPainter.registerPaint()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Taking Inputs&lt;/h2&gt;
&lt;p&gt;In order for our worklet to do something fun we will probably want to take some inputs. We can specifiy which CSS properties (or custom properties) we want to use as an input - we do this via &lt;code&gt;inputProperties&lt;/code&gt;. We can also register a custom property by using &lt;code&gt;CSS.registerProperty&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For our example, we&apos;ll also define a method in the &lt;code&gt;MyCustomPainter&lt;/code&gt; class that does this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// ... rest of class
static readonly colorProp = &apos;--custom-painter-color&apos;

static registerProperties() {
  CSS.registerProperty({
    name: MyCustomPainter.colorProp,
    syntax: &apos;&amp;lt;color&amp;gt;&apos;,
    inherits: false,
    initialValue: &apos;transparent&apos;,
  })
}

static get inputProperties() {
  return [MyCustomPainter.colorProp]
}

// ... rest of class
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we need to call the &lt;code&gt;registerProperties&lt;/code&gt; method above to register the custom property in the &lt;code&gt;main.ts&lt;/code&gt; file (or somewhere in the normal page/JS context)&lt;/p&gt;
&lt;p&gt;We can do this along with where we defined the worklet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { MyCustomPainter } from &apos;./my-painter&apos;
import workletUrl from &apos;./worklet?url&apos;

CSS.paintWorklet.addModule(workletUrl)
MyCustomPainter.registerProperties()
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;While it should be possible to get inputs as &lt;code&gt;arguments&lt;/code&gt; to a painter, it seems that is not supported on any browsers as yet&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This will make it so that we can provide inputs when painting. Inputs can come from our CSS, so using our worklet now looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.fancy {
  --custom-painter-color: yellow;
  background-image: paint(myCustomPainter);  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, we can access this in the &lt;code&gt;paint&lt;/code&gt; method to do something like draw a rectangle over the entire canvas&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// ... rest of class
paint(ctx: PaintRenderingContext, size: PaintSize, styleMap: StylePropertyMapReadOnly) {
  const color = styleMap.get(MyCustomPainter.colorProp)!.toString()

  ctx.fillStyle = color
  ctx.fillRect(0, 0, size.width, size.height)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;paint&lt;/code&gt; method receives a rendering &lt;code&gt;context&lt;/code&gt;, the &lt;code&gt;size&lt;/code&gt; of the element, and the &lt;code&gt;styles&lt;/code&gt; that we defined in &lt;code&gt;registerProperties&lt;/code&gt; (if they are set on the element)&lt;/p&gt;
&lt;p&gt;It&apos;s also nice to note that since we&apos;ve specified that &lt;code&gt;--custom-painter-color&lt;/code&gt; has an &lt;code&gt;initialValue&lt;/code&gt; it will not be &lt;code&gt;undefined&lt;/code&gt; and the browser will provide us with the &lt;code&gt;initialValue&lt;/code&gt; if it&apos;s not provided&lt;/p&gt;
&lt;p&gt;And that&apos;s really about it. The API is pretty simple but powerful and makes it possible to do so much&lt;/p&gt;
&lt;h2&gt;The Complete Worklet&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h1 class=&amp;quot;fancy&amp;quot;&amp;gt;Hello world&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.fancy {
  --custom-painter-color: yellow;
  background-image: paint(myCustomPainter);  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export class MyCustomPainter implements Paint {
  static readonly colorProp = &apos;--custom-painter-color&apos;

  static registerProperties() {
    CSS.registerProperty({
      name: MyCustomPainter.colorProp,
      syntax: &apos;&amp;lt;color&amp;gt;&apos;,
      inherits: false,
      initialValue: &apos;transparent&apos;,
    })
  }

  static registerPaint() {
    registerPaint(&amp;quot;myCustomPainter&amp;quot;, MyCustomPainter);
  }

  static get inputProperties() {
    return [MyCustomPainter.colorProp]
  }

  static get contextOptions() {
    return { alpha: true };
  }

  paint(ctx: PaintRenderingContext, size: PaintSize, styleMap: StylePropertyMapReadOnly) {
    const color = styleMap.get(MyCustomPainter.colorProp)!.toString()

    ctx.fillStyle = color
    ctx.fillRect(0, 0, size.width, size.height)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { MyCustomPainter } from &amp;quot;./my-painter&amp;quot;;

MyCustomPainter.registerPaint()
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { MyCustomPainter } from &apos;./my-painter&apos;
import workletUrl from &apos;./worklet?url&apos;

MyCustomPainter.registerProperties()
CSS.paintWorklet.addModule(workletUrl)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// Types for working with the CSS Paint API

namespace CSS {
  declare const paintWorklet: {
    addModule(url: string): Promise&amp;lt;void&amp;gt;
  }
}

declare function registerPaint(name: string, paintCtor: PainterOptions): Promise&amp;lt;void&amp;gt;

declare interface Paint {
  paint(ctx: PaintRenderingContext, size: PaintSize, styleMap: StylePropertyMapReadOnly): void
}

type PaintCtor = new () =&amp;gt; Paint

declare interface PainterClassRef {
  inputProperties?: string[]
  contextOptions?: { alpha: boolean }

  /**
   * Not supported in any browsers I&apos;ve tested.
   * Chrome on MacOS will completely break rendering the `paint` function is passed
   * any values in the CSS
   */
  inputArguments?: string[]
}

type PainterOptions = PainterClassRef &amp;amp; PaintCtor

declare type PaintRenderingContext = CanvasRenderingContext2D

declare type PaintSize = { height: number, width: number }
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;There are loads of things you can do with the Houdini APIs, some things I recommend reading and taking a look at on this topic are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/css-paint-api-1/&quot;&gt;The CSS Paint API Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ishoudinireadyyet.com/&quot;&gt;Is Houdini Ready Yet?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-houdini.iamvdo.me/&quot;&gt;CSS Houdini Experiments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_properties_and_values_API/Houdini&quot;&gt;MDN CSS Houdini Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;p&gt;It&apos;s kinda annoying how many moving parts this has and that makes it a little challenging to include a live example on this blog. Hopefully the other examples I&apos;ve linked above will serve this purpose&lt;/p&gt;
&lt;p&gt;Some nice next things to look at from here are the other Houdini APIs since they offer very different sets of functionality and can be combined to do some interesting stuff&lt;/p&gt;
</content:encoded></item><item><title>Accessibility Reference List</title><link>https://nabeelvalley.co.za/blog/2025/07-07/accessibility-tools/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/07-07/accessibility-tools/</guid><description>A collection of useful accessibility tools and resources</description><pubDate>Mon, 07 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Resources&lt;/h2&gt;
&lt;p&gt;Some websites or content that cover accessibility topics&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WCAG21/&quot;&gt;Web Content Accessibility Guidelines (WCAG)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.sarasoueidan.com/&quot;&gt;Sara Soueidan&apos;s Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://adrianroselli.com/&quot;&gt;Adrian Roselli&apos;s Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hidde.blog/&quot;&gt;Hidde&apos;s Blog&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Courses&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/WAI/courses/foundations-course/&quot;&gt;WCAG Digital Accessibility Foundations&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Bookmarklets&lt;/h2&gt;
&lt;p&gt;Bookmarklets that make checking accessibility easier&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;IDK how to save a bookmarklet, look at your browser&apos;s documentation I guess&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://hinderlingvolkart.github.io/h123&quot;&gt;H123 Accessibility Outliner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://accessibility-bookmarklets.org/install.html&quot;&gt;Layout Related Accessibility Bookmarklets&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Patching packages with PNPM</title><link>https://nabeelvalley.co.za/blog/2025/03-07/pnpm-package-patch/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/03-07/pnpm-package-patch/</guid><description>Using PNPM&apos;s patching commands to modify installed dependencies</description><pubDate>Thu, 03 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Patching packages is a task that&apos;s occasionally done to fix bugs or update behavior of 3rd party dependencies within a specific project. This is often done while waiting for a fix from the upstream library or when the library author does not agree with the change that is needed&lt;/p&gt;
&lt;h2&gt;Creating a Patch&lt;/h2&gt;
&lt;p&gt;Say we have some package installed that we&apos;d like to patch, for example we&apos;ll call this &lt;code&gt;my-package&lt;/code&gt;. We currently have &lt;code&gt;my-package&lt;/code&gt; version &lt;code&gt;1.1.1&lt;/code&gt; installed and want to create a patch for that. We can kick this process off with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pnpm patch my-package@1.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Doing this will result in some output from &lt;code&gt;pnpm&lt;/code&gt; with a path to a directory that contains the package&apos;s code that we can modify&lt;/p&gt;
&lt;p&gt;To modify the code, open the given path in your editor and make the required changes&lt;/p&gt;
&lt;p&gt;Once you&apos;re satisfied with the changes, you can use the following command to commit the patch:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pnpm patch-commit path/to/folder
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;patches/my-package@1.1.1.patch&lt;/code&gt; file with the patch&lt;/li&gt;
&lt;li&gt;Add a reference to this patch in the &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Install dependencies and apply this patch&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The patch will be applied in future whenever dependencies are installed/added&lt;/p&gt;
&lt;h2&gt;Removing a Patch&lt;/h2&gt;
&lt;p&gt;To remove a patch you can use the &lt;code&gt;pnpm patch-remove&lt;/code&gt; command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pnpm patch-remove my-package@1.1.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That will remove the patch from the &lt;code&gt;patches&lt;/code&gt; directory as well as from the &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; file&lt;/p&gt;
&lt;h2&gt;Updating a Patch&lt;/h2&gt;
&lt;p&gt;To update a patch you will need to remove it and then re-create it using the info above&lt;/p&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;p&gt;Patching is annoying, avoid it if you can&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;p&gt;PNPM has documentation for all of the above mentioned commands on the &lt;a href=&quot;https://pnpm.io/cli/patch&quot;&gt;Patching Dependencies Docs&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Typescript debugging without an IDE</title><link>https://nabeelvalley.co.za/blog/2025/18-06/typescript-debugging-without-an-ide/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/18-06/typescript-debugging-without-an-ide/</guid><description>Debug Node.js code using your browser&apos;s dev tools</description><pubDate>Wed, 18 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I generally steer clear of IDEs. Their overall slowness and clunkyness makes using them a hassle. There is however one place they execel - debugging.&lt;/p&gt;
&lt;p&gt;Recently I&apos;ve been looking into how to get Node.js to debug some JS and TS code and this proved to be relatively simple&lt;/p&gt;
&lt;h2&gt;A JS file&lt;/h2&gt;
&lt;p&gt;Debugging a Javascript app is actually pretty straightforward, you can use &lt;code&gt;node inspect&lt;/code&gt; followed by the file to debug. So this just looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;node inspect my-file.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Runnning the above with a &lt;code&gt;debugger;&lt;/code&gt; statement in your code will stop at the breakpoint and you can debug from there&lt;/p&gt;
&lt;p&gt;You can then open your browser at &lt;code&gt;chrome://inspect&lt;/code&gt; and select &lt;code&gt;inspect&lt;/code&gt; on the process you&apos;d like to debug&lt;/p&gt;
&lt;h2&gt;A TS File&lt;/h2&gt;
&lt;p&gt;Typescript requires you to have a few things installed. I&apos;m going to assume that TypeScript is already installed in the project you&apos;re working in. Additionally, you need to install &lt;code&gt;ts-node&lt;/code&gt; into your project - this can be done using whatever package manager you&apos;re currently using&lt;/p&gt;
&lt;p&gt;You will also need to ensure that you have &lt;code&gt;sourceMap&lt;/code&gt; enabled in your &lt;code&gt;tsconfig.json&lt;/code&gt; file in order to have a bit of a decent debugging experience:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;compilerOptions&amp;quot;: {
	// ... other stuff
    &amp;quot;sourceMap&amp;quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you can use &lt;code&gt;node inspect&lt;/code&gt; with the &lt;code&gt;ts-loader&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;node inspect -r ts-node/register my-file.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The process then is pretty much the same as for the Javascript file debugging above. You can use &lt;code&gt;debugger;&lt;/code&gt; statements to add breakpoints, and you can open the debugger at &lt;code&gt;chrome://inspect&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>Scan based regex composition</title><link>https://nabeelvalley.co.za/blog/2025/27-03/regex-composition/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/27-03/regex-composition/</guid><description>A simplified approach to complex text replacements</description><pubDate>Thu, 27 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I needed a regex to camel-case some text, this sounds simple enough at first glance but since I had some very specific stylistic requirements it started to get more and more complex and the regex became pretty unwieldy&lt;/p&gt;
&lt;p&gt;A colleague suggested the following function to get the job done:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const normalize = (str) =&amp;gt; str.replace(/([a-z])([A-Z])/g,&apos;$1-$2&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, this works on simple examples like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;normalize(&amp;quot;HelloWorld&amp;quot;) // Hello-World
normalize(&amp;quot;helloThereBob&amp;quot;) // hello-There-Bob
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it fails on more complex cases such as when we have numbers or when a word is all caps (abbreviations/initialisms?) such as these&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;normalize(&amp;quot;URLParser&amp;quot;) // URLParser, i want URL-Parser
normalize(&amp;quot;Text1Parser&amp;quot;) // Text1Parser, i want Text-1-Parser
normalize(&amp;quot;MyURLExample1ForProgramX&amp;quot;) // My-URLExample1For-Program-X, i want My-URL-Example-1-For-Program-X
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After a lot of playing around I couldn&apos;t find a simple regex that let me do what I wanted. I did however like the idea of scanning across a string to make very specific, usually one or two character replacements. I liked the idea that different parts of the regex could be named and applied, using this idea - I thought we could have small regexes that do really simple things, such as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const replacement = `$1-$2`
const aB = /([a-z])([A-Z])/g // aB -&amp;gt; a-B
const ABc = /([A-Z])([A-Z][a-z])/g // A-Bc
const wd = /(\w)(\d)/g // a1 -&amp;gt; a-1
const dw = /(\d)(\w)/g // 1a -&amp;gt; 1-a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, these small scanners work at the 2-3 letter pattern size and let us perform surgical replacements, scanning across text and applying a replacement on small subsets of a string.&lt;/p&gt;
&lt;p&gt;Something like looking for a pattern in &lt;code&gt;URLParser&lt;/code&gt; for a set of smaller patterns like: &lt;code&gt;UR&lt;/code&gt;, &lt;code&gt;RL&lt;/code&gt;,&lt;code&gt;LP&lt;/code&gt;, &lt;code&gt;Pa&lt;/code&gt;, &lt;code&gt;ar&lt;/code&gt;, &lt;code&gt;rs&lt;/code&gt;, &lt;code&gt;se&lt;/code&gt;, and &lt;code&gt;er&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This takes away the global concern of the regex and lets us think distinctly about the different subproblems. Applying these sub-solutions is also easy:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const normalize = (str) =&amp;gt; 
	str.replace(aB, replacement)
	   .replace(ABc, replacement)
	   .replace(wd, replacement)
	   .replace(dw, replacement)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Testing this with the examples that failed earlier we see the following result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;normalize(&amp;quot;HelloWorld&amp;quot;) // Hello-World
normalize(&amp;quot;URLParser&amp;quot;) // URL-Parser
normalize(&amp;quot;Text1Parser&amp;quot;) // Text-1-Parser
normalize(&amp;quot;MyURLExample1ForProgramX&amp;quot;) // My-URL-Example-1-For-Program-X
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s basically what I want.&lt;/p&gt;
&lt;p&gt;The above solution shows us a general approach that can be used for building complex replacement structures. It is possible that it would be less efficient than a big complicated regex but I think where possible, this solution allows us to incrementally build and add functionality to regex-based solutions in a way that&apos;s much easier to understand and modify than one-shot regexes tend to be&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Lastly, a quick note - the name of this post can probably use some work, the closest thing to this pattern that I can find is &lt;a href=&quot;https://martinfowler.com/bliki/ComposedRegex.html&quot;&gt;Composed Regex by Martin Fowler&lt;/a&gt; which breaks regexes down into smaller parts in order to create a bigger regex&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Getting Started with the Language Server Protocol</title><link>https://nabeelvalley.co.za/blog/2025/26-03/the-language-server-protocol/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/26-03/the-language-server-protocol/</guid><description>Building a Basic Language Server with JavaScript</description><pubDate>Wed, 26 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Snippet from &apos;@/components/Snippet.astro&apos;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that the code here serves as a high level example for the development of a language server and is in no means intended to be a production-ready implementation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;The Language Server Protocol&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://microsoft.github.io/language-server-protocol/&quot;&gt;Language Server Protocol Specification&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Language Server Protocol (LSP) is a specification for communication between code editing applications and language servers that provide information about the programming language being worked with&lt;/p&gt;
&lt;p&gt;The protocol enables language related functionality such as diagnostics or documentation to be implemented once and reused in all editors that support LSP&lt;/p&gt;
&lt;p&gt;The specification uses &lt;a href=&quot;https://www.jsonrpc.org/specification&quot;&gt;JSON RPC 2.0&lt;/a&gt; for communicating between the editor and language server&lt;/p&gt;
&lt;h2&gt;Creating a Basic Language Server&lt;/h2&gt;
&lt;h3&gt;Input and Output&lt;/h3&gt;
&lt;p&gt;A basic language server can be created using standard in and out as the communication mechanism for the server. This is quite easy to get access to using Node.js as we can get it from &lt;code&gt;process&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { stdout, stdin } = require(&amp;quot;process&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stdin&lt;/code&gt; are streams, we can read from the &lt;code&gt;stdin&lt;/code&gt; stream using the &lt;code&gt;data&lt;/code&gt; event, and we can write to &lt;code&gt;stdout&lt;/code&gt; directly&lt;/p&gt;
&lt;p&gt;The code editor that&apos;s managing the language server will pass data to it using &lt;code&gt;stdin&lt;/code&gt;, responses need to be sent using &lt;code&gt;stdout&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Each message that&apos;s sent/received consists of two parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A headers section containing a &lt;code&gt;Content-Length&lt;/code&gt; header structured like &lt;code&gt;Content-Length: 123&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A content section&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The header and content sections are separated by &lt;code&gt;\r\n\r\n&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The overall structure looks like this (&lt;code&gt;\r\n&lt;/code&gt; shown as well since they are a strictly considered in the message)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Content-Length: 123\r\n
\r\n
{
  &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,
  &amp;quot;id&amp;quot;: 1,
  &amp;quot;method&amp;quot;: &amp;quot;example/method&amp;quot;,
  &amp;quot;params&amp;quot;: {
    ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are two types of messages, namely &lt;code&gt;Request&lt;/code&gt;s and &lt;code&gt;Notification&lt;/code&gt;s. &lt;code&gt;Request&lt;/code&gt; messages require a response. The &lt;code&gt;id&lt;/code&gt; of the message is relevant and is sent back with a response, a &lt;code&gt;Response&lt;/code&gt; looks a bit like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Content-Length: 123\r\n
\r\n
{
  &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,
  &amp;quot;id&amp;quot;: 1,
  &amp;quot;result&amp;quot;: {
    ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other type of message is a &lt;code&gt;Notification&lt;/code&gt;. &lt;code&gt;Notification&lt;/code&gt; messages don&apos;t require a &lt;code&gt;Response&lt;/code&gt;. Additionally, they will not have an &lt;code&gt;id&lt;/code&gt; and will look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Content-Length: 123\r\n
\r\n
{
  &amp;quot;jsonrpc&amp;quot;: &amp;quot;2.0&amp;quot;,
  &amp;quot;params&amp;quot;: {
    ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Initializing the Project&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;m assuming you&apos;ve got some basic idea of how Node.js works and that you&apos;re familiar with the overall idea of creating a CLI tool with Node.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since the language server needs a command, we need to do a little thing with &lt;code&gt;npm&lt;/code&gt; to register the server as a command. This can be done by first defining our language server as a &lt;code&gt;bin&lt;/code&gt;. To do this we need a JS file with the language server&lt;/p&gt;
&lt;p&gt;In this example, I&apos;m creating a folder with the following two files:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;cli.js&lt;/code&gt; - the language server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the &lt;code&gt;cli.js&lt;/code&gt; you can simply add something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;#!/usr/bin/env node

console.log(&amp;quot;Hello from Language Server&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you&apos;ll need to add the following to a &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;example-lsp&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;bin&amp;quot;: &amp;quot;./cli.js&amp;quot;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;bin&lt;/code&gt; fields are needed so that &lt;code&gt;npm&lt;/code&gt; knows how to call your command after installing it.&lt;/p&gt;
&lt;p&gt;Once the above two files are in place, you can install/register your command using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;npm i -g
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will make the &lt;code&gt;example-lsp&lt;/code&gt; command available and it will automatically run the &lt;code&gt;cli.js&lt;/code&gt; file&lt;/p&gt;
&lt;h3&gt;Linking to an Editor&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The example below is for Helix, on other editors this process is different and is not the focus of this post&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Language servers are started by or connected to from the code editing application. I&apos;m using &lt;a href=&quot;https://helix-editor.com/&quot;&gt;Helix&lt;/a&gt; which uses a config file that specifies the available language servers. We can reference the server we&apos;ve created in Helix&apos;s &lt;code&gt;languages.toml&lt;/code&gt; file like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-toml&quot;&gt;## define the language server
[language-server.example]
command = &amp;quot;example-lsp&amp;quot;

## associate a language with the language server
[[language]]
name = &amp;quot;example&amp;quot;
scope = &amp;quot;source.example&amp;quot;
file-types = [&amp;quot;example&amp;quot;]
language-servers = [&amp;quot;example&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Seeing your editor&apos;s logs may vary so I&apos;m not going to get too into that, but if you&apos;re trying to debug issues with a language server that&apos;s probably a good place to start&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Handling Messages&lt;/h3&gt;
&lt;p&gt;Once we&apos;ve got our editor setup, we should be able to open a file with a &lt;code&gt;.example&lt;/code&gt; extension which will trigger our LSP&lt;/p&gt;
&lt;p&gt;When the language server is started it will receive an &lt;code&gt;initialize&lt;/code&gt; event which will look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Content-Length: 2011

{&amp;quot;jsonrpc&amp;quot;:&amp;quot;2.0&amp;quot;,&amp;quot;method&amp;quot;:&amp;quot;initialize&amp;quot;,&amp;quot;params&amp;quot;:{&amp;quot;capabilities&amp;quot;:{&amp;quot;general&amp;quot;:{&amp;quot;positionEncodings&amp;quot;:[&amp;quot;utf-8&amp;quot;,&amp;quot;utf-32&amp;quot;,&amp;quot;utf-16&amp;quot;]},&amp;quot;textDocument&amp;quot;:{&amp;quot;codeAction&amp;quot;:{&amp;quot;codeActionLiteralSupport&amp;quot;:{&amp;quot;codeActionKind&amp;quot;:{&amp;quot;valueSet&amp;quot;:[&amp;quot;&amp;quot;,&amp;quot;quickfix&amp;quot;,&amp;quot;refactor&amp;quot;,&amp;quot;refactor.extract&amp;quot;,&amp;quot;refactor.inline&amp;quot;,&amp;quot;refactor.rewrite&amp;quot;,&amp;quot;source&amp;quot;,&amp;quot;source.organizeImports&amp;quot;]}},&amp;quot;dataSupport&amp;quot;:true,&amp;quot;disabledSupport&amp;quot;:true,&amp;quot;isPreferredSupport&amp;quot;:true,&amp;quot;resolveSupport&amp;quot;:{&amp;quot;properties&amp;quot;:[&amp;quot;edit&amp;quot;,&amp;quot;command&amp;quot;]}},&amp;quot;completion&amp;quot;:{&amp;quot;completionItem&amp;quot;:{&amp;quot;deprecatedSupport&amp;quot;:true,&amp;quot;insertReplaceSupport&amp;quot;:true,&amp;quot;resolveSupport&amp;quot;:{&amp;quot;properties&amp;quot;:[&amp;quot;documentation&amp;quot;,&amp;quot;detail&amp;quot;,&amp;quot;additionalTextEdits&amp;quot;]},&amp;quot;snippetSupport&amp;quot;:true,&amp;quot;tagSupport&amp;quot;:{&amp;quot;valueSet&amp;quot;:[1]}},&amp;quot;completionItemKind&amp;quot;:{}},&amp;quot;formatting&amp;quot;:{&amp;quot;dynamicRegistration&amp;quot;:false},&amp;quot;hover&amp;quot;:{&amp;quot;contentFormat&amp;quot;:[&amp;quot;markdown&amp;quot;]},&amp;quot;inlayHint&amp;quot;:{&amp;quot;dynamicRegistration&amp;quot;:false},&amp;quot;publishDiagnostics&amp;quot;:{&amp;quot;tagSupport&amp;quot;:{&amp;quot;valueSet&amp;quot;:[1,2]},&amp;quot;versionSupport&amp;quot;:true},&amp;quot;rename&amp;quot;:{&amp;quot;dynamicRegistration&amp;quot;:false,&amp;quot;honorsChangeAnnotations&amp;quot;:false,&amp;quot;prepareSupport&amp;quot;:true},&amp;quot;signatureHelp&amp;quot;:{&amp;quot;signatureInformation&amp;quot;:{&amp;quot;activeParameterSupport&amp;quot;:true,&amp;quot;documentationFormat&amp;quot;:[&amp;quot;markdown&amp;quot;],&amp;quot;parameterInformation&amp;quot;:{&amp;quot;labelOffsetSupport&amp;quot;:true}}}},&amp;quot;window&amp;quot;:{&amp;quot;workDoneProgress&amp;quot;:true},&amp;quot;workspace&amp;quot;:{&amp;quot;applyEdit&amp;quot;:true,&amp;quot;configuration&amp;quot;:true,&amp;quot;didChangeConfiguration&amp;quot;:{&amp;quot;dynamicRegistration&amp;quot;:false},&amp;quot;didChangeWatchedFiles&amp;quot;:{&amp;quot;dynamicRegistration&amp;quot;:true,&amp;quot;relativePatternSupport&amp;quot;:false},&amp;quot;executeCommand&amp;quot;:{&amp;quot;dynamicRegistration&amp;quot;:false},&amp;quot;fileOperations&amp;quot;:{&amp;quot;didRename&amp;quot;:true,&amp;quot;willRename&amp;quot;:true},&amp;quot;inlayHint&amp;quot;:{&amp;quot;refreshSupport&amp;quot;:false},&amp;quot;symbol&amp;quot;:{&amp;quot;dynamicRegistration&amp;quot;:false},&amp;quot;workspaceEdit&amp;quot;:{&amp;quot;documentChanges&amp;quot;:true,&amp;quot;failureHandling&amp;quot;:&amp;quot;abort&amp;quot;,&amp;quot;normalizesLineEndings&amp;quot;:false,&amp;quot;resourceOperations&amp;quot;:[&amp;quot;create&amp;quot;,&amp;quot;rename&amp;quot;,&amp;quot;delete&amp;quot;]},&amp;quot;workspaceFolders&amp;quot;:true}},&amp;quot;clientInfo&amp;quot;:{&amp;quot;name&amp;quot;:&amp;quot;helix&amp;quot;,&amp;quot;version&amp;quot;:&amp;quot;25.01.1 (e7ac2fcd)&amp;quot;},&amp;quot;processId&amp;quot;:34756,&amp;quot;rootPath&amp;quot;:&amp;quot;/example-lsp&amp;quot;,&amp;quot;rootUri&amp;quot;:&amp;quot;file:///example-lsp&amp;quot;,&amp;quot;workspaceFolders&amp;quot;:[{&amp;quot;name&amp;quot;:&amp;quot;example-lsp&amp;quot;,&amp;quot;uri&amp;quot;:&amp;quot;file:///example-lsp&amp;quot;}]},&amp;quot;id&amp;quot;:0}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want to try to view and process this message on the language server.The first thing we&apos;re going to run into when trying do this is that we can&apos;t log things anymore since the &lt;code&gt;stdout&lt;/code&gt; is used as a way to send messages to the code editor - so instead, we can output our logs to a file&lt;/p&gt;
&lt;p&gt;A little &lt;code&gt;log&lt;/code&gt; function will do that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { appendFileSync } = require(&amp;quot;fs&amp;quot;)

function log(contents) {
  const logMessage = typeof contents === &apos;string&apos; ? contents : JSON.stringify(contents)
  return appendFileSync(&apos;./log&apos;, &amp;quot;\n&amp;quot; + logMessage + &amp;quot;\n&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So this will output the logs to a file called &lt;code&gt;log&lt;/code&gt; and can be super useful to debug/inspect any issues that come up&lt;/p&gt;
&lt;p&gt;Now, to receive a message we can listen to the &lt;code&gt;data&lt;/code&gt; even on &lt;code&gt;stdin&lt;/code&gt; and respond by logging on &lt;code&gt;stdout&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;initialize&lt;/code&gt; message expects a response with some basic information about the language server. Reading this message and responding can be done as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { stdout, stdin } = require(&amp;quot;process&amp;quot;)
const { appendFileSync } = require(&amp;quot;fs&amp;quot;)

function log(contents) {
  const logMessage = typeof contents === &apos;string&apos; ? contents : JSON.stringify(contents)
  return appendFileSync(&apos;./log&apos;, &amp;quot;\n&amp;quot; + logMessage + &amp;quot;\n&amp;quot;)
}

// listen to the `data` event on `stdin` returns a `Buffer`
stdin.on(&apos;data&apos;, (buff) =&amp;gt; {
  // convert the buffer into lines
  const message = buff.toString().split(&apos;\r\n&apos;)

  // get the message content
  const content = message[message.length - 1]

  // parse the message content into a request
  const request = JSON.parse(content)
 
  // log the request to a file for later use
  log(request)

  if (message.method !== &apos;initialize&apos;) {
    // currently we only support the initialize message
    throw new Error(&amp;quot;Unsupported message &amp;quot; + message.method)
  }

  // respond with a JSON RPC message
  const result = JSON.stringify({
    jsonrpc: &amp;quot;2.0&amp;quot;,
    // reference the ID of the request
    id: request.id,
    // the result depends on the type of message being responded to
    result: {
      capabilities: {
        // we can add any functionality we want to support here as per the spec
      },
      serverInfo: {
        name: &amp;quot;example-lsp&amp;quot;,
        version: &amp;quot;0.0.1&amp;quot;
      }
    }  
  })
  
  // create the Content-Length header
  const length = Buffer.byteLength(result, &apos;utf-8&apos;)
  const header = `Content-Length: ${length}`
  
  // join the header and message into a response
  const response = `${header}\r\n\r\n${result}`

  // send the response
  stdout.write(response)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that the above example assumes that the entire message is received completely at once - there is no actual guarantee of this but it&apos;s retained here for the sake of simplicity&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the basic flow for building a language server. Listening to events from some input, often &lt;code&gt;stdin/stdout&lt;/code&gt; and responding to it using JSON RPC. The types of messages that can be received along with the expected response or behavior is all outlined in &lt;a href=&quot;https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/&quot;&gt;the LSP Specification&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Complete Example&lt;/h2&gt;
&lt;p&gt;A more complete example showing the handling of multiple messages can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;lsp-example/package.json&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;lsp-example/cli.js&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://microsoft.github.io/language-server-protocol/&quot;&gt;Language Server Protocol Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@malintha1996/understanding-the-language-server-protocol-5c0ba3ac83d2&quot;&gt;Understanding the Language Server Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Xo5VXTRoL6Q&quot;&gt;Building a Language Server from Scratch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode-languageserver-node&quot;&gt;VSCode Language Server Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/vscode-extension-samples/tree/main/lsp-sample&quot;&gt;VSCode LSP Sample&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Typescript Workers in NodeJS</title><link>https://nabeelvalley.co.za/blog/2025/12-02/nodejs-worker-threads/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/12-02/nodejs-worker-threads/</guid><description>Basic Setup for using workers in NodeJS with Typescript</description><pubDate>Wed, 12 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Using worker threads with Typescript is pretty straightforward, this probably depends a bit on your setup but the below idea seems to work for me&lt;/p&gt;
&lt;h2&gt;Single File Worker&lt;/h2&gt;
&lt;p&gt;In NodeJS we can use a sort of self-referrential worker such that depending on the context in which the file is loaded the behavior will differ, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { Worker, isMainThread, parentPort, workerData } from &amp;quot;node:worker_threads&amp;quot;;

// the worker is the current file
const workerFileName = __filename

// define a type for the data we want to share
type WorkerData = {
  id: number,
  name: string
}

// check if we&apos;re on the main or worker thread
if (isMainThread) {
  // launch a worker thread
  const worker = new Promise((resolve, reject) =&amp;gt; {
    const worker = new Worker(workerFileName, {
      // pass data to the worker
      workerData: {
        id: &amp;quot;my-worker&amp;quot;,
        name: &amp;quot;Bob&amp;quot;
      }
    })

    worker.addListener(&amp;quot;message&amp;quot;, (result) =&amp;gt; resolve(result))
    worker.addListener(&amp;quot;error&amp;quot;, reject)
  })

  worker.then(console.log)
} else {
  // do stuff for the worker thread
  console.log(&amp;quot;Running in worker&amp;quot;, workerData as WorkerData)
  const message = `Hello ${workerData.name} from worker`

  // return back to the parent thread
  parentPort?.postMessage({ message })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above file we can see a few things that are important to using workers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A check is done using &lt;code&gt;isMainThread&lt;/code&gt; to determine if the file is being executed as a worker. the handling for the worker is based on this&lt;/li&gt;
&lt;li&gt;A reference to the file which should be run in the worker thread, the &lt;code&gt;__filename&lt;/code&gt; variable is defined by NodeJS and holds the name of the curent file - this will be the compiled file name so we don&apos;t need to figure that out on our own&lt;/li&gt;
&lt;li&gt;A worker is created using &lt;code&gt;new Worker&lt;/code&gt;, since the worker is an event based API in the above example it&apos;s being wrapped in a &lt;code&gt;Promise&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Data can be passed to the worker via the &lt;code&gt;workerData&lt;/code&gt; property, this will then be put into the &lt;code&gt;workerData&lt;/code&gt; variable from &lt;code&gt;node:worker_threads&lt;/code&gt; in the worker thread&lt;/li&gt;
&lt;li&gt;Data is sent back to the worker using &lt;code&gt;parentPort.postMessage&lt;/code&gt;. This is the same even that&apos;s being listened for the &lt;code&gt;Promise&lt;/code&gt; to resolve in &lt;code&gt;worker.addListener(&amp;quot;message&amp;quot;, resolve)&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Multi File Worker&lt;/h2&gt;
&lt;p&gt;Extending the above to work with multiple files is pretty simple, the only additional trick we need is to export the &lt;code&gt;__filename&lt;/code&gt; from our worker file to the place where we want to construct the worker&lt;/p&gt;
&lt;p&gt;So, the updated code can then be broken into two files as follows:&lt;/p&gt;
&lt;p&gt;First, the worker is pretty similar to the one above, except now we export the &lt;code&gt;__filename&lt;/code&gt; as &lt;code&gt;workerFileName&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { isMainThread, parentPort, workerData } from &amp;quot;node:worker_threads&amp;quot;;

export const workerFileName = __filename

export type WorkerData = {
  id: number,
  name: string
}

if (!isMainThread) {
  console.log(&amp;quot;Running in worker&amp;quot;, workerData)
  const message = `Hello ${workerData.name} from worker`
  parentPort?.postMessage({ message })
} else {
  console.log(&amp;quot;Worker was run in the main thread&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;main.ts&lt;/code&gt; file then makes use of this exported file name to invoke the worker. Note that this is now just a normal script and will be executed in the main thread as normal&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { Worker } from &amp;quot;node:worker_threads&amp;quot;

// import the worker file name from where we defined the worker
import { workerFileName } from &amp;quot;./worker&amp;quot;

const workers = [1, 2, 3, 4].map(id =&amp;gt; new Promise((resolve, reject) =&amp;gt; {
  const worker = new Worker(workerFileName, {
    workerData: {
      id,
      name: `Bob ${id}`
    }
  })

  worker.addListener(&amp;quot;message&amp;quot;, (result) =&amp;gt; resolve({ id, result }))
  worker.addListener(&amp;quot;error&amp;quot;, reject)
}))

async function main() {
  const results = await Promise.all(workers)
  console.log(results)
}

main()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Uncompiled Worker Using &lt;code&gt;ts-node&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;When executing workers it&apos;s also possible to execute the Typescript file directly instead of relying on the compilation. This can be useful for cases where the Javascript code is compiled to a single file or in situations where you don&apos;t have control over the execution environment&lt;/p&gt;
&lt;p&gt;Executing a Typescript worker can be done by using &lt;code&gt;ts-node&lt;/code&gt; when running the worker, an example of this is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const worker = new Worker(&amp;quot;my-worker.ts&amp;quot;, {
    execArgv: [&amp;quot;-r&amp;quot;, &amp;quot;ts-node/register&amp;quot;, &amp;quot;--no-warnings&amp;quot;],
    workerData: {
      id
    }
  })

// do stuff with the worker
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/api/worker_threads.html&quot;&gt;NodeJS Worker Threads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Web Workers and Vite</title><link>https://nabeelvalley.co.za/blog/2025/06-01/web-workers/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2025/06-01/web-workers/</guid><description>An overview of using Web Workers with Vite</description><pubDate>Mon, 06 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Snippet from &apos;@/components/Snippet.astro&apos;&lt;/p&gt;
&lt;p&gt;Web workers provide a mechanism for running code outside of the main thread using Javascript. They are currently supported in the browser as well as in Node.js, but for the purpose of this post we&apos;ll look at how to use them from within the browser&lt;/p&gt;
&lt;h2&gt;Vanilla&lt;/h2&gt;
&lt;p&gt;Web workers can be used directly from the browser using some script tags. For the sake of example, we&apos;ll use the following HTML file with it&apos;s related script tags:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/plain/index.html&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;In the above, we can see three scripts referenced, we&apos;ll take a look at these as we talk about the mechanisms for using web workers&lt;/p&gt;
&lt;h3&gt;Workers&lt;/h3&gt;
&lt;p&gt;Web workers are simply Javascript modules that are loaded by some other code dynamically as a &lt;code&gt;Worker&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we assume we have some worker called &lt;code&gt;simple-worker.js&lt;/code&gt; in the same directory of our page, we can load it using the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const worker = new Worker(&amp;quot;./simple-worker.js&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upon doing this, the &lt;code&gt;simple-worker.js&lt;/code&gt; script will be loaded and executed.&lt;/p&gt;
&lt;p&gt;Now, the real value of workers comes from the ability to get data from the code that launches it, this is done using &lt;code&gt;worker.postMessage&lt;/code&gt;, this allows us to send any data we want to the worker we have defined, so we can do this in our script, an example of this can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/plain/simple-worker-launcher.js&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;On the other side of this conversation we have the actual worker script/module. This actually looks really simple:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/plain/simple-worker.js&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;This file uses &lt;code&gt;self.addEventListener&lt;/code&gt; to listen to &lt;code&gt;messsage&lt;/code&gt;s sent to the worker, when a message is received, the worker can decide what to do with it - what&apos;s important to know is that this handler does not block the main thread so it can be as intensive as we want&lt;/p&gt;
&lt;p&gt;The worker can also be more complex, for example we can see in the below message that the worker receives a message via &lt;code&gt;self.addEventListener&lt;/code&gt;, after doing some intensive processing, it calls &lt;code&gt;self.postMessage&lt;/code&gt; to basically respond to the parent&lt;/p&gt;
&lt;p&gt;The parent can then listen to these messages with &lt;code&gt;worker.addEventListener&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/plain/worker-launcher.js&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;And we can see the worker that sends messages as well:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/plain/worker.js&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h3&gt;ServiceWorkers&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ServiceWorkers&lt;/code&gt; are a special kind of worker that acts as a proxy between the application and network and can interact with network requests even when the device is not connected to the server&lt;/p&gt;
&lt;p&gt;Service workers have different events that may be triggered, commonly is the &lt;code&gt;installed&lt;/code&gt;, &lt;code&gt;activated&lt;/code&gt;, and &lt;code&gt;fetch&lt;/code&gt; event among others, we add listners for these events the same as we did in the above&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/plain/service-worker.js&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;In the above file, we intercept requests to the &lt;code&gt;placeholder&lt;/code&gt; url and proxy it by making a new request to &lt;code&gt;https://placeholder.co&lt;/code&gt;, we could do anything here though, even responding with our own data if we want&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ServiceWorkers&lt;/code&gt; are special though since an application can only have a single &lt;code&gt;ServiceWorker&lt;/code&gt;. Creating a &lt;code&gt;ServiceWorker&lt;/code&gt; is done using &lt;code&gt;navigator.serviceWorker.register&lt;/code&gt; and not using &lt;code&gt;new Worker&lt;/code&gt;, an example of service worker registration can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/plain/register-service-worker.js&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Vite&lt;/h2&gt;
&lt;p&gt;In practice we&apos;re rarely using some random Javascript files though and often have more complex scenarios with external dependencies or even stuff like Typescript involved, in this case we need to consider things like bundling as well as somehow resolving the name of the file we need to load. Thankfully modern bundlers like Vite have a solution for us&lt;/p&gt;
&lt;p&gt;In the case of Vite specifically, it provides us with an API that we can use while importing files that Vite uses to infer that a file should be treated as a worker. Vite does this by using the &lt;code&gt;?worker&lt;/code&gt; at the end of the import path&lt;/p&gt;
&lt;p&gt;Assume we have some Vite-based project that uses a worker such as the one below. That worker also imports some code from another file we have and we expect it all to be bundled correctly:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/vite/src/canvas.worker.ts&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;We can see that we have a &lt;code&gt;run&lt;/code&gt; function that is called when we receive the &lt;code&gt;message&lt;/code&gt; as before, we also have a type specified for the data we expect to receive&lt;/p&gt;
&lt;p&gt;When we import something using &lt;code&gt;?worker&lt;/code&gt; Vite creates a constructor for us that will initialize the worker without us having to manually pass the path to the file, so a consumer of this file can now use the worker a bit like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import CanvasWorker from &apos;./canvas.worker?worker&apos;
import type { InvokeParams } from &apos;./canvas.worker&apos;

const worker = new CanvasWorker()

worker.postMessage({ canvas: offscreen } satisfies InvokeParams, [offscreen])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that we also use the &lt;code&gt;type&lt;/code&gt; import above so we can keep the type definition of the data our worker expects in the same palce as the worker&lt;/p&gt;
&lt;p&gt;A more full example of this can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;web-workers/vite/src/canvas.worker.ts&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;Something that&apos;s also interesting to note is the second parameter of &lt;code&gt;postMessage&lt;/code&gt;, this is an array of &lt;code&gt;TransferrableObjects&lt;/code&gt; that are specific objects that the browser allows us to share between the main thread and worker threads. In the above example we&apos;re using a &lt;code&gt;OffscreenCanvas&lt;/code&gt; but this can be any of the objects that are defined as &lt;code&gt;TransferrableObjects&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, web workers are pretty fun to play around with and really increase the options available to us when working to make applications more performant. Modern tools like Vite also make using them pretty easy&lt;/p&gt;
&lt;p&gt;There&apos;s a lot that you can do with workers and I&apos;ve simply provided you with a small overview of the functionality, looking at the MDN documentation is always a good place to go to learn more&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API&quot;&gt;MDN Web Workers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API&quot;&gt;MDN Service Workers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v3.vitejs.dev/guide/features.html#web-workers&quot;&gt;Web Workers in Vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/offscreen-canvas&quot;&gt;Speed up Canvas Operations with OffscreenCanvas&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Javascript Proxy Object</title><link>https://nabeelvalley.co.za/blog/2024/11-12/proxy-objects/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/11-12/proxy-objects/</guid><description>Basic introduction to proxies in Javascript/Typescript</description><pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Proxies allow us to wrap existing object and modify the behavior when interacting with them in some interesting ways. This post will take a look at a few things we can use them for&lt;/p&gt;
&lt;h2&gt;Something to work with&lt;/h2&gt;
&lt;p&gt;For the sake of this example we&apos;ll be using Typescript. Let&apos;s create a reference object type that we will interact with - we&apos;re going to call this &lt;code&gt;MyApi&lt;/code&gt; and it&apos;s defined simply as an object with a few methods on it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface MyApi {
  /**
   * Adds 2 numbers
   * @returns the result of addition
   */
  add: (a: number, b: number) =&amp;gt; number;

  /**
   * Difference between 2 numbers
   * @returns the result of subtraction
   */
  subtract: (a: number, b: number) =&amp;gt; number;

  /**
   * (secretly does some illegal stuff)
   */
  illegal: (a: number, b: number) =&amp;gt; number;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Initial implementation&lt;/h2&gt;
&lt;p&gt;We can implement a simple object that satisifies this APi as below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const baseApi: MyApi = {
  add(a, b) {
    return a + b;
  },

  subtract(a, b) {
    return a - b;
  },

  illegal(a, b) {
    return a / b;
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Log accesses&lt;/h2&gt;
&lt;p&gt;For this example we&apos;ll consider the &lt;code&gt;illegal&lt;/code&gt; method as special. We&apos;ll want to track each time the &lt;code&gt;illegal&lt;/code&gt; property is accessed. Using a &lt;code&gt;Proxy&lt;/code&gt; we can wrap the &lt;code&gt;baseApi&lt;/code&gt; and provide a &lt;code&gt;get&lt;/code&gt; method that will handle property access and allow us to see what property of our object is being accessed&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;illegal&lt;/code&gt; is accessed, we log out a message:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const logAccess = new Proxy&amp;lt;MyApi&amp;gt;(baseApi, {
  get(target, key: keyof MyApi) {
    if (key === &amp;quot;illegal&amp;quot;) {
      console.log(&amp;quot;Tried to access illegal method&amp;quot;);
    }

    // return the property from the original object
    return target[key];
  },
});

logAccess.illegal(1, 2);
// logs out the message before calling the function
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Prevent illegal access&lt;/h2&gt;
&lt;p&gt;We can also do stuff like create a type of &lt;code&gt;WithoutIllegal&lt;/code&gt; version of &lt;code&gt;MyApi&lt;/code&gt; in which we remove the property from the type definition. Additionally, we can also make this throw an error if someone attempts to access it at runtime as can be seen below. This is very similar to the previous example but now we have a direct impact on the consumer&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type WithoutIllegal&amp;lt;T&amp;gt; = Omit&amp;lt;T, &amp;quot;illegal&amp;quot;&amp;gt;;

const police = new Proxy&amp;lt;WithoutIllegal&amp;lt;MyApi&amp;gt;&amp;gt;(baseApi, {
  get(target, key: keyof MyApi) {
    if (key === &amp;quot;illegal&amp;quot;) {
      throw new Error(&amp;quot;accessing illegal properties is a crime&amp;quot;);
    }

    return target[key];
  },
});

try {
  // @ts-expect-error this is now an error since we say &amp;quot;illegal is not defined&amp;quot;
  police.illegal;

  // @ts-expect-error if we try to access it, it will throw
  police.illegal(1, 2);
} catch (err) {
  console.error(&amp;quot;Got illegal access&amp;quot;, err);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Interact with other objects&lt;/h2&gt;
&lt;p&gt;During the proxying process, we can also do things like interact with objects that aren&apos;t defined within our base object itself:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const logs: any[][] = [];
const withLogs = new Proxy&amp;lt;MyApi&amp;gt;(baseApi, {
  get&amp;lt;K extends keyof MyApi&amp;gt;(target: MyApi, key: K) {
    const method = target[key];

    return (a: number, b: number) =&amp;gt; {
      logs.push([&amp;quot;accessing&amp;quot;, key, a, b]);

      const result = method(a, b);

      logs.push([&amp;quot;result&amp;quot;, result]);

      return result;
    };
  },
});

withLogs.add(1, 2);
withLogs.subtract(1, 2);
withLogs.illegal(1, 2);

console.log(logs);
// [
//   [ &apos;accessing&apos;, &apos;add&apos;, 1, 2 ],
//   [ &apos;result&apos;, 3 ],
//   [ &apos;accessing&apos;, &apos;subtract&apos;, 1, 2 ],
//   [ &apos;result&apos;, -1 ],
//   [ &apos;accessing&apos;, &apos;illegal&apos;, 1, 2 ],
//   [ &apos;result&apos;, 0.5 ]
// ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Creating fake objects&lt;/h2&gt;
&lt;p&gt;We can also create an object in which &lt;em&gt;any&lt;/em&gt; properties can exist and have a specific value, for example an object that has this structure for any key given:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;{
    myKey: &amp;quot;myKey&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be done like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const fake = new Proxy&amp;lt;Record&amp;lt;string, Record&amp;lt;string, string&amp;gt;&amp;gt;&amp;gt;(
  {},
  {
    get(target, property) {
      return {
        [property]: property,
      };
    },
  }
);

console.log(fake);
// {}

console.log(fake.name);
// { name: &apos;name&apos; }

console.log(fake.age);
// { age: &apos;age&apos; }

console.log(fake.somethingelse);
// { somethingelse: &apos;somethingelse&apos; }
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;It&apos;s also interesting to note that the &lt;code&gt;fake&lt;/code&gt; object has no direct properties, and we cxan see that when we log it&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Recursive proxies&lt;/h2&gt;
&lt;p&gt;Proxies can also return other proxies. This allows us to proxy objects recursively. For example, given the following object:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const deepObject = {
  a: {
    b: {
      getC: () =&amp;gt; ({
        c: (x: number, y: number) =&amp;gt; ({
          answer: x + y,
        }),
      }),
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can create a proxy that tracks different actions, such as property acccess. Recursive proxies can be created by returning a new proxy at the levels that we care about. In the below example, we create a proxy for every property that we access as well as for the result of every function call:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const tracker: any[][] = [];
const createTracker = &amp;lt;T extends object&amp;gt;(obj: T, prefix: string = &amp;quot;&amp;quot;): T =&amp;gt; {
  return new Proxy&amp;lt;T&amp;gt;(obj, {
    apply(target, thisArg, argArray) {
      tracker.push([&amp;quot;call&amp;quot;, prefix, argArray]);

      const bound = (target as (...args: any[]) =&amp;gt; any).bind(thisArg);
      const result = bound(...argArray);

      tracker.push([&amp;quot;return&amp;quot;, prefix, result]);

      if (typeof result === &amp;quot;undefined&amp;quot;) {
        return result;
      }

      // create a new proxy around the object that&apos;s returned from a function call
      return createTracker(result, prefix);
    },

    get(_, prop: keyof T &amp;amp; string) {
      const path = `${prefix}/${prop}`;

      tracker.push([&amp;quot;accessed&amp;quot;, path]);
      const nxt = obj[prop];

      if (typeof nxt === &amp;quot;undefined&amp;quot;) {
        return nxt;
      }

      // create a new proxy around the object that&apos;s being accessed
      return createTracker(nxt as object, path);
    },
  });
};

const tracked = createTracker(deepObject);

const result = tracked.a.b.getC().c(1, 2);

console.log({ result });
// { result: { answer: 3 } }

console.log(tracker);
// [
//   [ &apos;accessed&apos;, &apos;/a&apos; ],
//   [ &apos;accessed&apos;, &apos;/a/b&apos; ],
//   [ &apos;accessed&apos;, &apos;/a/b/getC&apos; ],
//   [ &apos;call&apos;, &apos;/a/b/getC&apos;, [] ],
//   [ &apos;return&apos;, &apos;/a/b/getC&apos;, { c: [Function: c] } ],
//   [ &apos;accessed&apos;, &apos;/a/b/getC/c&apos; ],
//   [ &apos;call&apos;, &apos;/a/b/getC/c&apos;, [ 1, 2 ] ],
//   [ &apos;return&apos;, &apos;/a/b/getC/c&apos;, { answer: 3 } ]
// ]
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;References&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy&quot;&gt;MDN Proxy Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Conditionally Protect Properties in Typescript</title><link>https://nabeelvalley.co.za/blog/2024/03-12/conditional-protection/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/03-12/conditional-protection/</guid><description>Using type-guards to protect access to values</description><pubDate>Tue, 03 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Type Guards&lt;/h2&gt;
&lt;p&gt;So, type guards are really handy in Typescript as they let us check if something meets a certain requirement before moving along, for example, given the following user type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type User = {
  active: boolean;
  name: string;
  age: number;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can define a type guard that checks if the user is fully is &lt;code&gt;active&lt;/code&gt; before allowing certain things. To do this we usually use a type guard, that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ActiveUser = User &amp;amp; { active: true };

const isActive = (base: Partial&amp;lt;User&amp;gt;): base is ActiveUser =&amp;gt;
  !!(base.active &amp;amp;&amp;amp; base.age &amp;amp;&amp;amp; base.name);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important thing in a type guard is that it takes something of one type and asserts something about that type, e.g. that it is an &lt;code&gt;ActiveUser&lt;/code&gt; in the above. This is done by returning a boolean, if it is &lt;code&gt;true&lt;/code&gt; then the assertion applies, otherwise it does not&lt;/p&gt;
&lt;p&gt;And normally, we would use it like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;if (isActive(user)) {
    // do stuff that can only be done with an active user
}

// outside of this scope users are not active
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Gaurded Class&lt;/h2&gt;
&lt;p&gt;The above solution is usually good enough. But it&apos;s also possible to couple the types of these checks while not providing direct access to the underlying object. This is useful in cases where we may want to restrict access to some functionality unless a certain set of checks pass&lt;/p&gt;
&lt;p&gt;To do this, we can encapsulate the value and check into a class, e.g. the &lt;code&gt;Guarded&lt;/code&gt; class below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Guarded&amp;lt;Unsafe, Safe extends Unsafe&amp;gt; {
  constructor(
    protected readonly value: Unsafe,
    private readonly safe: (value: Unsafe) =&amp;gt; value is Safe,
  ) {}

  /**
   * Type guard that grants access to the wrapped `value`
   */
  isSafe(): this is { value: Safe } {
    return this.safe(this.value);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above, we define a &lt;code&gt;Guarded&lt;/code&gt; class htat has a type of a &lt;code&gt;Safe&lt;/code&gt; and &lt;code&gt;Unsafe&lt;/code&gt; value. These generics can be inferred by the arguments provided to &lt;code&gt;constructor&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Next, we define the &lt;code&gt;isSafe&lt;/code&gt; method on the class that is a gaurd that says something about &lt;code&gt;this&lt;/code&gt; which is the instance itself.&lt;/p&gt;
&lt;p&gt;So, we can use &lt;code&gt;Guarded&lt;/code&gt; to wrap something that we want to only make available under certain scenarios:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const guarded = new Guarded(value, isActive);

if (guarded.isSafe()) {
  console.log(&apos;Can access value here&apos;, guarded.value);
}

// guarded.value; // error: Property &apos;value&apos; is protected and only accessible within class &apos;Guarded&amp;lt;Unsafe, Safe&amp;gt;&apos; and its subclasses.ts(2445)
console.log(&amp;quot;Can&apos;t access value here&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What&apos;s great is that this &lt;code&gt;safe&lt;/code&gt; check is re-run whenever we want to access the &lt;code&gt;value&lt;/code&gt;, this means that we can make certain properties available based on some other state that can be checked in the &lt;code&gt;safe&lt;/code&gt; method&lt;/p&gt;
&lt;p&gt;This approach means that at compile time the Typescript compiler will check that we are only accessing &lt;code&gt;value&lt;/code&gt; within a context that we have defined to be okay by way of our &lt;code&gt;isSafe&lt;/code&gt; method. Additionally, since we can specify the behavior of &lt;code&gt;isSafe&lt;/code&gt; we end up with a a check that works at the intersection of compile-time and runtime&lt;/p&gt;
&lt;h2&gt;Note&lt;/h2&gt;
&lt;p&gt;The first idea of Type Guards is quite often used and should be good enough for normal use&lt;/p&gt;
&lt;p&gt;Withr egards to the &lt;code&gt;Guarded&lt;/code&gt; idea, use with caution. The idea here it to create a certain safety for consumers of some code, but this is at the expense of complexity and should be used with care. Outside of the &amp;quot;can it be done&amp;quot; discussion I haven&apos;t really had much use for something like this since usually a normal type guard is good enough&lt;/p&gt;
</content:encoded></item><item><title>Type safe URL templates</title><link>https://nabeelvalley.co.za/blog/2024/31-10/type-safe-url-templates/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/31-10/type-safe-url-templates/</guid><description>Making URL template replacements safe</description><pubDate>Thu, 31 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I don&apos;t think the below is a good idea, but I thought it was a fun little Typescript excercise so here you go&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Something I see as a sort of recurring pattern is people doing template replacements in URLs, particularly something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const template = &apos;/users/{userId}/projects/{projectId}&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, while you can more simply make this template a function like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const template = (userId:string, projectId:string) =&amp;gt; `/users/${userId}/projects/${projectId}`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For some reason people don&apos;t like to do that, I think it&apos;s that it looks like a lot of duplication and perhaps they just don&apos;t believe in making their own functions (who am I to know)&lt;/p&gt;
&lt;p&gt;More often than I&apos;d like, I instead see people doing this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const template = &apos;/users/{userId}/projects/{projectId}&apos;

// later
const url = template.replace(&apos;{userId}&apos;, userId).replace(&apos;{projectId}&apos;, projectId)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think this is horrible, and while it works, it&apos;s quite brittle and unless it&apos;s got some tests or other means of verifying that this works it&apos;s a really quick source of bugs for when things change, for example if you add or remove a parameter from the URL&lt;/p&gt;
&lt;p&gt;Now, I&apos;m a huge fan of using the compiler to derive as much correctness as possible, even before even really thinking about tests, so when looking at something like this all I can think is that the TypeScript compiler can solve this&lt;/p&gt;
&lt;p&gt;I&apos;m not saying that you should do what I&apos;m about to present here, I think you&apos;re probably better off using the method of a template being a simple function above, but I think it&apos;s a fun little mental excercise&lt;/p&gt;
&lt;h1&gt;The Typescriptssss&lt;/h1&gt;
&lt;p&gt;Firstly, we need to parse this URL template things, this is simple enough using a little recursive type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;/**
 * Extracts the keys from the URL
 */
type PathKeys&amp;lt;TUrl extends string&amp;gt; = 
    TUrl extends `${string}{${infer Param}}${infer Rest}` 
    ? Param | PathKeys&amp;lt;Rest&amp;gt; 
    : never
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, since in a URL all keys need to be a string at the end, we can define an object for URLs that uses this to define a record:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;/**
 * Uses the keys to define a record in which each key of the URL can be assigned to a string
 */
type PathParams&amp;lt;TUrl extends string&amp;gt; = Record&amp;lt;PathKeys&amp;lt;TUrl&amp;gt;, string&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A little test of the above types shows us:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Keys = PathKeys&amp;lt;&apos;/users/{userId}/projects/{projectId}&apos;&amp;gt;
//   ^? type Keys = &amp;quot;userId&amp;quot; | &amp;quot;projectId&amp;quot;

type Params = PathParams&amp;lt;&apos;/users/{userId}/projects/{projectId}&apos;&amp;gt;
//   ^? type Params = { userId: string; projectId: string; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So great, that works and we can use that as the basis for building up more general function for creating these &amp;quot;safe urls&amp;quot;&lt;/p&gt;
&lt;p&gt;Before we go there though, let&apos;s take a moment to think about the result of this URL. Now we could return the URL as a &lt;code&gt;string&lt;/code&gt; but since we&apos;re being strict it would be nice to inform downstream consumers of what this string is made up of. Using a very similar method to how the &lt;code&gt;PathKeys&lt;/code&gt; type was done we can create a type for the result of a URL where the params have been replaced&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;/**
 * Represents a URL in which all params have been substituted
 */
type ReplacedUrl&amp;lt;TUrl extends string&amp;gt; = 
    TUrl extends `${infer Base}{${infer _}}${infer Rest}` 
    ? `${Base}${string}${ReplacedUrl&amp;lt;Rest&amp;gt;}` 
    : TUrl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly, we can define the implementation of the URL replacer which is effectively just calling the &lt;code&gt;String.replace&lt;/code&gt; method on an input URL while using a strong type for the URL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const createTypedUrl = &amp;lt;const TUrl extends string&amp;gt;(url: TUrl) =&amp;gt; (params: PathParams&amp;lt;TUrl&amp;gt;) =&amp;gt; {
    return url.replace(/\{\w+\}/g, (val) =&amp;gt; {
        const key = val.slice(1,-1)
        return  (params as Record&amp;lt;string, string&amp;gt;)[key] || val
    }) as ReplacedUrl&amp;lt;TUrl&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const template = &apos;/users/{userId}/projects/{projectId}&apos; as const

/**
 * A little factory for making typed URLs from the given template
 */
const typedUrl = createTypedUrl(template)
//    ^? const typedUrl: (params: PathParams&amp;lt;&amp;quot;/users/{userId}/projects/{projectId}&amp;quot;&amp;gt;) =&amp;gt; string

const url = typedUrl({
    userId: &apos;123&apos;,
    projectId: &apos;456&apos;
})
// ^? const url: `/users/${string}/projects/${string}`

console.log(url) // &apos;/users/123/projects/456&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, is this better than random string replacements? Yes. Is it better than just using string interpolation? No.&lt;/p&gt;
&lt;p&gt;While this isn&apos;t something I recommend using I think the idea about thinking of underlying structure of common data types is important and something that&apos;s worth thinking about in order to define more complete solutions&lt;/p&gt;
&lt;p&gt;Lastly, if you&apos;re into this type of thing, take a look at some of my other TS shenanigans:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2024/16-08/optional-parameters-and-overloads-in-typescript&quot;&gt;Parameters, but only sometimes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2024/15-08/handling-complex-typescript-generics&quot;&gt;More generic than it should be&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2022/13-12/typescript-utilities&quot;&gt;Typescript Utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2023/09-05/generic-transformer-typescript&quot;&gt;Generic Object Property Formatter and Validator using Typescript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>week 40, year 2024 - paper and pictures</title><link>https://nabeelvalley.co.za/blog/2024/06-10/week-40-paper-and-pictures/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/06-10/week-40-paper-and-pictures/</guid><pubDate>Sun, 06 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;firstly, a small sadness - i missed the past two posts due to my vacation, but on the other hand i guess i had a vacation so that works out i suppose&lt;/p&gt;
&lt;h2&gt;what i&apos;m working on&lt;/h2&gt;
&lt;p&gt;spent the past week mostly working on a talk that i&apos;m (hopefully) going to be doing towards the end of the month, i also gave a little &lt;a href=&quot;https://nabeelvalley.co.za/talks/2024/03-10/a-nu-er-shell/&quot;&gt;intro presentation on nushell&lt;/a&gt; that I think went pretty well&lt;/p&gt;
&lt;h2&gt;what i found&lt;/h2&gt;
&lt;p&gt;this week i&apos;m going to be sharing a few sites i&apos;ve come across of people doing interesting things&lt;/p&gt;
&lt;h3&gt;paper engineering&lt;/h3&gt;
&lt;p&gt;Julia Yus makes really interesting things out of paper and &lt;a href=&quot;https://juliayus.com&quot;&gt;her portfolio&lt;/a&gt; is a really window into the things that you wouldn&apos;t have thought were possible with paper&lt;/p&gt;
&lt;h3&gt;fashion photography&lt;/h3&gt;
&lt;p&gt;George Morris is a London based photographer and director with &lt;a href=&quot;https://www.george-morris.com&quot;&gt;a portfolio of images and videos&lt;/a&gt; focused on some campaigns that he&apos;s done&lt;/p&gt;
&lt;h3&gt;street photography&lt;/h3&gt;
&lt;p&gt;Eric Anderson is a photographer and web designer with a particularly great &lt;a href=&quot;https://www.esquareda.com&quot;&gt;portfolio of street photography&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>week 37, year 2024 - ui paradigms and comic books</title><link>https://nabeelvalley.co.za/blog/2024/15-09/week-37-ui-paradigms-and-comic-books/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/15-09/week-37-ui-paradigms-and-comic-books/</guid><pubDate>Sun, 15 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;between doomscrolling and visiting &lt;a href=&quot;https://www.foam.org/?gad_source=1&amp;amp;gclid=Cj0KCQjwi5q3BhCiARIsAJCfuZkTCodlHCRjT5oZANFRotVr8C131p7Ad5DIjty3-1DrBP9PqkiXSPcaAkJmEALw_wcB&quot;&gt;FOAM&lt;/a&gt; there was barely any time to put something together but here we go&lt;/p&gt;
&lt;h1&gt;what i found&lt;/h1&gt;
&lt;p&gt;i spent a decent amount of time comparing different ways of doing the same things. recently i&apos;ve been thinking about ui state management, but first - some art&lt;/p&gt;
&lt;h2&gt;mœbius&lt;/h2&gt;
&lt;p&gt;mœbius is the pseudonym of &lt;a href=&quot;https://en.wikipedia.org/wiki/Jean_Giraud&quot;&gt;Jean Henri Gaston Giraud&lt;/a&gt; who was a french cartoonist. i&apos;ve found &lt;a href=&quot;https://www.iamag.co/the-art-of-moebius/&quot;&gt;his work&lt;/a&gt; fascinating for quite some time. the level of detail packed into each frame is astonishing&lt;/p&gt;
&lt;h2&gt;state management&lt;/h2&gt;
&lt;p&gt;ui state is always something where there are an infinite number of solutions, each with their own drawbacks or drawfronts (of course that&apos;s the opposite right?)&lt;/p&gt;
&lt;h3&gt;reactive programming&lt;/h3&gt;
&lt;p&gt;something old to get us started. i think reactive programming (using things like RxJS or hand-rolled equivalents) give us a good starting point for managing state and &lt;a href=&quot;https://gist.github.com/staltz/868e7e9bc2a7b8c1f754&quot;&gt;this gist by André Staltz&lt;/a&gt; looks like a nice intro to the topic&lt;/p&gt;
&lt;h3&gt;signals&lt;/h3&gt;
&lt;p&gt;i came across a library called &lt;a href=&quot;https://github.com/adamhaile/S&quot;&gt;S.js&lt;/a&gt; which is one of the earlier signal implementations around and works with a jsx based framework called &lt;a href=&quot;https://github.com/adamhaile/surplus&quot;&gt;surplus&lt;/a&gt;. both of which are made by Adam Haile and last updated about 6 years ago (so probably don&apos;t pitch this during standup on monday)&lt;/p&gt;
&lt;p&gt;if you&apos;re looking for a more modern implementation of signals, your favourite framework probably has something: &lt;a href=&quot;https://angular.dev/guide/signals&quot;&gt;angular&lt;/a&gt; - and &lt;a href=&quot;https://github.com/preactjs/signals&quot;&gt;a bunch of other stuff&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;state machines&lt;/h3&gt;
&lt;p&gt;when talking about state management i always like to put &lt;a href=&quot;https://xstate.js.org/&quot;&gt;xstate&lt;/a&gt; on the table since it&apos;s a really handy library with some great developer experience and tooling built in. &lt;a href=&quot;https://nabeelvalley.co.za/blog/2023/31-01/xstate-draggable-div/&quot;&gt;i wrote a little intro&lt;/a&gt; a while back if you&apos;d like to get a feel for the library as well&lt;/p&gt;
&lt;h3&gt;strictness&lt;/h3&gt;
&lt;p&gt;something more obscure. i find the approach of &lt;a href=&quot;https://elm-lang.org/&quot;&gt;elm&lt;/a&gt; for ui quite interesting and is outlined in &lt;a href=&quot;https://guide.elm-lang.org/architecture/&quot;&gt;the elm architecture&lt;/a&gt;. i first came across it in &lt;a href=&quot;https://zaid-ajaj.github.io/the-elmish-book/#/&quot;&gt;the elmish book&lt;/a&gt; which presents this method for building interfaces using &lt;a href=&quot;https://fsharp.org/&quot;&gt;f#&lt;/a&gt; and &lt;a href=&quot;https://fable.io/&quot;&gt;fable&lt;/a&gt; which is compiler that turns f# into javascript.&lt;/p&gt;
</content:encoded></item><item><title>week 36, year 2024 - pretty printing</title><link>https://nabeelvalley.co.za/blog/2024/08-09/week-36-pretty-printing/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/08-09/week-36-pretty-printing/</guid><pubDate>Sun, 08 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;this week has been a little insane so i&apos;m actually amazed i&apos;ve found 5 mins to put this together&lt;/p&gt;
&lt;h1&gt;what i found&lt;/h1&gt;
&lt;p&gt;spent some time playing around with two little projects, one of which are pretty useful and the other is somewhat conceptual&lt;/p&gt;
&lt;h2&gt;delta&lt;/h2&gt;
&lt;p&gt;this is a &lt;a href=&quot;https://github.com/dandavison/delta&quot;&gt;cli tool for better git diffs&lt;/a&gt; and provides syntax highlighting for your git diff and some git commands. it&apos;s also written in rust if you care about that sort of thing&lt;/p&gt;
&lt;h2&gt;fancy fonts&lt;/h2&gt;
&lt;p&gt;i also came across a &lt;a href=&quot;https://kuanwh.com/markdown-font/&quot;&gt;font which renders markdown as rich text&lt;/a&gt; using some fancy font features. it&apos;s a little glitchy but really cool that this works without any JS&lt;/p&gt;
&lt;p&gt;additionally, there&apos;s also &lt;a href=&quot;https://blog.glyphdrawing.club/font-with-built-in-syntax-highlighting/&quot;&gt;this font which does syntax highlighting&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;overall, fonts are getting pretty cool these days. &lt;a href=&quot;https://developer.chrome.com/blog/colrv1-fonts&quot;&gt;the chrome devblog has a cool bit about colrv1 fonts&lt;/a&gt; which let us do some pretty fancy things too&lt;/p&gt;
&lt;p&gt;it&apos;s also worth taking at &lt;a href=&quot;https://x.com/JohannesMutter/status/1824948096205459903&quot;&gt;this thread&lt;/a&gt; which has some links to font related stuff worth checking out&lt;/p&gt;
</content:encoded></item><item><title>week 35, year 2024 - datetimes and logic programming</title><link>https://nabeelvalley.co.za/blog/2024/01-09/week-35-datetimes-and-logic-programming/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/01-09/week-35-datetimes-and-logic-programming/</guid><pubDate>Sun, 01 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;what i&apos;m working on&lt;/h2&gt;
&lt;p&gt;after many months i spent some time on a project i&apos;m working with a friend to build a sort of &amp;quot;home cloud&amp;quot; platform. it&apos;s always weird coming to a project having no clue where you left it and trying to stitch some context from whatever happens when you run &lt;code&gt;pnpm start&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;i also found a handy little way to &lt;a href=&quot;https://nabeelvalley.co.za/blog/2024/28-08/open-terminal-links-in-vscode/&quot;&gt;open links from the vscode terminal&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;what i found&lt;/h2&gt;
&lt;p&gt;i spent a little time learning about logic programming and came across an interesting talk about some of the challenges when writing libraries&lt;/p&gt;
&lt;h3&gt;prolog&lt;/h3&gt;
&lt;p&gt;a logic programming language - super weird but &lt;a href=&quot;https://www.youtube.com/watch?v=G_eYTctGZw8&quot;&gt;this talk on prolog by Michael Hendricks&lt;/a&gt; helped shed some light on how this is something that&apos;s actually usable&lt;/p&gt;
&lt;h3&gt;standard libraries&lt;/h3&gt;
&lt;p&gt;i also came across a great talk about some challenges when maintaining something like &lt;a href=&quot;https://www.youtube.com/watch?v=lxoKilLSJ4k&quot;&gt;the kotlin standard library by Vsevolod Tolstopyatov&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>An unexpected way to open links in the terminal</title><link>https://nabeelvalley.co.za/blog/2024/28-08/open-terminal-links-in-vscode/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/28-08/open-terminal-links-in-vscode/</guid><description>A little shortcut for opening terminal links in VSCode</description><pubDate>Wed, 28 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I accidentally hit &lt;code&gt;cmd + shift + o&lt;/code&gt; while in the terminal on VSCode which popped open a little window to navigate to the links to files that were currently printed out in my terminal - this seems like a more keyboard friendly way to do &lt;code&gt;cmd + click&lt;/code&gt; on a link in the terminal&lt;/p&gt;
&lt;p&gt;Upon further investigation it looks like the following is a thing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When in the terminal, after running some command&lt;/li&gt;
&lt;li&gt;Find a link (URL or file) that you want to open&lt;/li&gt;
&lt;li&gt;Use the command pallette with &lt;code&gt;cmd + shift + p&lt;/code&gt; and use the &lt;code&gt;Terminal: Open Detected Link ...&lt;/code&gt; command&lt;/li&gt;
&lt;li&gt;Browse the links, if it&apos;s a file you&apos;ll automatically preview the file, click enter to select a file or link to open&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tadaa, that&apos;s about it - an accidental shortcut that I&apos;ll most definitely be using in the future&lt;/p&gt;
</content:encoded></item><item><title>A Visual Language for Image Manipulation</title><link>https://nabeelvalley.co.za/blog/2024/24-08/unintentionally-made-a-programming-language/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/24-08/unintentionally-made-a-programming-language/</guid><description>I accidentally created a programming language for editing photos</description><pubDate>Sat, 24 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve spent the past few weeks building a concept photo editing application that allows users to visually define and compose shaders to transform an image in ways that are really challenging or impossible in other image manipulation software&lt;/p&gt;
&lt;p&gt;For readers of my website it&apos;s probably not too much of a surprise that I&apos;ve been spending a lot of time learning about &lt;a href=&quot;/blog/20-07/parser-combinators-and-gleam&quot;&gt;Parser Combinators&lt;/a&gt; as well as &lt;a href=&quot;/docs/shaders/intro-to-shaders&quot;&gt;Shaders&lt;/a&gt;. Armed with this information, it looks like I accidentally created a Visual Programming Language - this post will talk about how that all works&lt;/p&gt;
&lt;h2&gt;Why&lt;/h2&gt;
&lt;p&gt;Every time I&apos;ve shown anyone the app the first question was &amp;quot;Why do you need this?&amp;quot;. I think it&apos;s fair to say that no one &lt;em&gt;really&lt;/em&gt; &lt;strong&gt;needs&lt;/strong&gt; this. This exists to satisfy the artistic urge to do create something new. I&apos;ve spent so much time feeling limited by the tools I have for working with images are lacking in creative expression. I think there&apos;s an intersection between computational/generative art and photography that&apos;s underserved and it&apos;s a space I would like to play in. I wanted to create a tool that allows creative &lt;strong&gt;exploration&lt;/strong&gt; of images and helps break away from the &amp;quot;filter&amp;quot; based approach that dominates how we edit images&lt;/p&gt;
&lt;p&gt;It also seemed like a challenge, it begged to be done.&lt;/p&gt;
&lt;h2&gt;The App&lt;/h2&gt;
&lt;p&gt;The high level architecture that makes this all work looks something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I define different types of functions that can be applied to an image using a shader function written in &lt;strong&gt;WebGPU&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The shader is then parsed into a &lt;strong&gt;Node&lt;/strong&gt; that a user can use in the editing workflow&lt;/li&gt;
&lt;li&gt;A user can structure &lt;strong&gt;Nodes&lt;/strong&gt; and &lt;strong&gt;Edges&lt;/strong&gt; into a tree for applying edits&lt;/li&gt;
&lt;li&gt;The tree is compiled into shader code and inputs to the shader (&lt;strong&gt;Bindings/Uniforms&lt;/strong&gt;) are identified&lt;/li&gt;
&lt;li&gt;The final shader is applied to image and is updated when a user modifies any &lt;strong&gt;Bindings&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Shaders&lt;/h2&gt;
&lt;p&gt;Shaders are programs that run on the GPU. Due to this fact there are some interesting limitations on how shaders work and what they can do. For working in our application a shader consists of two parts, a &lt;strong&gt;Vertex Shader&lt;/strong&gt; and a &lt;strong&gt;Fragment Shader&lt;/strong&gt;. The Vertex Shader is related to objects that are being rendered in a scene, since we&apos;re rendering an image this isn&apos;t of too much consequence, and for our purposes this always looks the same:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgpu&quot;&gt;struct VertexOutput {
  @builtin(position) position: vec4f,
  @location(0) texcoord: vec2f,
};


@node fn vs(
  @builtin(node_index) nodeIndex : u32
) -&amp;gt; VertexOutput {
  const pos = array(
    vec2( 1.0,  1.0),
    vec2( 1.0, -1.0),
    vec2(-1.0, -1.0),
    vec2( 1.0,  1.0),
    vec2(-1.0, -1.0),
    vec2(-1.0,  1.0),
  );

  var vsOutput: VertexOutput;

  let xy = pos[nodeIndex];
  vsOutput.texcoord = pos[nodeIndex] * vec2f(0.5, 0.5) + vec2f(0.5);
  vsOutput.position = vec4f(pos[nodeIndex], 0, 1);

  return vsOutput;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The data output from the Vertex shader is sent to the Fragment shader. We&apos;ve defined a struct for the data I want to pass called &lt;code&gt;VertexOutput&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The Fragment shader is where things get interesting though. This is where I apply transformations to pixel data and it allows us to do stuff to our image. For now I&apos;ve defined the main part of our Fragment shader as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgpu&quot;&gt;@group(0) @binding(0) var ourSampler: sampler;
@group(0) @binding(1) var ourTexture: texture_2d&amp;lt;f32&amp;gt;;

// BINDINGS_SECTION_START
// BINDINGS_SECTION_END

@node fn sample(texcoord: vec2f) -&amp;gt; vec4f {
  return textureSample(ourTexture, ourSampler, texcoord);
}

@fragment fn fs(fsInput: VertexOutput) -&amp;gt; @location(0) vec4f {
  var input__result = fsInput;
  // MAIN_SECTION_START
  return textureSample(ourTexture, ourSampler, fsInput__result.texcoord);
  // MAIN_SECTION_END
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above I have also defined a function called &lt;code&gt;sample&lt;/code&gt; which has the &lt;code&gt;@node&lt;/code&gt; decorator - this is important - our app will use this decorator to identify methods that will be available in the UI that can be applied to images. The &lt;code&gt;sample&lt;/code&gt; decorator simply gets the color of a pixel in the input for a given coordinate. In fragment shader I need to output a color as denoted by the return type of the &lt;code&gt;fs&lt;/code&gt; function&lt;/p&gt;
&lt;p&gt;From the perspective of a shader our goal is to provide a library of functions that apply transformations that users can compose to apply an edit to an image, a simple example of this are the &lt;code&gt;splitChannels&lt;/code&gt; and &lt;code&gt;combineChannels&lt;/code&gt; functions that we can see below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgpu&quot;&gt;struct SplitChannelsOutput {
  r: f32,
  g: f32,
  b: f32,
  a: f32,
};

@node fn splitChannels(color: vec4f) -&amp;gt; SplitChannelsOutput {
  var output: SplitChannelsOutput;

  output.r = color.r;
  output.g = color.g;
  output.b = color.b;
  output.a = color.a;

  return output;
}

@node fn combineChannels(r: f32, g: f32, b: f32, a: f32) -&amp;gt; vec4f {
  return vec4f(r, g, b, a);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above methods can be composed in interesting ways to do things like swap around the green and blue channels of an image:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgpu&quot;&gt;@fragment fn fs(fsInput: VertexOutput) -&amp;gt; @location(0) vec4f {
    var split = splitChannels(color);
    var result = combineChannels(color.r, color.b, color.g, color.a);
    return result;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So this is the basic concept, a bit of complexity comes in when we consider that it&apos;s possible that a function may want inputs from multiple other functions but this still doesn&apos;t create too much of a hurdle for us as we&apos;ll discuss later&lt;/p&gt;
&lt;h2&gt;Parsing&lt;/h2&gt;
&lt;p&gt;I wanted to ensure that the application has a single source of truth for the available functions. In order to do this I wanted to use the shader to inform us as to what functions should be available for a user. In order to do this I had to create a parser for the WebGPU langauge. The parser I built is a little simplified since there are only certain things I care about when parsing the shader. It&apos;s also optimized for maintenance and probably isn&apos;t very fast. My main goal here was to get something working. I wrote the parser using a library called &lt;a href=&quot;https://github.com/microsoft/ts-parsec&quot;&gt;&lt;code&gt;ts-parsec&lt;/code&gt;&lt;/a&gt; which lets me define parsers using parser combinators.&lt;/p&gt;
&lt;p&gt;Defining a parser using this library requires a list of tokens to be defined using regexes. Below are the tokens I currently have defined:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;enum Tok {
  Var = &apos;Var&apos;,
  Let = &apos;Let&apos;,
  Const = &apos;Const&apos;,
  Struct = &apos;Struct&apos;,
  Return = &apos;Return&apos;,
  Fn = &apos;Fn&apos;,
  At = &apos;At&apos;,
  Arrow = &apos;Arrow&apos;,
  Integer = &apos;Integer&apos;,
  Comma = &apos;Comma&apos;,
  Dot = &apos;Dot&apos;,
  Plus = &apos;Plus&apos;,
  Semicolon = &apos;Semicolon&apos;,
  Colon = &apos;Colon&apos;,
  Dash = &apos;Dash&apos;,
  Asterisk = &apos;Asterisk&apos;,
  Slash = &apos;Slash&apos;,
  Equal = &apos;Equal&apos;,
  OpenParen = &apos;OpenParen&apos;,
  CloseParen = &apos;CloseParen&apos;,
  OpenBrace = &apos;OpenBrace&apos;,
  CloseBrace = &apos;CloseBrace&apos;,
  OpenBracket = &apos;OpenBracket&apos;,
  CloseBracket = &apos;CloseBracket&apos;,
  OpenAngle = &apos;OpenAngle&apos;,
  CloseAngle = &apos;CloseAngle&apos;,
  Identifier = &apos;Identifier&apos;,
  Space = &apos;Space&apos;,
  Comment = &apos;Comment&apos;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Along with the tokenizer. Each token is configured as &lt;code&gt;[shouldKeepToken, regex, token]&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export const tokenizer = ts.buildLexer([
  [true, /^var/g, Tok.Var],
  [true, /^let/g, Tok.Let],
  [true, /^const/g, Tok.Const],
  [true, /^struct /g, Tok.Struct],
  [true, /^fn/g, Tok.Fn],
  [true, /^return/g, Tok.Return],
  [true, /^-&amp;gt;/g, Tok.Arrow],
  [true, /^@/g, Tok.At],
  [true, /^,/g, Tok.Comma],
  [true, /^\./g, Tok.Dot],
  [true, /^\+/g, Tok.Plus],
  [true, /^\;/g, Tok.Semicolon],
  [true, /^\:/g, Tok.Colon],
  [true, /^\-/g, Tok.Dash],
  [true, /^\*/g, Tok.Asterisk],
  [true, /^\//g, Tok.Slash],
  [true, /^\=/g, Tok.Equal],
  [true, /^\(/g, Tok.OpenParen],
  [true, /^\)/g, Tok.CloseParen],
  [true, /^\{/g, Tok.OpenBrace],
  [true, /^\}/g, Tok.CloseBrace],
  [true, /^\[/g, Tok.OpenBracket],
  [true, /^\]/g, Tok.CloseBracket],
  [true, /^\&amp;lt;/g, Tok.OpenAngle],
  [true, /^\&amp;gt;/g, Tok.CloseAngle],

  [true, /^\d+?/g, Tok.Integer],
  [true, /^[A-Za-z]+([A-Za-z0-9_]*)/g, Tok.Identifier],
  [false, /^\s+/g, Tok.Space],
  [false, /^\/\/ .*/g, Tok.Comment],
])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that I throw away comments and spaces since I don&apos;t care about these for now&lt;/p&gt;
&lt;p&gt;A relatively simple parser that I have is&lt;/p&gt;
&lt;p&gt;All parsers in my application are defined using classes to just help keep things a little tidy. One of the simpler parsers I have is the one that parses integers and is defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export class Integer {
  constructor(public value: number) {}

  static parser = ts.apply(ts.tok(Tok.Integer), (t) =&amp;gt; new Integer(+t.text))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This consists of a constructor for defining the members and a &lt;code&gt;static parser&lt;/code&gt; function which defines a parser for the current class. We can compose these parsers to build more complex ones, for example the way I parse &lt;code&gt;Generic&lt;/code&gt; uses &lt;code&gt;Integer&lt;/code&gt; for an optional &lt;code&gt;length&lt;/code&gt; that a generic may have, for example &lt;code&gt;array&amp;lt;f32, 3&amp;gt;&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export class Generic {
  constructor(
    public type: TypeDeclaration,
    public length?: Integer,
  ) {}

  static parser = ts.apply(
    ts.kmid(
      ts.tok(Tok.OpenAngle),
      ts.seq(
        TypeDeclaration.parser,
        ts.opt(ts.kright(ts.tok(Tok.Comma), Integer.parser)),
      ),
      ts.tok(Tok.CloseAngle),
    ),
    (matches) =&amp;gt; new Generic(...matches),
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The composition of these parses results in a tree looking something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;TypeDeclaration {
  &amp;quot;generic&amp;quot;: Generic {
    &amp;quot;length&amp;quot;: Integer {
      &amp;quot;value&amp;quot;: 5,
    },
    &amp;quot;type&amp;quot;: TypeDeclaration {
      &amp;quot;generic&amp;quot;: undefined,
      &amp;quot;identifier&amp;quot;: Identifier {
        &amp;quot;name&amp;quot;: &amp;quot;i32&amp;quot;,
      },
    },
  },
  &amp;quot;identifier&amp;quot;: Identifier {
    &amp;quot;name&amp;quot;: &amp;quot;array&amp;quot;,
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At a high level, we can apply this to the entire file to get a syntax tree for the whole file, but as you can imagine that starts to get much bigger&lt;/p&gt;
&lt;h2&gt;The UI&lt;/h2&gt;
&lt;p&gt;Now, since I&apos;m able to parse the file, I can extract the functions from it and use that to define the different things a user can do in the UI. A simple example of some UI that uses the &lt;code&gt;sample&lt;/code&gt; function defined previously can be seen below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./sample.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this we are able to define Nodes that have certain inputs and outputs which can be connected to each other. Each node is a function call and each edge refers to using the result of one function as an input to another function. When defining connections it&apos;s important to verify that connections are of the same type and don&apos;t create a cycle in any way - while fiddly, the code to do this isn&apos;t particularly interesting&lt;/p&gt;
&lt;p&gt;This step is actually relatively simple, the complexity comes into converting this back to the WebGPU code.&lt;/p&gt;
&lt;h2&gt;Compiling&lt;/h2&gt;
&lt;p&gt;This tree structure effectively represents a &lt;strong&gt;Dependency Graph&lt;/strong&gt; where all functions depend on their inputs, and the final &lt;code&gt;output&lt;/code&gt; node depends on any previous edges. The goal in this step is to build a tree out of the nodes and edges and then sort this in a way that defines the order that different operations need to be applied to obtain the &lt;code&gt;output&lt;/code&gt; value&lt;/p&gt;
&lt;p&gt;The first step to this is compiling a list of &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;edges&lt;/code&gt; into a &lt;code&gt;tree&lt;/code&gt;. I&apos;ve done this using the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface ReadonlyOrderedMap&amp;lt;T&amp;gt; extends ReadonlyMap&amp;lt;Id, T&amp;gt; {
  orderedValues(): ReadonlyArray&amp;lt;T&amp;gt;
  orderedKeys(): ReadonlyArray&amp;lt;Id&amp;gt;
}

/**
 * Wraps the builtin `Map` with an easy way to get keys and values as an array
 * sorted by the original insertion order
 *
 * @see MDN: [Map is insertion-order aware](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
 */
class OrderedMap&amp;lt;T&amp;gt; extends Map&amp;lt;Id, T&amp;gt; implements ReadonlyOrderedMap&amp;lt;T&amp;gt; {
  orderedValues() {
    return Array.from(this.values())
  }

  orderedKeys() {
    return Array.from(this.keys())
  }
}

export function buildTree&amp;lt;T extends Node, E extends Edge&amp;gt;(
  nodes: T[],
  edges: E[],
): OrderedMap&amp;lt;Connected&amp;lt;T, E&amp;gt;&amp;gt; {
  const map = new OrderedMap&amp;lt;Connected&amp;lt;T, E&amp;gt;&amp;gt;()

  for (const node of nodes) {
    map.set(node.id, { ...node, connections: [] })
  }

  for (const edge of edges) {
    const from = map.get(edge.from)
    const to = map.get(edge.to)

    if (from &amp;amp;&amp;amp; to) {
      from.connections.push([edge, to])
    }
  }

  return map
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This helps us go from the list of connections to a tree that represents the relationships between the nodes - this looks pretty much the same as the UI from earlier&lt;/p&gt;
&lt;p&gt;Next, we need to sort the nodes in an order that ensures that each node comes after any nodes that it depends on, this is called a &lt;strong&gt;Topographic Sort&lt;/strong&gt; and I&apos;ve loosely implemented it as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;/**
 * Does a depth-first search on the input vertices relative to the given ID.
 *
 * @returns a map of the nodes reachable from
 */
export function topologicalSort&amp;lt;T extends Vertex, E extends Edge&amp;gt;(
  vertices: ReadonlyMap&amp;lt;Id, Connected&amp;lt;T, E&amp;gt;&amp;gt;,
  relative: Id,
) {
  const visited = new OrderedMap&amp;lt;Connected&amp;lt;T, E&amp;gt;&amp;gt;()

  const rec = (at: Connected&amp;lt;T, E&amp;gt;) =&amp;gt; {
    if (visited.has(at.id)) return

    for (const [_, child] of at.connections) rec(child)

    // Insert self after all children have been inserted to maintain ordering
    visited.set(at.id, at)
  }

  const initial = vertices.get(relative)
  if (!initial) {
    console.error(&apos;Relative node not in tree&apos;, relative, vertices)
    throw new Error(&apos;Relative node not provided&apos;)
  }

  rec(initial)
  return visited
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this function, I can transform the earlier example for sampling an image into a list that looks something like &lt;code&gt;[input, sample, output]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;What&apos;s nice is that this will also work with a more complicated set of connections like so:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./complex.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Can be compiled into &lt;code&gt;[input, sample, splitChannels, combineChannels, brighten, output]&lt;/code&gt;. It&apos;s worth taking a moment to let this idea sink in because this is the core idea that allows us to compile the UI based language into a shader&lt;/p&gt;
&lt;p&gt;Once we are able to order our nodes, it&apos;s a simple matter of iterating through them in order and determining which inputs are needed and which functions these nodes refer to, the output of this looks something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgpu&quot;&gt;@fragment fn fs(fsInput: VertexOutput) -&amp;gt; @location(0) vec4f {
    var value1 = sample(input.texcoord);
    var value2 = splitChannels(value1);
    var value3 = combineChannels(value2.g, value2.r, value2.b, value2.a);
    var value4 = brighten(value3, value2.b);
    return value4;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;User Input&lt;/h2&gt;
&lt;p&gt;So, it&apos;s all well and good that I can compile a shader, but as I have it right now a user can&apos;t really customize what any of these values do. It would be nice if I could allow users to provide some input to the shader. For this we will use a &lt;strong&gt;uniform&lt;/strong&gt; which is basically an input to the GPU. Uniforms are nice because we can change them without having to recompile the shader&lt;/p&gt;
&lt;p&gt;For my purpose, I can infer that any input to a node that is not specified is meant to be set by the user, we can depict this using some kind of input field for that value, in the example below we use a range input for a &lt;code&gt;f32&lt;/code&gt; value, this can be set by the user:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./input.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Then, when compiling our nodes, we can extract this to a &lt;code&gt;binding&lt;/code&gt;, which would look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgpu&quot;&gt;@group(1) @binding(0) var&amp;lt;uniform&amp;gt; combineChannelsInputB: f32;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that can be used in the fragment shader as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-wgpu&quot;&gt;@fragment fn fs(fsInput: VertexOutput) -&amp;gt; @location(0) vec4f {
    var value1 = sample(input.texcoord);
    var value2 = splitChannels(value1);
    var value3 = combineChannels(value2.g, value2.r, combineChannelsInputB, value2.a);
    var value4 = brighten(value3, value2.b);
    return value4;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, actually passing this value to the shader is a bit messy but really comes down to using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API&quot;&gt;WebGPU API&lt;/a&gt;. This effectively involves creating a &lt;code&gt;bindGroup&lt;/code&gt; adding &lt;code&gt;buffers&lt;/code&gt; which hold the value of the data&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const dynamicBuffers: Record&amp;lt;BindingId, GPUBuffer&amp;gt; = {}

const entries: GPUBindGroupEntry[] = []
for (const { id, bindings } of shader.compiled.compiledNodes) {
  for (const binding of bindings) {
    const buffer = device.createBuffer({
      size: binding.size,
      usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
      label: &apos;dynamic binding for: &apos; + binding.declaration,
    })

    buffer.unmap()

    entries.push({
      binding: binding.binding,
      resource: {
        buffer,
      },
    })

    dynamicBuffers[`${id}.${binding.name}`] = buffer
  }
}

const dynamicBindGroup =
  entries.length &amp;amp;&amp;amp;
  device.createBindGroup({
    label: &apos;dynamic bind group&apos;,
    layout: pipeline.getBindGroupLayout(1),
    entries,
  })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whenever the user changes some input the buffer values can be updates like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;for (const [groupId, group] of Object.entries(data || {})) {
  for (const [bindingId, value] of Object.entries(group || {})) {
    const buffer = dynamicBuffers[`${groupId}.${bindingId}`]
    if (buffer) {
      device.queue.writeBuffer(buffer, 0, value)
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, there are some finicky bits involved in assembling all the data here but these are the important bits around using the API&lt;/p&gt;
&lt;h2&gt;Closing&lt;/h2&gt;
&lt;p&gt;As you can see there are quite a few moving pieces but I feel like the approach I&apos;ve taken here fits the problem relatively well. As things are defined now, all app functionality is driven by what is available in the shader and the different nodes can be inferred and combined however the user wants&lt;/p&gt;
&lt;p&gt;This isn&apos;t the end though. There&apos;s a lot more to do, and a lot of art to be made&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;The most important resource in making this work is defintely the &lt;a href=&quot;https://webgpufundamentals.org/&quot;&gt;WebGPU Fundamentals Site&lt;/a&gt;. The UI is inspired by &lt;a href=&quot;https://www.blender.org/&quot;&gt;Blender&apos;s&lt;/a&gt; Node Editor and is implemented using &lt;a href=&quot;https://reactflow.dev/&quot;&gt;React Flow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For the purpose of implementation, I&apos;ve also looked at loads of different things, of notable value were the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/WGSL&quot;&gt;WGSL Spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webgpufundamentals.org/&quot;&gt;WebGPU Fundamentals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alain.xyz/&quot;&gt;Alan Galvan&apos;s Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://maximmcnair.com/&quot;&gt;Maxim McNair&apos;s Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=vPEiCNjjjFU&quot;&gt;WebGPU Course by GetIntoGameDev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/topological-sorting/&quot;&gt;Topographical Sorting&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/microsoft/ts-parsec&quot;&gt;&lt;code&gt;ts-parsec&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactflow.dev/&quot;&gt;React Flow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>week 34, year 2024 - programming languages of various types</title><link>https://nabeelvalley.co.za/blog/2024/24-08/week-34-programming-languages-of-various-types/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/24-08/week-34-programming-languages-of-various-types/</guid><pubDate>Sat, 24 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;what i&apos;m working on&lt;/h2&gt;
&lt;p&gt;i&apos;ve been putting some hours into my image editing app and think i have something that technically works, at the moment it doesn&apos;t look like much but proves that the visual programming language idea works:&lt;/p&gt;
&lt;p&gt;i wrote a &lt;a href=&quot;https://nabeelvalley.co.za/blog/2024/24-08/unintentionally-made-a-programming-language/&quot;&gt;blog post explaining how the application works&lt;/a&gt;{rel=&amp;quot;nofollow ugc noopener&amp;quot;} which explains the concepts around everything all the way from shaders to the ui&lt;/p&gt;
&lt;h2&gt;what i found&lt;/h2&gt;
&lt;p&gt;this week was pretty busy but i managed to get some time to speak to some other devs and we got chatting about configuration languages&lt;/p&gt;
&lt;h3&gt;rcl&lt;/h3&gt;
&lt;p&gt;i bumped into &lt;a href=&quot;https://github.com/ruuda&quot;&gt;Ruud&lt;/a&gt;{rel=&amp;quot;nofollow ugc noopener&amp;quot;} who works on a &lt;a href=&quot;https://github.com/ruuda/rcl&quot;&gt;reasonable configuration language&lt;/a&gt;{rel=&amp;quot;nofollow ugc noopener&amp;quot;} which a language for defining configuration that outputs to more common formats like json&lt;/p&gt;
&lt;h3&gt;pkl&lt;/h3&gt;
&lt;p&gt;this chat also reminded my about &lt;a href=&quot;https://github.com/apple/pkl&quot;&gt;another configuration language made by apple&lt;/a&gt;{rel=&amp;quot;nofollow ugc noopener&amp;quot;} which was released a while ago and is a language for config as code with support for validation&lt;/p&gt;
</content:encoded></item><item><title>week 33, year 2024 - compilers, videography and good intentions</title><link>https://nabeelvalley.co.za/blog/2024/17-08/week-33-compilers-videography-and-good-intentions/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/17-08/week-33-compilers-videography-and-good-intentions/</guid><pubDate>Sat, 17 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;what i&apos;m working on&lt;/h2&gt;
&lt;p&gt;this week i spent some time writing a small compiler to take my node based ui and compile it into a web gpu shader that i can then render images with - and ... that works now. i&apos;m currently in the process of creating a solution for passing user input data between the ui and the gpu which shouldn&apos;t be too difficult - that&apos;s pretty much the last thing i need to do before i can have something that i can actually edit some photos with&lt;/p&gt;
&lt;p&gt;additionally, i spent far too much time fighting with typescript and wrote a bit about &lt;a href=&quot;https://nabeelvalley.co.za/blog/2024/16-08/optional-parameters-and-overloads-in-typescript/&quot;&gt;generic function overloads&lt;/a&gt; and &lt;a href=&quot;https://nabeelvalley.co.za/blog/2024/15-08/handling-complex-typescript-generics/&quot;&gt;even more generic functions&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;what i found&lt;/h2&gt;
&lt;h3&gt;crafting interpreters&lt;/h3&gt;
&lt;p&gt;i&apos;ve been reading &lt;a href=&quot;https://craftinginterpreters.com/&quot;&gt;crafting interpreters by Robert Nystrom&lt;/a&gt; which takes you through the entire process of implementing an interpreter for a custom programming language&lt;/p&gt;
&lt;h3&gt;the art of showing up&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=UJzh8X4Z8ys&quot;&gt;this vlog by Life of Riza&lt;/a&gt; is a little story about just being present, it&apos;s a really uplifting watch and just an exciting little journey overall&lt;/p&gt;
&lt;h3&gt;a phoneless summer&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=7kseFWPllIo&quot;&gt;a &amp;quot;TVlog&amp;quot; by Anna Maria Luisa&lt;/a&gt; dealing with the awareness of time passing. excellent vibes and great writing&lt;/p&gt;
&lt;h3&gt;then next comes&lt;/h3&gt;
&lt;p&gt;if you share my internet you may have seen &lt;a href=&quot;https://www.youtube.com/watch?v=o1OsDWT_DUc&quot;&gt;exurb1a&apos;s latest existential crisis&lt;/a&gt; which starts off as a look into a potential future of humanity until it takes us full circle into wishing we had any idea what anything is at all&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;and thanks for reading, till next week!&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Parameters, but only sometimes</title><link>https://nabeelvalley.co.za/blog/2024/16-08/optional-parameters-and-overloads-in-typescript/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/16-08/optional-parameters-and-overloads-in-typescript/</guid><description>Better handling of function generics with optional parameters in Typescript using overloads</description><pubDate>Fri, 16 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ran into this question today and I thought it would be a nice little example to document:&lt;/p&gt;
&lt;p&gt;I have the following function &lt;code&gt;doWork&lt;/code&gt; that is generic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function doWork&amp;lt;T&amp;gt;(data?: T): void {
  console.log(data)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This function can be called in any of the following ways:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// Works
doWork&amp;lt;string&amp;gt;(&apos;hello&apos;) //  T is string, data is string
doWork() // T is undefined, data is undefined
doWork(undefined) // T is undefined, data is undefined;

doWork&amp;lt;string&amp;gt;() // T is string, data is undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above usage, we want to make it so that users of this function need to provide the &lt;code&gt;data&lt;/code&gt; parameter when calling the function when the type is provided. Now, a simple solution could be to define our function as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function doWork&amp;lt;T&amp;gt;(data: T): void
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem is that it&apos;s a bit ugly for cases where we want to allow &lt;code&gt;T&lt;/code&gt; as &lt;code&gt;undefined&lt;/code&gt;, because you now have to do this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;doWork(undefined)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the issue here is that we only want to make the &lt;code&gt;data&lt;/code&gt; parameter required when &lt;code&gt;T&lt;/code&gt; is not &lt;code&gt;undefined&lt;/code&gt;, there&apos;s a lot of funny stuff you can try using generics and other weird typescript notation, but simply defining the necessary overloads for our method works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;/**
 * This specifically handles the case where T is undefined
 */
function doWork&amp;lt;T extends undefined&amp;gt;(): void
/**
 * The data param will be required since T is not undefined here
 */
function doWork&amp;lt;T&amp;gt;(data: T): void
/**
 * This provideds an implementation that is the same as before while providing a
 * better interface for function users
 */
function doWork&amp;lt;T&amp;gt;(data?: T): void {
  console.log(data)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, having defined those function overloads, we can use the function and it works as expected:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// Works
doWork&amp;lt;string&amp;gt;(&apos;hello&apos;) //  T is string, data is required
doWork() // T is undefined, data parameter is not required
doWork(undefined) // T is undefined, specifying data is still okay

// Error: Type &apos;string&apos; does not satisfy the constraint &apos;undefined&apos;
doWork&amp;lt;string&amp;gt;() // this overload is not valid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The added benefit of this method is that we can also write the doc comments for each implementation separately which can be a nice way for us to give additional context to consumers. It&apos;s kind of like having two specialized functions without the overhead of having to implement them independently&lt;/p&gt;
</content:encoded></item><item><title>More generic than it should be</title><link>https://nabeelvalley.co.za/blog/2024/15-08/handling-complex-typescript-generics/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/15-08/handling-complex-typescript-generics/</guid><description>A method for designing highly generic APIs in Typescript</description><pubDate>Thu, 15 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A method for designing highly generic APIs in Typescript&lt;/p&gt;
&lt;h2&gt;The Pattern&lt;/h2&gt;
&lt;p&gt;A recurring point I&apos;ve seen when designing highly generic API&apos;s in Typescript is around giving consumers of an API an interface that requires the least amount of extra information from them. For example, take the function below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface Data {
  name: string;
  age: number;
}

declare const data: Data;

function getProperty&amp;lt;D, K extends keyof D&amp;gt;(key: K) {
  return function getProp(data: D): D[K] {
    return data[key];
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, we define a function called &lt;code&gt;getProperty&lt;/code&gt; that gets the &lt;code&gt;key&lt;/code&gt; property of &lt;code&gt;data&lt;/code&gt;, we would use this like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getName = getProperty&amp;lt;Data, &amp;quot;name&amp;quot;&amp;gt;(&amp;quot;name&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem here is that the user of this function has to provide both generics when using the function since the object with type &lt;code&gt;D&lt;/code&gt; is only provided to the function that is returned. The experience of a consumer here is a little cumbersome and would be nicer if we didn&apos;t have to do this.&lt;/p&gt;
&lt;h2&gt;Some Other Ideas&lt;/h2&gt;
&lt;p&gt;We can also try the following where we just provide the &lt;code&gt;name&lt;/code&gt;, but this won&apos;t work:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getName = getProperty(&amp;quot;name&amp;quot;); // Error: Argument of type &apos;string&apos; is not assignable to parameter of type `never`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is because the function doesn&apos;t know what type it&apos;s dealing with. The obvious next thing we can try is just provide a single type argument, but this doesn&apos;t work either since typescript needs us to provide both generics since we&apos;re not defaulting the second one&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getName = getProperty&amp;lt;Data&amp;gt;(&amp;quot;name&amp;quot;); // Error: Expected 2 type arguments, but got 1
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;We &lt;em&gt;could&lt;/em&gt; default the type of &lt;code&gt;K&lt;/code&gt; which would take away our error but would also completely remove the benefit of it being a generic parameter in this case which is to narrow down the type the function returns&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, a general strategy here is to instead swap around our type arguments, what if we defined &lt;code&gt;getProperty&lt;/code&gt; instead by defining &lt;code&gt;D&lt;/code&gt; in terms of &lt;code&gt;K&lt;/code&gt;, something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function getProperty&amp;lt;K extends string&amp;gt;(key: K) {
  return function getProp&amp;lt;D extends Record&amp;lt;K, any&amp;gt;&amp;gt;(data: D): D[K] {
    return data[key];
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, this works and may be okay for your usecase, but often we want to constrain the &lt;code&gt;getProperty&lt;/code&gt; function with the type of data known in advance. Also it can be more complicated than just a record with the key of the input type and this isn&apos;t always something we can extend more generally&lt;/p&gt;
&lt;p&gt;This also has the issue that when using the &lt;code&gt;getProperty&lt;/code&gt; function we end up with a function that lets anything through that maybe has a &lt;code&gt;name&lt;/code&gt; property which may not be what we want&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getName = getProperty(&amp;quot;name&amp;quot;); // getter is not constrained by the type of `D`
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;A Weird Solution&lt;/h2&gt;
&lt;p&gt;What can be a better solution is to split our function into a part that provides a generic and a part that provides data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function createGetter&amp;lt;D&amp;gt;() {
  return function getProperty&amp;lt;K extends keyof D&amp;gt;(key: K) {
    return function (data: D): D[K] {
      return data[key];
    };
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can now be used in a way where we don&apos;t specify any more generics than we need and has the weirdness of us invoking a function twice for no reason other than providing a generic&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getName = createGetter&amp;lt;Data&amp;gt;()(&amp;quot;name&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also make this a bit easier on the eyes by creating an intermediate variable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const dataGetter = createGetter&amp;lt;Data&amp;gt;();
const getName = dataGetter(&amp;quot;name&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This isn&apos;t too bad, and I&apos;d be okay to leave it here, but after speaking to some other developers I end up having a lot of questions around how the mechanics of the generic type need to work as well as the fact that we have multiple levels of functions returning functions that creates confusion when trying to use this code&lt;/p&gt;
&lt;h2&gt;A Classier Way&lt;/h2&gt;
&lt;p&gt;Weirdly, thinking of this as a class seemed to help. Instead of using a function to preload a generic, we can use a class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;class Getter&amp;lt;D&amp;gt; {
  property&amp;lt;K extends keyof D&amp;gt;(key: K) {
    return function (data: D): D[K] {
      return data[key];
    };
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I think this code reads a bit nicer and it&apos;s clear where the different generics come from. Ultimately it&apos;s doing the exact same thing but we&apos;re hiding the complexity of initializing the generic behind some syntax&lt;/p&gt;
&lt;p&gt;Using this is quite nice now as well:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const dataGetter = new Getter&amp;lt;Data&amp;gt;();
const getName = dataGetter.property(&amp;quot;name&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What&apos;s also different with using the class approach is that things have names now, we know that we are calling the &lt;code&gt;.property&lt;/code&gt; method which is giving us something to work with. Something about using classes gives people a bit more familiarity when working with generic things and creates a good relationship between the mechanics of the method and the mental model most developers have of class based development&lt;/p&gt;
&lt;h3&gt;Gross&lt;/h3&gt;
&lt;p&gt;I&apos;m more and more moving towards the idea that this kind of generic stuff should be kept to a minimum. This is a relatively simple example but these concepts can get pretty complex and perhaps speaks to something more fundementally incorrect about the data structures being worked with. If you can control the data structures, then ideally simplify them so you don&apos;t need this level of type magic, but if you do - it&apos;s always handy to have a way to express things that makes it easier for other developers to understand and work with&lt;/p&gt;
</content:encoded></item><item><title>week 32, year 2024 - branded types, nodes, and image segmentation</title><link>https://nabeelvalley.co.za/blog/2024/10-08/week-32-branded-types-nodes-and-image-segmentation/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/10-08/week-32-branded-types-nodes-and-image-segmentation/</guid><pubDate>Sat, 10 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;what i&apos;m working on&lt;/h2&gt;
&lt;p&gt;i&apos;ve still been spending a decent amount of time on my photo editing app and progress has been good. this week i put together a basic concept of how i want the ui to work as well as how i can translate configuration from the webGPU backend i&apos;m using to the ui&lt;/p&gt;
&lt;h2&gt;what i found&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;react-flow&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;react-flow&lt;/code&gt; is a library for building node-based user interfaces and has been pretty great to play around with and pretty much does what it says on the box&lt;/p&gt;
&lt;h2&gt;branded types&lt;/h2&gt;
&lt;p&gt;branded types are a way to bring some ideas around primitive types from functional languages to typescript. i find them to be a generally useful thing to know. i think they play very well with the concept of type-first design, as far as it goes &lt;a href=&quot;https://fsharpforfunandprofit.com/series/designing-with-types/&quot;&gt;this post by Scott Wlaschin&lt;/a&gt; is always something i recommend. as far as doing this in typescript i think &lt;a href=&quot;https://x.com/mattpocockuk/status/1625173884885401600?lang=en&quot;&gt;this thread by matt pocock&lt;/a&gt; is a pretty good reference as well as &lt;a href=&quot;https://typescript.tv/best-practices/improve-your-type-safety-with-branded-types/&quot;&gt;this post on typescript.tv&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;image segmentation&lt;/h2&gt;
&lt;p&gt;i came across the &lt;a href=&quot;https://ai.meta.com/blog/segment-anything-foundation-model-image-segmentation/&quot;&gt;segment anything model by meta&lt;/a&gt; which is a pretty cool model for image segmentation and is just generally fun to play around with&lt;/p&gt;
</content:encoded></item><item><title>week 31, year 2024 - webgpu and parsers</title><link>https://nabeelvalley.co.za/blog/2024/02-08/week-31-webgpu-and-parsers/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/02-08/week-31-webgpu-and-parsers/</guid><pubDate>Fri, 02 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;welcome&lt;/h2&gt;
&lt;p&gt;since this is my first post in this format i figured i should just say hey! this series will be a bit of a braindump for project updates and links to things i found this week&lt;/p&gt;
&lt;h2&gt;what i&apos;m working on&lt;/h2&gt;
&lt;p&gt;right now i&apos;m the concept of a photo editing app that uses shaders for applying image effects, the initial concept seems to be promising but there&apos;s still a fair amount of work to be done before i can have anything even remotely usable&lt;/p&gt;
&lt;p&gt;i also had an excuse to use git bisect in a new and interesting way and made some additions to &lt;a href=&quot;https://nabeelvalley.co.za/docs/random/git#find-bad-commits-using-bisect&quot;&gt;my git notes&lt;/a&gt; about using the &lt;code&gt;—first-parent&lt;/code&gt; and &lt;code&gt;replay &lt;/code&gt;functionality&lt;/p&gt;
&lt;h2&gt;what i found&lt;/h2&gt;
&lt;h3&gt;&lt;code&gt;ts-parsec&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;i&apos;ve been pretty invested in parser combinators recently and have been playing around with the &lt;a href=&quot;https://github.com/microsoft/ts-parsec&quot;&gt;ts-parsec library&lt;/a&gt; and it&apos;s been a pretty fun time. for a general idea of what these things are all about you can take a look at &lt;a href=&quot;https://nabeelvalley.co.za/blog/2024/20-07/parser-combinators-and-gleam/&quot;&gt;my blog post on parser combinators&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;WebGPU&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API&quot;&gt;webgpu&lt;/a&gt; is the &amp;quot;new&amp;quot; way to create shaders on the web and comes with a new javsacript API and a &lt;a href=&quot;https://www.w3.org/TR/WGSL/&quot;&gt;new language called wgsl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;the api is a bit more complex than the one for webgl but still reasonably manageable if you take a read through the &lt;a href=&quot;https://webgpufundamentals.org/&quot;&gt;webgpu fundamentals site&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;additionally, i found a few great resources for using webgpu for image filters, namely work by &lt;a href=&quot;https://alain.xyz/blog/image-editor-effects&quot;&gt;Alain Galvan&lt;/a&gt; and &lt;a href=&quot;https://maximmcnair.com/#&quot;&gt;Maxim McNair&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Life, Gleam, and Parser Combinators</title><link>https://nabeelvalley.co.za/blog/2024/20-07/parser-combinators-and-gleam/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/20-07/parser-combinators-and-gleam/</guid><description>A short introduction to Parser Combinators</description><pubDate>Sat, 20 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Time&lt;/h2&gt;
&lt;p&gt;There&apos;s never enough time to do the things we want to do. Recently I find myself struggling with this. There are too few hours in a day, too few days in a week. Between work and trying to simply stay alive there aren&apos;t many hours left to do things you care about&lt;/p&gt;
&lt;p&gt;For the past year or so I&apos;ve made a consistent effort to take my camera with me everywhere. It&apos;s always either in my bag or in my hand. And I&apos;ve taken a lot of pictures. The thing is, I feel that my photos have stagnated - they&apos;re no better than they were a year ago, and arguably worse than five years ago. I seem to have hit some kind of local maximum, the point where I put just enough effort to passable but not nearly enough time to do anything useful&lt;/p&gt;
&lt;p&gt;As far as my photography goes, I&apos;m planning to take fewer pictures, but spend a lot more time looking for ways to be better and create work that means more to me.&lt;/p&gt;
&lt;p&gt;The other area of my life that&apos;s suffered due to poor time management is my technical learning. I&apos;ve found programming to be an interesting lens through which to see the world, and different approaches and paradigms make that a constantly moving picture.&lt;/p&gt;
&lt;h2&gt;Gleam&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam&lt;/a&gt; is a functional programming language in the Erlang/Elixir ecosystem that compiles to code that can run on the Erlang VM and can also optionally target Javascript/Node&lt;/p&gt;
&lt;p&gt;There are a lot of things I still want to learn about and a lot of things I want to do. A few months ago I tried learning the Gleam but between windows being a generally disagreeable operating system and a general lack of direction I never quite got anywhere with it. Throught the documentation the language seemed like a nice little thing to learn and looked like a good balance of the strictness I wanted from a functional language and the ease of learning.&lt;/p&gt;
&lt;p&gt;Overall, I found it really easy to pick up Gleam - the syntax is very Javascripty and it&apos;s got a very similar type system to F# both in terms of how the syntax looks as well as how it works overall. The standard library is also pretty good and covered most things I had to do and provided some utilities for a lot of common things as well as had testing configured from the get-go which made this overall quite a pleasure to setup&lt;/p&gt;
&lt;p&gt;I&apos;ve also been interested in Parser Combinators and spent some time learning about them from &lt;a href=&quot;https://www.youtube.com/playlist?list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU&quot;&gt;this YouTube Series by Low Byte Productions&lt;/a&gt; as well as as some work by &lt;a href=&quot;https://fsharpforfunandprofit.com/posts/understanding-parser-combinators/&quot;&gt;Scott Wlaschin on F# for Fun and Profit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The series by Low Byte was pretty great but was done in Javascript and didn&apos;t really delve into some of the type complexities and behaviours that crop up when working with static types. It was on my second watch of Scott Wlaschin&apos;s talk where the behaviour of generics really clicked and allowed me to related things back to Gleam&lt;/p&gt;
&lt;p&gt;As far as my actual experimentation goes I tried to use the kinds of parsers and combinators defined by the LowByte YouTube series while using the approach by Scott Wlaschin&lt;/p&gt;
&lt;p&gt;Overall I think I learnt quite a bit, I spent a lot of time looking at the Gleam code and rewriting things to work more consistely with the type of data structure I wanted. One of the things I found a little annoying things I found is that recursive functions seem to be definable only at the top-level of a module which adds some ceremony around doing things that involve recursion&lt;/p&gt;
&lt;p&gt;But anyways, all that aside, let&apos;s take a look at some parser things&lt;/p&gt;
&lt;h2&gt;Parsers&lt;/h2&gt;
&lt;h3&gt;What is a Parser&lt;/h3&gt;
&lt;p&gt;In our context, a parser is simply a function that takes in some input, and tries to convert it into some meaningful pieces of data, further - a combinator is a function that takes one or more parsers and combines them into a new parser - get it? - combine = combinator.&lt;/p&gt;
&lt;p&gt;So in our context, we can define a type for a parser as a function that takes a &lt;code&gt;String&lt;/code&gt; and returns some result that tells use the part of the string which was matched and what was left over&lt;/p&gt;
&lt;p&gt;Additionally, a parser can be either successful or unsuccessful, and we do that using the &lt;code&gt;Result&lt;/code&gt; type that&apos;s built into Gleam:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub type ParserState(a) {
  ParserState(matched: a, remaining: String)
}

pub type Err =
  String

pub type Parser(a) =
  fn(String) -&amp;gt; Result(ParserState(a), Err)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;A Simple Parser&lt;/h3&gt;
&lt;p&gt;We can also see that we are using this &lt;code&gt;a&lt;/code&gt; thing above, this is a generic type in Gleam. In our implementation we define that a parser just needs to return some kind of data as what was matched, but we don&apos;t particularly care what that is&lt;/p&gt;
&lt;p&gt;For the sake of example, we can define a simple parser that matches a string exactly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn starts_with_xx(input) {
  case string.starts_with(input, &amp;quot;xx&amp;quot;) {
    False -&amp;gt; Error(&amp;quot;Expected xx&amp;quot; &amp;lt;&amp;gt; &amp;quot; but found &amp;quot; &amp;lt;&amp;gt; input)
    True -&amp;gt; {
      let remaining = string.drop_left(input, string.length(&amp;quot;xx&amp;quot;))
      Ok(ParserState(&amp;quot;xx&amp;quot;, remaining))
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above, we define a parser called &lt;code&gt;starts_with_xx&lt;/code&gt; which will simply parse the characters &lt;code&gt;xx&lt;/code&gt; in a string. Now, overall this isn&apos;t super useful and is pretty tedious if we need to do this each time we define a parser, so more generally we can define parsers using a function that takes some configuration and returns a parser&lt;/p&gt;
&lt;p&gt;So an example of a function that takes in a &lt;code&gt;String&lt;/code&gt; to match and returns a parser to us can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn str(start) -&amp;gt; Parser(String) {
  fn(input) {
    case string.starts_with(input, start) {
      False -&amp;gt; Error(&amp;quot;Expected &amp;quot; &amp;lt;&amp;gt; start &amp;lt;&amp;gt; &amp;quot; but found &amp;quot; &amp;lt;&amp;gt; input)
      True -&amp;gt; {
        let remaining = string.drop_left(input, string.length(start))
        Ok(ParserState(start, remaining))
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then redefine our above &lt;code&gt;starts_with_x&lt;/code&gt; parser in terms of this one, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let starts_with_xx = str(&amp;quot;x&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running a parser we can see a bit about the type of data this returns:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let parser = str(&amp;quot;x&amp;quot;)

let result = parser(&amp;quot;xxY&amp;quot;)
// Ok(ParserState(&amp;quot;xx&amp;quot;, &amp;quot;Y&amp;quot;))


let error = parser(&amp;quot;Yxx&amp;quot;)
// Error(&amp;quot;Expected xx but found Yxx&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can define other parsers using a similar style but this is the core of it, the above is very specifically a &lt;code&gt;Parser(String)&lt;/code&gt; but these can be more generic as we&apos;ll see when we get to combinators&lt;/p&gt;
&lt;h3&gt;A Simple Combinator&lt;/h3&gt;
&lt;p&gt;Combinators are used to combine parsers in interesing ways. A simple combinator is the &lt;code&gt;left&lt;/code&gt; combinator which takes in two parsers and tries to parse them as a sequence, but will only keep the left-side of the parsed result.&lt;/p&gt;
&lt;p&gt;We can define this parser as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn left(l: Parser(a), r: Parser(b)) -&amp;gt; Parser(a) {
  fn(input) {
    case l(input) {
      Error(err) -&amp;gt; Error(err)
      Ok(okl) -&amp;gt;
        case r(okl.remaining) {
          Error(err) -&amp;gt; Error(err)
          Ok(okr) -&amp;gt; Ok(ParserState(okl.matched, okr.remaining))
        }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s also interesting to note that we take a &lt;code&gt;Parser(a)&lt;/code&gt; and &lt;code&gt;Parser(b)&lt;/code&gt; but return a &lt;code&gt;Parser(a)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We can define a parser using the &lt;code&gt;choice&lt;/code&gt; combinator which would work as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let parser = choice(str(&amp;quot;x&amp;quot;), str(&amp;quot;y&amp;quot;))

let result = parser(&amp;quot;xyz&amp;quot;)
// Ok(ParserState(&amp;quot;x&amp;quot;, &amp;quot;z&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The parser above effectively throws away the second match in the choice but moves our inputs to the end of the second parser&lt;/p&gt;
&lt;p&gt;So far however we&apos;re just working with strings, it would be nice to parse something more complex. In order to facilitate this we&apos;re going to define a combinator called &lt;code&gt;map&lt;/code&gt; which will allow us to transform the result of the parser for the case where it succeeds (is &lt;code&gt;Ok&lt;/code&gt;)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;pub fn map(parser: Parser(a), transform) {
  fn(input) {
    case parser(input) {
      Error(err) -&amp;gt; Error(err)
      Ok(ok) -&amp;gt; Ok(ParserState(transform(ok.matched), ok.remaining))
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above definition you can see that the &lt;code&gt;parser&lt;/code&gt; is the first input to &lt;code&gt;map&lt;/code&gt;. We&apos;re defining it like this because Gleam allows us to automatically pass the first argument as a result of a previous computation using the pipe operator which looks like &lt;code&gt;|&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To do something meaningful with &lt;code&gt;map&lt;/code&gt; we&apos;re going to define a small type called &lt;code&gt;Token&lt;/code&gt; which will have a constructor called &lt;code&gt;TokenX&lt;/code&gt; which we will just use to represent us matching the character &lt;code&gt;X&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;type Token {
  TokenX(matched: String)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use the type we create along with the map operator to transform the result of the parsing to a more sophisticated data type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let parser =
  left(
    str(&amp;quot;x&amp;quot;)
      |&amp;gt; map(TokenX),
    str(&amp;quot;y&amp;quot;),
  )

let result = parser(&amp;quot;xyz&amp;quot;)
// Ok(ParserState(TokenX(&amp;quot;x&amp;quot;), &amp;quot;z&amp;quot;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So that&apos;s pretty cool right?&lt;/p&gt;
&lt;h3&gt;A More Complex Parser&lt;/h3&gt;
&lt;p&gt;Using the basic idea of a parser and a combinator, we can define a whole bunch of them as I have &lt;a href=&quot;https://github.com/sftsrv/parz&quot;&gt;in my Parz project on GitHub&lt;/a&gt; we can compose them to create a parser for a more complex data type, for example:&lt;/p&gt;
&lt;p&gt;Say we have a little language that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;name:string;
age:number;
active:boolean;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can define a little syntax tree that we want our output to match as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;type Ast {
  Ast(List(Node))
}

type Node {
  Node(name: Identifier, kind: Kind)
}

type Kind {
  StringKind
  BooleanKind
  NumberKind
}

type Identifier {
  Identifier(name: String)
}

type NodePart {
  NodeKind(kind: Kind)
  NodeIdentifier(identifier: Identifier)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All of the above directly map to something within our syntax other than &lt;code&gt;NodePart&lt;/code&gt; which is used as an intermediate type that allows us to search for &lt;code&gt;Kind&lt;/code&gt; and &lt;code&gt;Identifier&lt;/code&gt; in the same &lt;code&gt;choice&lt;/code&gt; due to how Gleam generics work&lt;/p&gt;
&lt;p&gt;Finally, we can define a parser using the library I made as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;fn parser() {
  // Parse an identifier
  let identifier =
    letters()
    |&amp;gt; map(Identifier)

  // Parse the different node &amp;quot;kinds&amp;quot; that the language has
  let string_kind = str(&amp;quot;string&amp;quot;) |&amp;gt; map_token(StringKind)
  let number_kind = str(&amp;quot;number&amp;quot;) |&amp;gt; map_token(NumberKind)
  let boolean_kind = str(&amp;quot;boolean&amp;quot;) |&amp;gt; map_token(BooleanKind)

  let kind = choice([string_kind, number_kind, boolean_kind])

  // A node is defined as a sequence of (indeitifier, :)(kind, ;)
  let node =
    sequence([
      left(identifier, str(&amp;quot;:&amp;quot;) |&amp;gt; label_error(custom_error))
        |&amp;gt; map(NodeIdentifier),
      left(kind, str(&amp;quot;;&amp;quot;)) |&amp;gt; map(NodeKind),
    ])
    // Extract the identifier and kind from our mapping
    |&amp;gt; try_map(fn(ok) {
      case ok {
        [NodeIdentifier(i), NodeKind(k)] -&amp;gt; Ok(Node(i, k))
        _ -&amp;gt; Error(&amp;quot;Failed to match identifier:kind&amp;quot;)
      }
    })

  let whitespace = regex(&amp;quot;\\s*&amp;quot;)

  let parser = separator1(node, whitespace) |&amp;gt; map(Ast)

  parser
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can use this to parse our initial input fragment which yields:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-gleam&quot;&gt;let result = parser(input)
// ParserState(
//    Ast([
//      Node(Identifier(&amp;quot;name&amp;quot;), StringKind),
//      Node(Identifier(&amp;quot;age&amp;quot;), NumberKind),
//      Node(Identifier(&amp;quot;active&amp;quot;), BooleanKind),
//    ]),
//    &amp;quot;&amp;quot;,
//  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s about it. At a high level you should be able to build parsers using the concepts I&apos;ve mentioned here. Combinators are extremely powerful and I think can work as a great introduction to to functional programming concepts&lt;/p&gt;
&lt;h2&gt;The Library&lt;/h2&gt;
&lt;p&gt;Over the course of learning about parser combinators and the gleam language, I put together a little parsing library. It&apos;s probably extremely inefficient but was a fun little project and I think it was a useful learning excercise. My libray can be found &lt;a href=&quot;https://github.com/sftsrv/parz&quot;&gt;on GitHub&lt;/a&gt; but it&apos;s also published as a package that you can use on &lt;a href=&quot;https://hexdocs.pm/parz&quot;&gt;Hex&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;My time was primarily spent between the following resources when working on this project&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gleam.run/documentation/&quot;&gt;Gleam Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PLP29wDx6QmW5yfO1LAgO8kU3aQEj8SIrU&quot;&gt;Parser Combinators by Low Byte Productions on YouTube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fsharpforfunandprofit.com/posts/understanding-parser-combinators&quot;&gt;Parser Combinators by Scott Wlaschin on F# for Fun and Profit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, if you just wan to learn to program in Gleam you can take a look on &lt;a href=&quot;https://exercism.org/tracks/gleam&quot;&gt;Exercism&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Additonally, some more generally related information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/docs/javascript/typescript-ast&quot;&gt;My notes on working with the Typescript AST&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>The Most Awkward Person in the Room</title><link>https://nabeelvalley.co.za/blog/2024/13-07/on-being-awkward/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/13-07/on-being-awkward/</guid><description>The challenge of language</description><pubDate>Sat, 13 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;I should preface this by saying that I don&apos;t think I&apos;m particularly good at English&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&apos;s already challenging enough trying to communicate in a foreign country - add in some loud music and a sketchy location and we&apos;ve just made that about ten times more difficult&lt;/p&gt;
&lt;h2&gt;English, or something&lt;/h2&gt;
&lt;p&gt;A friend of mine mentioned to me the other day that they&apos;ve been thinking about moving to the UK because of how much gets lost when communicating in a second language&lt;/p&gt;
&lt;p&gt;This morning I met up with some developers and we were chatting about software but also politics (since everything is politics) and a few times during the conversation the perfect sentence popped into my head - but I couldn&apos;t say it. There was the immediate realization that the meaning would be lost, the nuance would not translate.&lt;/p&gt;
&lt;p&gt;I&apos;ve been experiencing this a lot at work well, while everyone speaks English perfectly, there&apos;s just a little bit of style that has to be eliminated to communicate clearly - something I don&apos;t find myself doing when speaking to native English speakers. I simplify words, use fewer metaphors, and slow down significantly&lt;/p&gt;
&lt;p&gt;Anyways, I went home and spoke to my wife and she had some strong opinions about the churro place she went to. All the signs were in English but when she tried to order in English the person working there didn&apos;t seem to understand what she was saying, even though he repeated all the same things back to her in English&lt;/p&gt;
&lt;p&gt;Now, if I&apos;m being completely honest here, some of these problems exist when speaking through language boundaries but it&apos;s a lot less frequent&lt;/p&gt;
&lt;h2&gt;The Curse of the Awkward&lt;/h2&gt;
&lt;p&gt;So, anyways - I&apos;m not a super social person - I don&apos;t really know how to speak to people and kind of overthink every interaction&lt;/p&gt;
&lt;p&gt;On one of the Photography groups I&apos;m on someone posted an invite to a &amp;quot;Party&amp;quot; which was meant to just be a social event for photographers and creatives. They also added a tiny note saying &amp;quot;no alcohol event, more like networking&amp;quot;&lt;/p&gt;
&lt;p&gt;No alcohol you say? Do such things exist? Okay count me in - is what I would have said if I didn&apos;t spend two hours contemplating whether or not this would be the worst experience of my life&lt;/p&gt;
&lt;p&gt;It was a bit in the middle of nowhere but looked like it wouldn&apos;t take me too long to get there - so I was like yeah sure. I dropped them a message and said I&apos;d meet them there - this wasn&apos;t someone I&apos;d met before but I know a few people who know them so I figured it should be alright&lt;/p&gt;
&lt;p&gt;I got to what Google told me was the destination but this was just a weird abandoned building with automatic doors that wouldn&apos;t open automatically&lt;/p&gt;
&lt;p&gt;I saw a person with a camera standing in the passage upstairs and figured I was probably in the right place but had no idea what to expect&lt;/p&gt;
&lt;p&gt;The dude I was supposed to meet got there about 5 minutes after I did and we went in together (after awkwardly waiting for someone to see us and let us in)&lt;/p&gt;
&lt;p&gt;It was super weird. There were photographers everywhere and people posing all over the space, the music was maaad loud and there were some people live-DJing&lt;/p&gt;
&lt;p&gt;This was a kind of chaos I wasn&apos;t ready for&lt;/p&gt;
&lt;p&gt;I think the worst part of going to a place you&apos;ve never been is not knowing anyone - events are a sort of social fabric and it&apos;s always a bit scary being a loose thread&lt;/p&gt;
&lt;p&gt;I floated about not too sure what to do, looking around, just trying to see what was happening - I was kind of shocked at how diverse the space was. It&apos;s rare in the Netherlands to end up in a room where you aren&apos;t the only person of colour in&lt;/p&gt;
&lt;p&gt;This is something I noticed the last time I attended a photography meetup which was that it was a lot less white than the professional spaces I tend to be involved in&lt;/p&gt;
&lt;p&gt;There may be some social commentary that could be added here but that&apos;s not what this post is about so moving on&lt;/p&gt;
&lt;p&gt;Later in the evening there was a short poetry performance which was cool - but that&apos;s about all I can say about it - the poetry was in Dutch and while I think my rudimentary understanding of the language was enough to grasp the high level idea of it, I feel like a lot of meaning and intent was lost in translation&lt;/p&gt;
&lt;h2&gt;Thought&lt;/h2&gt;
&lt;p&gt;I think the way we communicate with people close to us resonates on a level that&apos;s more than just the words we&apos;re saying. There&apos;s an understanding that becomes so difficult to interpret when speaking a second language&lt;/p&gt;
&lt;p&gt;Maybe there&apos;s something I&apos;m missing here, maybe there&apos;s something to be had where language isn&apos;t the main factor - where the words we say aren&apos;t the foundation of our relationships. But maybe that&apos;s a thought for another day&lt;/p&gt;
</content:encoded></item><item><title>On Automatic Lensess</title><link>https://nabeelvalley.co.za/blog/2024/27-04/automatic-lenses/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/27-04/automatic-lenses/</guid><description>Why automatic camera lenses suck</description><pubDate>Sat, 27 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I enjoy capturing the world around me - places, people, plants - anything the light touches really&lt;/p&gt;
&lt;p&gt;I&apos;ve also spent a fair number of years shooting with manual focus lenses. Every now and then I pick up an auto focus lens - usually my kit lens, usually because I&apos;m experimenting with a focal length or style I don&apos;t use often&lt;/p&gt;
&lt;p&gt;Between a museum and getting a bite to eat I was strolling the streets of Amsterdam trying to catch some of the Kingsday activities. I used my kit lens most of the time. It&apos;s a 15-45mm f3.5 Fujifilm lens that&apos;s fully automatic&lt;/p&gt;
&lt;p&gt;Recently I&apos;ve been experimenting with shooting at f11-f22 and aperture priority mode while prefocusing to get some more &amp;quot;classic style&amp;quot; street photos. This setup is really great because it means I don&apos;t have to fiddle with anything when trying to get a shot - I can just lift my camera and click. This is especially handy since a scene can change quickly when shooting on a busy street&lt;/p&gt;
&lt;p&gt;While shooting today I noticed a few things that annoyed me quite a bit and thought I should put them down mostly as a reminder to myself as to why I don&apos;t really shoot with automatic lenses&lt;/p&gt;
&lt;p&gt;Firstly, I get the feeling that automatic lenses make the process of turning a camera on and off a lot slower - I also get the feeling that it consumes a lot more battery life when turning on or off since the lens I have, and other lenses I&apos;ve had previously, have a &amp;quot;collapsed&amp;quot; mode when inactive in which the lens elements are all fitted into the housing - when turned on, the motors in the lens &amp;quot;uncollapse&amp;quot; them which takes a bit of time and seems to eat a lot more battery than when using a fully manual lens&lt;/p&gt;
&lt;p&gt;Next, then lens I have uses &amp;quot;fake&amp;quot; focus and zoom rings (it&apos;s a fully auto lens as opposed to just auto-focus). I find this extremely annoying when shooting because I can&apos;t trust that my camera is going to retain my zoom or focus settings when turning it on or off or that they weren&apos;t randomly changed at some time accidentally&lt;/p&gt;
&lt;p&gt;Semi related to this is that due to the focus and zoom rings being electronic, I don&apos;t have any visible zoom or focus indicators on the lens. This means that I have to look through my camera to focus or zoom. This is a little annoying when shooting quickly because it means I can only change these settings after raising the camera to my eye - by the time I&apos;ve dialed the settings in my shot is gone&lt;/p&gt;
&lt;p&gt;You can see the indicators I&apos;m referring to below when comparing the two lenses I currently use&lt;/p&gt;
&lt;p&gt;The fully automatic Fujifilm 15-45mm f3.5 kit lens:&lt;/p&gt;
&lt;p&gt;&amp;lt;center style=&amp;quot;max-width: 500px; margin: auto;&amp;quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2024/27-04/fuji15-45mm.png&quot; alt=&quot;Fujifilm 15-45mm f3.5&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;A fully manual TTArtisan 35mm f1.4 lens:&lt;/p&gt;
&lt;p&gt;&amp;lt;center style=&amp;quot;max-width: 500px; margin: auto;&amp;quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2024/27-04/ttartisan35mm.png&quot; alt=&quot;TTArtisan 35mm f1.4&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;Normally when shooting you need to set the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Focus&lt;/li&gt;
&lt;li&gt;Zoom&lt;/li&gt;
&lt;li&gt;ISO&lt;/li&gt;
&lt;li&gt;Aperture&lt;/li&gt;
&lt;li&gt;Shutter speed&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If I have my focus set before even raising the camera, that&apos;s about more than half of my time-to-shot saved - it&apos;s really handy - particularly with lenses that have slow zoom or focus response like the Fuji lens&lt;/p&gt;
&lt;p&gt;Higher end cameras (particularly Fujifilm cameras) also have the ISO and shutter dials at the top of the camera so that you can view these settings on the hardware without having to turn the camera on - this way you&apos;re always ready to shoot&lt;/p&gt;
&lt;p&gt;Lastly - aperture. Fully manual lenses also have manual aperture rings. This means that on a fully manual lens, even on a lower end camera - at a glance I can view 3 of the 5 things I need to set up in order to take a picture&lt;/p&gt;
&lt;p&gt;Okay, so what? Just remember the settings right? Most cameras should retain your settings between restarts so this doesn&apos;t really matter too much, and generally you&apos;re not changing settings without knowing what your camera and light meter are showing you right? right?&lt;/p&gt;
&lt;p&gt;Well ... not exactly&lt;/p&gt;
&lt;p&gt;So, when shooting street there&apos;s a concept called &amp;quot;shooting from the hip&amp;quot; which is effectively shooting without having to pick up your camera at all. When doing this it can be useful (if not absolutely necessary) to set your camera focus and zoom while not actively shooting so that you can be ready when something comes up - when you&apos;re working with a mirrorless camera, this is even more useful since it lets you conserve battery life if your camera is off while doing this&lt;/p&gt;
&lt;p&gt;However, there are certain cases where being able to have a lens that is automatic is useful like in video for example, when smooth focusing and zooming can make or break a shot, or for photographers who are just starting out and want to let their camera control their aperture or focus settings so they can focus on just getting the shot&lt;/p&gt;
&lt;h2&gt;Some Technical Jargon&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Focal Length&amp;quot; not &amp;quot;Zoom&amp;quot;&lt;/li&gt;
&lt;li&gt;I don&apos;t know what lenses that have electronically controlled focus and zoom rings are called, I&apos;ve settled for &amp;quot;Automatic Lenses&amp;quot;&lt;/li&gt;
&lt;li&gt;The zoom thing obviously doesn&apos;t apply to lenses that do not zoom&lt;/li&gt;
&lt;li&gt;The aperture thing obviously doesn&apos;t apply to lenses that don&apos;t have an aperture control&lt;/li&gt;
&lt;li&gt;All of this also probably doesn&apos;t apply to cameras that are fully manual&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>On Falling Down</title><link>https://nabeelvalley.co.za/blog/2024/19-04/falling/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/19-04/falling/</guid><description>Responding to change</description><pubDate>Fri, 19 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today was kinda shitty. Actually really shitty.&lt;/p&gt;
&lt;p&gt;But also&lt;/p&gt;
&lt;p&gt;maybe not&lt;/p&gt;
&lt;p&gt;Its always weird sitting down to write about what&apos;s going on in your head. I&apos;m currently in a train at night hoping I&apos;ll make it home in the next two hours&lt;/p&gt;
&lt;p&gt;Today was a bit insane. I has to shuffle between trains and go to places I&apos;ve never been. Had to go through a storm feeling like I was constantly about to get thrown into a river by winds far stronger than they had any right to be&lt;/p&gt;
&lt;p&gt;Well. I guess that&apos;s as good a place as any to start&lt;/p&gt;
&lt;p&gt;So, we had a little ski trip planned for work to this weird indoor ski slope in the middle of nowhere. The journey there was gonna be long but was straightforward enough - take two trains and two buses then walk for 8 minutes&lt;/p&gt;
&lt;p&gt;That was not how it went&lt;/p&gt;
&lt;p&gt;So, I got onto the first train - the one I usually take to get to the Utrecht Central station, that was a little busy but nothing too unusual for 4pm on a Friday. When I got to the station I had to catch another train - this one to The Hague - and this is when everything descended into chaos&lt;/p&gt;
&lt;p&gt;The train to The Hague was cancelled - but I was already on it - it was going to Leiden, no further - oh, and pretty much any train going anywhere past Leiden was also cancelled&lt;/p&gt;
&lt;p&gt;Oh, and there isn&apos;t really any app that does &amp;quot;Hi, I&apos;m already on this train but I need to go to this other place, where do I get off?&amp;quot; (Like seriously, this needs to exist)&lt;/p&gt;
&lt;p&gt;After going insane for a while, I resigned myself to my fate, put on some headphones - oh, did I mention that mine were dead so I borrowed my wifes? - and put on a good playlist (after briefly attempting to listen to Taylor Swift&apos;s newest album). It&apos;s kind of weird how much calm the right playlist can bring&lt;/p&gt;
&lt;p&gt;But anyways, It looks like there are some buses I can use from Leiden sort of - so let&apos;s do that&lt;/p&gt;
&lt;p&gt;Now the thing is - since all the trains were stopping in Leiden - the station was absolutely packed. All i could see was a sea of heads&lt;/p&gt;
&lt;p&gt;(one moment, i need to switch trains)&lt;/p&gt;
&lt;p&gt;So, by the skin of my teeth i managed to get into a bus that was heading in the direction i needed to go. It was full, there were some loud americans, and some teenagers talking about tik tok songs, we drove past lots of sheep&lt;/p&gt;
&lt;p&gt;Oh, the bus was also 7 minutes late because of the mess at the station - I wasn&apos;t gonna make the next swap - I had to figure out which stop to take&lt;/p&gt;
&lt;p&gt;My options were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get off at some rando bus stop and walk for 20 minutes&lt;/li&gt;
&lt;li&gt;Get off at some other rando bus stop to wait about an hour and then walk for 10 minutes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Eventually I made it to a bus stop in the middle of nowhere&lt;/p&gt;
&lt;p&gt;I took option 1 - maybe it&apos;s me, maybe i&apos;m the problem - but, just after I got off the bus and oriented my google maps and got my camera out to enjoy my stroll and maybe take some pictures of some lil sheeps - the mother of all storms descended upon lil ol me.&lt;/p&gt;
&lt;p&gt;I don&apos;t know what happened, but the light drizzle turned into a beast with winds trying to steal my phone and camera and a torrent of rain racing to drown me&lt;/p&gt;
&lt;p&gt;Another test of my sanity today. I can&apos;t control the weather I suppose, not any more than I can control bus schedules I guess&lt;/p&gt;
&lt;p&gt;So I walked, slowly, taking pictures of everything I thought was interesting&lt;/p&gt;
&lt;p&gt;Yes, the sheep. And also the little yellow flowers, and the weird giant metal alien space ship thing in the distance, and the poor post person trying their absolute hardest to make it to the next house on their little blue bicycle - the dutch really take their post seriously&lt;/p&gt;
&lt;p&gt;After about 10 minutes of walking I seemed to be in a forest, a hiking trail of some sort - I saw a parent and child riding their bicycle and a woman walking a dog - in this weather?? I can only conclude that the forest was haunted&lt;/p&gt;
&lt;p&gt;But eventually I figured out where my map was taking me - the weird alien thing - oh, that&apos;s the ski slope&lt;/p&gt;
&lt;p&gt;With some end in sight, and a sense of where the heck I was, I walked now with a little more purpose&lt;/p&gt;
&lt;p&gt;I made it there eventually. Soaking wet, looking like whatever the thing that the cat dragged in would drag in&lt;/p&gt;
&lt;p&gt;Then, said hi to some work peeps and got some gear&lt;/p&gt;
&lt;p&gt;And so, may I present you with some snowboarding tips based on what some of my coworkers told me and what I learnt from falling a shit ton of times&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When trying to get on, dig your board in sideways with your back against the slope, this will keep you stable and help in trying to stand up, then commit when you stand - otherwise you&apos;re just gonna spend the entire time on your butt&lt;/li&gt;
&lt;li&gt;Lean less than you think you need to and wait for the board to catch the snow&lt;/li&gt;
&lt;li&gt;While it&apos;s a bit more difficult than the alternatives - take the weird lift thingy because you can keep your boots fully attached and once you get to the top you can just start snowboarding instead of doing the weird crab walk scoot struggle to standup thing&lt;/li&gt;
&lt;li&gt;You can always lean back more than you think and you probably won&apos;t fall down - it&apos;s a lot safer than learning forward and a really good way to quickly slow down if you&apos;re bad at snowboarding&lt;/li&gt;
&lt;li&gt;When using the weird lift thingy just let it take you, don&apos;t fight it - you will fall&lt;/li&gt;
&lt;li&gt;Fall. Yeah if you&apos;re old like me it&apos;s gonna suck tomorrow - but with every weird things on your feet sport, if you don&apos;t get over the fear of falling you&apos;re not really gonna get anywhere&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Oh and the new skiiers will get confused and stuck and not know how to standup - I don&apos;t have a solution, this is just an observation - those things are a deathtrap&lt;/p&gt;
&lt;p&gt;(also snowboarding pants are cool, I kind of want some just to like wear as clothes)&lt;/p&gt;
&lt;p&gt;Also it&apos;s cold and I&apos;m waiting for my last train. This has been a really long day, but if this works out I&apos;ll have at least managed to beat the plan all the map apps gave me - some consolation knowing you&apos;re a bit smarter than some rando pathfinding algorithm i guess&lt;/p&gt;
&lt;p&gt;But anyways, what I think im trying to say is, it&apos;s easy to get frustrated and angry when faced with challenges but all we can do is to make the best of what we can control and accept what we can&apos;t.&lt;/p&gt;
</content:encoded></item><item><title>Passwords</title><link>https://nabeelvalley.co.za/blog/2024/12-04/passwords/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/12-04/passwords/</guid><description>Some casual commentary</description><pubDate>Fri, 12 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Good design is actually a lot harder to notice than poor design, in part because good designs fit our needs so well that the design is invisible, serving us without drawing attention to itself. Bad design, on the other hand, screams out its inadequacies, making itself very noticeable.&amp;quot; - Don Norman&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just had a silly experience. I needed to log into an app on my browser and had the following nonsensical series of steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to website&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Login&amp;quot;&lt;/li&gt;
&lt;li&gt;Username automatically filled in by my password manager&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Next&amp;quot;&lt;/li&gt;
&lt;li&gt;Password is automatically filled in by my password manager&lt;/li&gt;
&lt;li&gt;Click &amp;quot;Submit&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Maybe there&apos;s trickiness I&apos;m not seeing here but from my perspective it doesn&apos;t look like I&apos;m required in this flow?&lt;/p&gt;
&lt;p&gt;Between my browser and my password manager, and to some extent the application I&apos;m logging into, this problem can be solved without my involvement. You have enough information to know who I am and log me in automatically when visiting a page - there&apos;s no real reason I ever need to see a login page when using an application on my device/browser&lt;/p&gt;
&lt;p&gt;I&apos;m thinking that since the data is already there at a hardware level this should be a solved problem&lt;/p&gt;
&lt;p&gt;Then again, maybe this is what &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API&quot;&gt;Web Authentication API&lt;/a&gt; is meant to solve but I&apos;m not too sure, I think it&apos;s still a click too many. That and my experiences with it have been a little inconsistent&lt;/p&gt;
&lt;p&gt;I think we&apos;re still missing some unifying solution - some means of tying my identity to a set of devices once and having the friction removed at every other point&lt;/p&gt;
&lt;p&gt;Generally things get smoother as time goes but I feel that hasn&apos;t been then case with auth. Every day there&apos;s a new step - OTPs, &amp;quot;Magic Links&amp;quot; or &amp;quot;Your password can&apos;t be the same as your past 5 passwords&amp;quot; which create a mess for most people. We like to think that most people just use password managers but that isn&apos;t really the case. Many people struggle with this constantly&lt;/p&gt;
&lt;p&gt;I&apos;m not sure what the solution is but I think we need to start thinking about security from a bit more of a human angle and less of a computer one&lt;/p&gt;
</content:encoded></item><item><title>Show Children when Parent is Hidden with CSS</title><link>https://nabeelvalley.co.za/blog/2024/04-04/css-show-children-when-parent-hidden/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/04-04/css-show-children-when-parent-hidden/</guid><description>Make the children of an HTML element visible when the parent element is hidden</description><pubDate>Thu, 04 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Example from &apos;@/snippets/css-visibility/CSSVisibility.astro&apos;
import HTMLSnippet from &apos;@/components/HTMLSnippet.astro&apos;
import CSSSnippet from &apos;@/components/CSSSnippet.astro&apos;&lt;/p&gt;
&lt;p&gt;When working with HTML we sometimes have a case where we want to view child items of an HTML element while the parent element itself is hidden&lt;/p&gt;
&lt;p&gt;Normally when trying to hide or show some elements, we would apply &lt;code&gt;display:none&lt;/code&gt; and move on. However, we may run into a case where we want to make a specific child visible while keeping the remaining content hidden, so, we might try to add the following to the child &lt;code&gt;display:block&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We will quickly see that this solution doesn&apos;t work. Another thing we might trying to play with the opacity of the items but this doesn&apos;t really solve our problem either&lt;/p&gt;
&lt;p&gt;The solution to this is the &lt;code&gt;visibility&lt;/code&gt; property&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;According to &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/visibility&quot;&gt;the MDN Documentation on Visibility&lt;/a&gt;: &amp;quot;The visibility CSS property shows or hides an element without changing the layout of a document.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The MDN definition brings up an important note - the visibility property does not change the layout of the document - this means the hidden elements will still take up space on the screen, which is different to the behaviour of &lt;code&gt;display:none&lt;/code&gt;. However, we can mitigate that in other ways if we need to deepending on what we&apos;re trying to do&lt;/p&gt;
&lt;p&gt;We can use the &lt;code&gt;visibility&lt;/code&gt; property to get what we want. For our example let&apos;s use a &lt;code&gt;ol&lt;/code&gt; with some children, however, we want anything inside of our list to be hidden other than a specific child&lt;/p&gt;
&lt;p&gt;The HTML we have is as follows:&lt;/p&gt;
&lt;p&gt;&amp;lt;HTMLSnippet path=&amp;quot;css-visibility/CSSVisibility.astro&amp;quot; lang=&amp;quot;html&amp;quot;&amp;gt;
&amp;lt;Example /&amp;gt;
&amp;lt;/HTMLSnippet&amp;gt;&lt;/p&gt;
&lt;p&gt;It&apos;s also important to note that the content before and after the list are not visible but they still take up space&lt;/p&gt;
&lt;p&gt;You can play around with the CSS properties below to see how the influence the overall styling:&lt;/p&gt;
&lt;p&gt;&amp;lt;CSSSnippet
html
path=&amp;quot;css-visibility/css-visibility.css&amp;quot;
variables={{
&apos;--show-visibility&apos;: {
initial: &apos;initial&apos;,
options: {
visible: &apos;visible&apos;,
hidden: &apos;hidden&apos;,
initial: &apos;initial&apos;
},
},
&apos;--show-display&apos;: {
initial: &apos;initial&apos;,
options: {
block: &apos;block&apos;,
hidden: &apos;none&apos;,
initial: &apos;initial&apos;
},
},
&apos;--hide-visibility&apos;: {
initial: &apos;initial&apos;,
options: {
visible: &apos;visible&apos;,
hidden: &apos;hidden&apos;,
initial: &apos;initial&apos;
},
},
&apos;--hide-display&apos;: {
initial: &apos;initial&apos;,
options: {
block: &apos;block&apos;,
hidden: &apos;none&apos;,
initial: &apos;initial&apos;
},
},&lt;/p&gt;
&lt;p&gt;}}&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;div class=&amp;quot;example&amp;quot;&amp;gt;
&amp;lt;div&amp;gt;before hidden&amp;lt;/div&amp;gt;
&amp;lt;ol class=&amp;quot;hide&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;Item 1&amp;lt;/li&amp;gt;
&amp;lt;li class=&amp;quot;show&amp;quot;&amp;gt;Item 2&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 3&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;div&amp;gt;after hidden&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/CSSSnippet&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>CSS @counter-style with Emojis</title><link>https://nabeelvalley.co.za/blog/2024/21-03/css-counter-style/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/21-03/css-counter-style/</guid><description>Using the Counter-style attribute in CSS</description><pubDate>Thu, 21 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Snippet from &apos;@/components/CSSSnippet.astro&apos;&lt;/p&gt;
&lt;p&gt;The CSS &lt;code&gt;@counter-style&lt;/code&gt; rule is used for defining list-styles in CSS&lt;/p&gt;
&lt;p&gt;The syntax is pretty simple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@counter-style &amp;lt;counter-style-name&amp;gt; {
  system: &amp;lt;cyclic|numeric|alphabetic|symblic|fixed&amp;gt;;
  symbols: &amp;lt;space separated list of symbols&amp;gt;;
  prefix: &amp;lt;content before symbol&amp;gt;;
  suffix: &amp;lt;content after symbol&amp;gt;;
  /* and some more options... */
  /* take a look at the MDN doc for all the customizations you can do, it&apos;s pretty cool */
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Currently &lt;code&gt;symbols&lt;/code&gt; just supports strings, but once fully supported it will also be possible to use images as symbols&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Cyclic Counter Style&lt;/h2&gt;
&lt;p&gt;For the sake of example, I&apos;ll be using Emojis as the symbols to display. We can define a cycle which uses some emojis like so:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;css-counter-style/cyclic.css&amp;quot; size=&amp;quot;s&amp;quot;&amp;gt;
&amp;lt;ul class=&amp;quot;emoji-cyclic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;Item 1&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 2&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 3&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 4&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 5&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 7&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 8&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 9&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 10&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/Snippet&amp;gt;&lt;/p&gt;
&lt;h2&gt;Numeric Counter Style&lt;/h2&gt;
&lt;p&gt;For this example, we&apos;ll use emoji numbers for the counter style&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet path=&amp;quot;css-counter-style/numeric.css&amp;quot; size=&amp;quot;s&amp;quot;&amp;gt;
&amp;lt;div&amp;gt;
&amp;lt;ol class=&amp;quot;emoji-numeric&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;Item 1&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 2&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 3&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 4&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 5&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;ol class=&amp;quot;emoji-numeric&amp;quot; start=&amp;quot;11&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;Item 11&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 12&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 13&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 14&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 15&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;ol class=&amp;quot;emoji-numeric&amp;quot; start=&amp;quot;111&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;Item 111&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 112&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 113&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 114&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Item 115&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/Snippet&amp;gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/@counter-style&quot;&gt;MDN @counter-style&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/predefined-counter-styles/&quot;&gt;W3C Predefined Counter Styles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://r12a.github.io/app-counters/&quot;&gt;Counter Style Converter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Use localStorage for Tab Synchronization</title><link>https://nabeelvalley.co.za/blog/2024/07-03/localstorage-based-sync/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/07-03/localstorage-based-sync/</guid><description>Synchronize data between browser tabs using localStorage</description><pubDate>Thu, 07 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import SynchronizedButton from &apos;@/snippets/localstorage-sync/SynchronizedButton.astro&apos;
import SynchronizedButtonRefactor from &apos;@/snippets/localstorage-sync/SynchronizedButtonRefactor.astro&apos;
import Snippet from &apos;@/components/Snippet.astro&apos;&lt;/p&gt;
&lt;h2&gt;localStorage&lt;/h2&gt;
&lt;p&gt;localStorage is a method for persistent data storage in the browser. The storage itself is a simple key-value store with a synchronous API&lt;/p&gt;
&lt;p&gt;We can write data to a given key using the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;window.localStorage.setItem(&apos;my-key&apos;, &apos;my-data&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can get that data back using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const myData = window.localStorage.getItem(&apos;my-key&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty neat right?&lt;/p&gt;
&lt;p&gt;For the purpose of this post we&apos;ll look into how we can use this as a method for sending data between different browser tabs of the same website&lt;/p&gt;
&lt;h2&gt;Storage Event&lt;/h2&gt;
&lt;p&gt;Aside from just data storage - localStorage (as well as sessionStorage) provides us with a notification when the data in a storage is changed - this is called a &lt;code&gt;StorageEvent&lt;/code&gt;. What&apos;s particularly interesting to us is that it&apos;s fired in all other tabs of a particular site when any a tab of that site modifies the data&lt;/p&gt;
&lt;p&gt;We can listen for this event using &lt;code&gt;window.addEventListener&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;window.addEventListener(&apos;storage&apos;, () =&amp;gt; {
  console.log(&apos;Something has changed in storage&apos;)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if you think about it for a short while, you may come to an interesting conclusion - we can talk to other tabs&lt;/p&gt;
&lt;h2&gt;Speaking to Tabs&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Open this page in two different windows side-by-side for this example&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since we can talk between tabs, we can synchronize parts of our UI using the messages we recieive&lt;/p&gt;
&lt;p&gt;Below we have a button that uses this - each time it is pressed in one tab - it updates the count in all tabs&lt;/p&gt;
&lt;p&gt;&amp;lt;SynchronizedButton /&amp;gt;&lt;/p&gt;
&lt;p&gt;The code for this can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet
base=&amp;quot;./src/snippets/localstorage-sync&amp;quot;
path=&amp;quot;SynchronizedButton.astro&amp;quot;
/&amp;gt;&lt;/p&gt;
&lt;h2&gt;Generic Implementation&lt;/h2&gt;
&lt;p&gt;So overall, this is a pretty neat method for sharing data between pages, but we end up having to do some repetitive work when setting this up in many places or when working with anything that isn&apos;t a string (as you can see with the &lt;code&gt;parseInt&lt;/code&gt;s required in the above example)&lt;/p&gt;
&lt;p&gt;To make this a little more generic we&apos;re first going to extract the getting and setting of data into their own functions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getValue = &amp;lt;T&amp;gt;(key: string, initial: T) =&amp;gt; {
  try {
    const existing = window.localStorage.getItem(key)
    if (!existing) {
      return initial
    }

    return JSON.parse(existing) as T
  } catch {
    return initial
  }
}

const setValue = &amp;lt;T&amp;gt;(key: string, value: T) =&amp;gt;
  window.localStorage.setItem(key, JSON.stringify(value))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These provide relatively simple wrappers around the reading and writing of data and making it possible for us to work with objects&lt;/p&gt;
&lt;p&gt;Next, we can provide an easy way to define a data reader and writer - the reason we define these separately is to make the interface a little easier for consumers to use without needing to rearrange all their code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export type SetValue&amp;lt;T&amp;gt; = (value: T) =&amp;gt; void

export const createSyncReader = &amp;lt;T&amp;gt;(
  key: string,
  initial: T,
  onChange: (value: T) =&amp;gt; void
) =&amp;gt; {
  window.addEventListener(&apos;storage&apos;, () =&amp;gt; {
    const value = getValue(key, initial)
    onChange(value)
  })

  return () =&amp;gt; getValue(key, initial)
}

export const createSyncWriter =
  &amp;lt;T&amp;gt;(key: string): SetValue&amp;lt;T&amp;gt; =&amp;gt;
  (value) =&amp;gt;
    setValue(key, value)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our reader function will call the provided &lt;code&gt;onChange&lt;/code&gt; callback that is provided to it when the data is changed with the parsed data. We can implement the same button as above using this new code as can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet
base=&amp;quot;./src/snippets/localstorage-sync&amp;quot;
path=&amp;quot;SynchronizedButtonRefactor.astro&amp;quot;
/&amp;gt;&lt;/p&gt;
&lt;p&gt;And for the the sake of being complete, we can see the refactored button running below:&lt;/p&gt;
&lt;p&gt;&amp;lt;SynchronizedButtonRefactor /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Further Reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage&quot;&gt;MDN localStorage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event&quot;&gt;MDN storage event&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>View Transitions and an Astro Presentation Framework</title><link>https://nabeelvalley.co.za/blog/2024/06-03/astro-slides/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2024/06-03/astro-slides/</guid><description>Easily create presentations from your existing markdown content</description><pubDate>Wed, 06 Mar 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import { Slide, Presentation, SlideOnly } from &apos;@/components/slides&apos;
import Snippet from &apos;@/components/Snippet.astro&apos;&lt;/p&gt;
&lt;p&gt;Well, since this is a post about building a presentation framework within your Astro site, it may be worth mentioning that you can view this page as a presentation using the below button:&lt;/p&gt;
&lt;p&gt;&amp;lt;Presentation /&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;m kind of lazy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;I had to put together a little presentation based on something I&apos;ve written about previously and wanted a lazy way to reuse my existing content while also making the resulting presentation available on my website&lt;/p&gt;
&lt;p&gt;Overall, these are the requirements I had in mind:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h3&gt;My Requirements&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Not require any additional build process&lt;/li&gt;
&lt;li&gt;Work with Markdown or MDX so I can include it in my website easily&lt;/li&gt;
&lt;li&gt;Have a small learning curve&lt;/li&gt;
&lt;li&gt;Integrate flexibly with my existing content - pages should be able to be very easily converted to slides&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;So I investigated a few solutions:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h3&gt;Existing Slide Solutions&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Just a markdown doc&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://revealjs.com/&quot;&gt;Reveal.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jxnblk/mdx-deck&quot;&gt;MDX Deck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/FormidableLabs/spectacle&quot;&gt;Spectacle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Plain&apos; ol&apos; HTML&lt;/li&gt;
&lt;li&gt;PowerPoint??&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The existing solutions just don&apos;t work for my case&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Now, it&apos;s not that they&apos;re not good - most of them are pretty great and have some features that I would like to use if this were some once-off throwaway presentation, but since I would like to refer back to and manage the way I want they&apos;re not really suitable&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I also didn&apos;t want to style everything from scratch or write lots of HTML everywhere&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;&lt;/p&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;&amp;lt;SlideOnly&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Build it myself. Obviously&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;/SlideOnly&amp;gt;
&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Instead of just looking at the existing options, I instead chose to build a library/framework that would work with my existing Astro site while keeping the implementation relatively minimal and just depending on plain CSS, Javascript, MDX, and Astro to get the job done&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;
&amp;lt;SlideOnly&amp;gt;&lt;/p&gt;
&lt;h3&gt;Use Existing Tooling&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;Javascript (Typescript)&lt;/li&gt;
&lt;li&gt;MDX&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Facilitated by - not coupled to - Astro&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;/SlideOnly&amp;gt;
&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;So, since I&apos;m building it myself, that means code - and that&apos;s what we&apos;re going to look at&lt;/p&gt;
&lt;h3&gt;The API&lt;/h3&gt;
&lt;p&gt;I wanted to keep the API relatively simple. It should work with existing markdown content and allow me to delineate a slide in a way that can be easily read from the DOM so as to minimize the amount of build-time processing I need to do as well as minimize how much markup I need to write. For this purpose, I decided that I want it to fit into an MDX document like so:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;
&amp;lt;SlideOnly&amp;gt;&lt;/p&gt;
&lt;h3&gt;The API&lt;/h3&gt;
&lt;p&gt;&amp;lt;/SlideOnly&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-mdx&quot;&gt;Button to launch the presentation

&amp;lt;Presentation /&amp;gt;

... Existing page content

&amp;lt;Slide&amp;gt;
## Heading for Slide

Some content for the slide

```js
console.log(&apos;I am a code block&apos;)
```

&amp;gt; And literally any other markdown content

&amp;lt;/Slide&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Hiven the above, I had a high level idea that I would need two parts to this - firstly I want to use the &lt;code&gt;Slide&lt;/code&gt; component to give me something to latch onto in the HTML that I can manipulate, secondly I know I would need some kind of component that would control the overall presentation state, I called that &lt;code&gt;Presentation&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;Slide&lt;/code&gt; Component&lt;/h3&gt;
&lt;p&gt;The Slide component is simply a wrapper that includes content in an HTML section with a class &lt;code&gt;presentation-slide&lt;/code&gt; which will contain the contents of a slide&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;
&amp;lt;SlideOnly&amp;gt;&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;Slide&lt;/code&gt; Component&lt;/h3&gt;
&lt;p&gt;&amp;lt;/SlideOnly&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;components/Slide.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;section class=&amp;quot;presentation-slide&amp;quot;&amp;gt;
  &amp;lt;slot /&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;Presentation&lt;/code&gt; Component&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Presentation&lt;/code&gt; component needs to do a few different things:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;
&amp;lt;SlideOnly&amp;gt;&lt;/p&gt;
&lt;h3&gt;The &lt;code&gt;Presentation&lt;/code&gt; Component&lt;/h3&gt;
&lt;p&gt;&amp;lt;/SlideOnly&amp;gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hide presentation until enabled&lt;/li&gt;
&lt;li&gt;Allow navigation of slides&lt;/li&gt;
&lt;li&gt;Render slide content above existing page&lt;/li&gt;
&lt;li&gt;Manage transitions between slide pages&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Firstly, we can just take a look at the HTML that we will render contains a few basic elements as well as a script tag that grabs a reference to these elements. The &lt;code&gt;presentation-hidden&lt;/code&gt; class is used for hiding or showing the presentation when active/inactive:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;
&amp;lt;SlideOnly&amp;gt;&lt;/p&gt;
&lt;h3&gt;Basic Elements&lt;/h3&gt;
&lt;p&gt;&amp;lt;/SlideOnly&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;button id=&amp;quot;presentation-button&amp;quot; class=&amp;quot;presentation-hidden&amp;quot; type=&amp;quot;button&amp;quot;&amp;gt;
  Start Presentation
&amp;lt;/button&amp;gt;

&amp;lt;div
  id=&amp;quot;presentation-container&amp;quot;
  class=&amp;quot;presentation-hidden presentation-overflow-hidden&amp;quot;
&amp;gt;
  &amp;lt;main id=&amp;quot;presentation-content&amp;quot;&amp;gt;
    &amp;lt;h1&amp;gt;No slides found on page&amp;lt;/h1&amp;gt;
  &amp;lt;/main&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
  const button = document.getElementById(&apos;presentation-button&apos;) as HTMLButtonElement
  const container = document.getElementById(&apos;presentation-container&apos;) as HTMLDivElement
  const content = document.getElementById(&apos;presentation-content&apos;) as HTMLDivElement
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Next, we can grab the actual slide content by using the &lt;code&gt;presentation-slide&lt;/code&gt; class we defined earlier:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide centered&amp;gt;&lt;/p&gt;
&lt;h3&gt;Get Slides&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;let slides = Array.from(document.querySelectorAll(&apos;.presentation-slide&apos;)).map(
  (el) =&amp;gt; el.outerHTML,
)

let slide = 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Once we have the content of the slides and a variable to track which slide we are on, we can define a function that will set the slide content. This will set the &lt;code&gt;innerHTML&lt;/code&gt; of the &lt;code&gt;content&lt;/code&gt; element to the &lt;code&gt;slide&lt;/code&gt; that is active. We can handle this by first defining some utilities for grabbing the next and previous slides as well as mapping a key code to the function that will resolve the next slide&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;
&amp;lt;SlideOnly&amp;gt;&lt;/p&gt;
&lt;h2&gt;Slide Utilities&lt;/h2&gt;
&lt;p&gt;&amp;lt;/SlideOnly&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const nextSlide = () =&amp;gt; {
  if (slide === slides.length - 1) {
    return slide
  }

  return slide + 1
}

const prevSlide = () =&amp;gt; {
  if (slide === 0) {
    return slide
  }

  return slide - 1
}

const keyHandlers: Record&amp;lt;string, () =&amp;gt; number&amp;gt; = {
  ArrowRight: nextSlide,
  ArrowLeft: prevSlide,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Next, we can define what it means for us to start and end a presentation. For this example, starting a presentation will remove the &lt;code&gt;presentation-hidden&lt;/code&gt; class from the main wrapper so we can make the presentation visible on the page as well as set the content to the current slide index (we initialized this to &lt;code&gt;0&lt;/code&gt; above)&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h2&gt;Start and End Presentation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const startPresentation = () =&amp;gt; {
  container.classList.remove(&apos;presentation-hidden&apos;)
  if (slides.length) {
    content.innerHTML = slides[slide]
  }
}

const endPresentation = () =&amp;gt; {
  container.classList.add(&apos;presentation-hidden&apos;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;We set the content to &lt;code&gt;slide&lt;/code&gt; instead of &lt;code&gt;0&lt;/code&gt; so that we can pause and continue the presentation if we wanted to&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Next, hook up some event handlers so that we can have a method for controlling our presentation:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h3&gt;Wiring things up&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// If there is no presentation on the page then we don&apos;t initialize
if (slides.length) {
  button.addEventListener(&apos;click&apos;, startPresentation)

  window.addEventListener(&apos;keyup&apos;, (ev) =&amp;gt; {
    const isEscape = ev.key === &apos;Escape&apos;
    if (isEscape) {
      endPresentation()
      return
    }

    const getSlide = keyHandlers[ev.key]

    if (!getSlide) {
      return
    }

    const nextSlide = getSlide()
    if (slide === nextSlide) {
      return
    }

    slide = nextSlide
    content.innerHTML = slides[slide]
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the above, the left and right arrows are used to navigate slides and the escape key is used to end the presentation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next up, we need to add some CSS to make the slides pin to the root of our application above everything else so that you can actually use this:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h3&gt;Styling&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;style is:global&amp;gt;
  .presentation-overflow-hidden {
    overflow: hidden;
  }

  .presentation-hidden {
    display: none;
  }

  #presentation-container {
    z-index: 10;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: auto;

    backdrop-filter: blur(50px);
    background-color: #0000007d;
  }

  #presentation-content {
    display: flex;
    flex-direction: column;

    background-color: black;
    color: white;

    box-sizing: border-box;
    min-height: 100vh;
    width: 100%;
    padding: 4rem;
  }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;And that&apos;s pretty much it for the core implementation. One other piece of fanciness that I wanted to add was the ability to make an actual slide transition. To do this I decided to use the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API&quot;&gt;View Transitions API&lt;/a&gt; and found a few nice references on the &lt;a href=&quot;https://philnash.github.io/unnecessary-view-transitions&quot;&gt;Unecesssary View Transitions API List&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In order to use this you need to have the feature enabled in your browser at the moment but it should be stable soon (I hope)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For this implementation, we will need to have different animations for the case where we are moving forwards or backwards. In order to do this, we will define some classes as part of our keyboard handler resolution that we will append to the &lt;code&gt;presentation-container&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h3&gt;View Transitions&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const nextClass = &apos;presentation-next&apos;
const prevClass = &apos;presentation-prev&apos;

const transitionClasses = [nextClass, prevClass]

const keyHandlers: Record&amp;lt;string, [string, () =&amp;gt; number]&amp;gt; = {
  ArrowRight: [nextClass, nextSlide],
  ArrowLeft: [prevClass, prevSlide],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Then, we will update our event handling logic to set these classes on the &lt;code&gt;contaienr&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h4&gt;Setting the Classes&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const [transitionClass, getSlide] = handler

content.classList.remove(...transitionClasses)
content.classList.add(transitionClass)

const nextSlide = getSlide()
if (slide === nextSlide) {
  return
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Then, instead just setting the &lt;code&gt;content.innerHTML&lt;/code&gt; directly, we do it within the &lt;code&gt;document.startViewTransition&lt;/code&gt; callback which will be what handles the state transition between the content leaving the DOM and the new content that is entering the DOM&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that the &lt;code&gt;startViewTransition&lt;/code&gt; API is experimental and typescript may complain, you will need to install &lt;code&gt;@types/dom-view-transitions&lt;/code&gt; which will provide the type definition you need to use this API&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h4&gt;Starting the Transition&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;document.startViewTransition(() =&amp;gt; {
  slide = nextSlide
  content.innerHTML = slides[slide]
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;The last thing we need to do is define the view transitions for when the content enters and exists the DOM. The transitions are defined in the &lt;code&gt;style&lt;/code&gt; tag of our component as follows:&lt;/p&gt;
&lt;p&gt;Firstly we need to&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h4&gt;Animations&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;@keyframes slide-out-right {
  0% {
    transform: translateX(0) scale(1);
  }
  15% {
    transform: translateX(0) scale(0.8) translateY(0%);
  }
  85% {
    transform: translateX(100%) scale(0.8) translateY(0%);
  }
  100% {
    transform: translateX(100%) scale(1);
  }
}

@keyframes slide-out-left {
  0% {
    transform: translateX(0) scale(1);
  }
  15% {
    transform: translateX(0) scale(0.8) translateY(0%);
  }
  85% {
    transform: translateX(-100%) scale(0.8) translateY(0%);
  }
  100% {
    transform: translateX(-100%) scale(1);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;The above defines two basic animations that we will use for our transitions. We define an animation that moves an element off the screen to the right called &lt;code&gt;slide-out-right&lt;/code&gt; and another to move it to the left called &lt;code&gt;slide-out-left&lt;/code&gt;. These animations can also be reversed to slide content in from the right or left respectively&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;For the &amp;quot;Next&amp;quot; animation we need to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Slide the old content to the left&lt;/li&gt;
&lt;li&gt;Slide the new content from the right&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;In the below we set that the &lt;code&gt;presentation-next&lt;/code&gt; class defines a &lt;code&gt;view-transition-name&lt;/code&gt; called &lt;code&gt;next&lt;/code&gt;. Then, we define the transitions for the &lt;code&gt;old&lt;/code&gt; and &lt;code&gt;new&lt;/code&gt; content that applies to the &lt;code&gt;next&lt;/code&gt; transition name as an Animation. We are referencing a &lt;code&gt;slide-out-right&lt;/code&gt; and &lt;code&gt;slide-out-left&lt;/code&gt; animations which we defined previously:&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h4&gt;CSS Transitions&lt;/h4&gt;
&lt;p&gt;Below is the transition for moving to the next slide&lt;/p&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.presentation-next {
  view-transition-name: next;
}

::view-transition-old(next) {
  animation: slide-out-left 0.5s linear;
}
::view-transition-new(next) {
  animation: slide-out-right 0.5s linear reverse;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;view-transition-old&lt;/code&gt; refers to content that is being removed from the DOM, &lt;code&gt;view-transition-new&lt;/code&gt; refers to the content that is being added to the DOM&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Lastly, the implementation for the &lt;code&gt;presentation-prev&lt;/code&gt; we can reuse the same animations for moving left or right as we defined previously, but change the directions as needed for the relevant section&lt;/p&gt;
&lt;p&gt;&lt;code&gt;components/Presentation.astro&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.presentation-prev {
  view-transition-name: prev;
}

::view-transition-old(prev) {
  animation: slide-out-right 0.5s linear;
}
::view-transition-new(prev) {
  animation: slide-out-left 0.5s linear reverse;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And yes, that&apos;s a fair amount of code. All-in it&apos;s about 200 lines - most of which is the CSS for the transition though. Generally the implementation is pretty straightforward and should be relatively easy to tweak to match the vibe of your website without adding any dependency bloat.&lt;/p&gt;
&lt;p&gt;As it stands right now the implementation is pretty simple but leaves a lot of space to be extended&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h3&gt;Added since this post was written&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[x] Presenter mode with some kind of synchronized state for multiple monitors (LocalStorage?)&lt;/li&gt;
&lt;li&gt;[x] Progress tracking&lt;/li&gt;
&lt;li&gt;[x] Support for non-static components&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Future Ideas&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[ ] Presenter notes and preview of next slide&lt;/li&gt;
&lt;li&gt;[ ] Make this a library so other people can use it with less copy pasta&lt;/li&gt;
&lt;li&gt;[ ] More transitions and styling possibilities&lt;/li&gt;
&lt;li&gt;[ ] Dynamic code blocks/customizable transitions (&lt;a href=&quot;https://github.com/pomber/code-surfer&quot;&gt;Code Surfer&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Automatic zooming&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Slide&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We used some interesting CSS here and overall we can see that it&apos;s not alays a huge amount of work to write your own implementation of something.&lt;/p&gt;
&lt;p&gt;&amp;lt;/Slide&amp;gt;&lt;/p&gt;
&lt;p&gt;Additionally, for the sake of completeness - since this component is alive and ever changing within this website - you can view the current state of the code (sans commentary) below&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet base=&amp;quot;./src/components/slides&amp;quot; path=&amp;quot;Slide.astro&amp;quot; lang=&amp;quot;html&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet base=&amp;quot;./src/components/slides&amp;quot; path=&amp;quot;Presentation.astro&amp;quot; lang=&amp;quot;html&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API&quot;&gt;MDN View Transitions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/web-platform/view-transitions&quot;&gt;Smooth and simple transitions with the View Transitions API &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://philnash.github.io/unnecessary-view-transitions&quot;&gt;Unnecessary View Transitions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Interacting with Kafka with Kotlin Coroutines</title><link>https://nabeelvalley.co.za/blog/2023/11-11/interacting-with-kafka-using-kotlin/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/11-11/interacting-with-kafka-using-kotlin/</guid><description>Producing, Consuming, and Processing Kafka Event Streams</description><pubDate>Thu, 09 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;The purpose of this post is to illustrate a method of interacting with Kafka using Kotlin in a functional programming style while using Kotlin coroutines for a multi-threading. We will be interacting with the &lt;a href=&quot;https://docs.confluent.io/kafka-clients/java/current/overview.html&quot;&gt;Kafka Client for Java&lt;/a&gt; and will be building a small library on top of this for the purpose of simplifying communication and handling tasks like JSON Serialization&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you would like to view the completed source code, you can take a look at the &lt;a href=&quot;https://github.com/nabeelvalley/kotlin-kafka&quot;&gt;kotlin-kafka GitHub repository&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Kafka&lt;/h3&gt;
&lt;p&gt;According to then &lt;a href=&quot;https://kafka.apache.org/&quot;&gt;Kafka Website&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Apache Kafka is an open-source distributed event streaming platform:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Generally we can think of Kafka as a platform that enables us to connect data producers to data.&lt;/p&gt;
&lt;p&gt;Kafka is an event platform that provides us with a few core functions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Publishing and subscribing event data&lt;/li&gt;
&lt;li&gt;Processing of events in real-time or retrospectively&lt;/li&gt;
&lt;li&gt;Storage of event streams&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;From a more detailed perspective, Kafka internally handles storage of event streams, but we are given control over the means of data production, consumption, and processing via the Kafka API, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Producer API for production&lt;/li&gt;
&lt;li&gt;The Consumer API for subscription&lt;/li&gt;
&lt;li&gt;The Streams API for processing stream data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Kotlin&lt;/h3&gt;
&lt;p&gt;Kotlin is a statically typed programming language built on the Java Virtual Machine that provides interop with Java code&lt;/p&gt;
&lt;h2&gt;The Code&lt;/h2&gt;
&lt;h3&gt;Config&lt;/h3&gt;
&lt;p&gt;To get some admin stuff out of the way, before you can really do any of this you will to have a &lt;code&gt;.env&lt;/code&gt; file in the project that you can load which contains some application configuration, for the purpose of our application we require the following config in this file - below is some example content&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;BOOTSTRAP_SERVERS=my-server-url:9092
SASL_JAAS_CONFIG=org.apache.kafka.common.security.scram.ScramLoginModule required username=&amp;quot;someUsername&amp;quot; password=&amp;quot;somePassword&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, we have some non-sensitive config in our &lt;code&gt;application.properties&lt;/code&gt; file in our application &lt;code&gt;resources&lt;/code&gt; folder which contains the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;resources/application.properties&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-properties&quot;&gt;sasl.mechanism=SCRAM-SHA-256
security.protocol=SASL_SSL
key.serializer=org.apache.kafka.common.serialization.StringSerializer
key.deserializer=org.apache.kafka.common.serialization.StringDeserializer
value.serializer=org.apache.kafka.common.serialization.StringSerializer
value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
auto.offset.reset=earliest
group.id=$GROUP_NAME
application.id=example-app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we need to load this in our application to create a &lt;code&gt;Properties&lt;/code&gt; object along with all the other application config we require. We can create the Properties object using the &lt;code&gt;application.properties&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; files as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package example

import io.github.cdimascio.dotenv.Dotenv
import java.io.FileInputStream
import java.util.*

fun loadProperties(): Properties {
    val props = Properties()
    val resource = ClassLoader.getSystemResource(&amp;quot;application.properties&amp;quot;)
    println(&amp;quot;File  path: ${resource.path}&amp;quot;)
    FileInputStream(resource.path).use { stream -&amp;gt;
        props.load(stream)
    }

    val dotenv = Dotenv.load()
    props[&amp;quot;bootstrap.servers&amp;quot;] = dotenv[&amp;quot;BOOTSTRAP_SERVERS&amp;quot;]
    props[&amp;quot;sasl.jaas.config&amp;quot;] = dotenv[&amp;quot;SASL_JAAS_CONFIG&amp;quot;]

    return props
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above example uses the &lt;code&gt;io.github.cdimascio:dotenv-java:3.0.0&lt;/code&gt; package for loading the environment variables and some builtin Java utilities for loading the application properties file&lt;/p&gt;
&lt;p&gt;Next, for the purpose of using it with our library we will create a &lt;code&gt;Config&lt;/code&gt; class that wraps the properties file we defined so that we can use this a little more elegantly in our consumers. Realistically we probably should do some validation on the resulting &lt;code&gt;Properties&lt;/code&gt; that we load in but we&apos;ll just keep it simple and define &lt;code&gt;Config&lt;/code&gt; as a class that contains the &lt;code&gt;properties&lt;/code&gt; as a property:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Config.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import java.util.Properties

open class Config(internal val properties: Properties) {}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Working with JSON Data&lt;/h3&gt;
&lt;p&gt;An important part of what we want our client to handle is the JSON serialization and deserialization when sending data to Kafka. Sending JSON data is not a requirement of Kafka as a platform, but it&apos;s the usecase that we&apos;re building our library around and so is something we need to consider&lt;/p&gt;
&lt;h4&gt;Serialization&lt;/h4&gt;
&lt;p&gt;Serialization in this context refers to the process of converting our Kotlin classes into a string and back to a Kotlin class. For this discussion we will refer to a class that is able to do this bidirectional conversion as a &lt;code&gt;Serializer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We can define generic representation of a serializer as a class that contains a method callsed &lt;code&gt;serialize&lt;/code&gt; that takes in data of type &lt;code&gt;T&lt;/code&gt; and returns a string, and contains a method called &lt;code&gt;deserialize&lt;/code&gt; that takes in a string and returns an object of type &lt;code&gt;T&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Not that at this point we&apos;re not considering that the serializer needs to return JSON. In our context a JSON serializer is just a specific implementation of the serialization concept that we have defined&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;An interface that describes the &lt;code&gt;Serializer&lt;/code&gt; we mentioned above can be seen as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Serializer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

interface ISerializer&amp;lt;T : Any&amp;gt; {
    fun serialize(data: T): String
    fun deserialize(data: String): T
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;JSON Serialization&lt;/h4&gt;
&lt;p&gt;Given the definition of a serializer we can define a JSON serializer that uses the &lt;code&gt;kotlinx.serialization&lt;/code&gt; library and implements our &lt;code&gt;ISerializer&lt;/code&gt; as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;JsonSerializer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import kotlin.reflect.KClass

class JsonSerializer&amp;lt;T : Any&amp;gt;(type: KClass&amp;lt;T&amp;gt;) : ISerializer&amp;lt;T&amp;gt; {
    private val serializer: KSerializer&amp;lt;T&amp;gt; = serializer(type.java) as KSerializer&amp;lt;T&amp;gt;

    override fun serialize(data: T): String = Json.encodeToString(serializer, data)

    override fun deserialize(data: String): T = Json.decodeFromString(serializer, data)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code is a little funky since we&apos;re using reflection on the actual class of the input data to define our serializer, other than we&apos;re just using the &lt;code&gt;kotlinx&lt;/code&gt; serializer to handle the data transformation. The thing that matters in this context is that we are able abstract the reflection aspect of the serializer, this will help make the final interface we provide to the user for working with Kafka simpler&lt;/p&gt;
&lt;h4&gt;Serde Serializer&lt;/h4&gt;
&lt;p&gt;Now that we have defined a simple representation of a serializer that provides some interop with the Kotlin data types, we need to implement the other side of this which is a &lt;code&gt;SerdeSerializer&lt;/code&gt; which is what the Kafka Clients need to work with. The requirements of this serializer are a little different to the one we defined above. This serializer needs to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Have a separate &lt;code&gt;Serializer&lt;/code&gt; and &lt;code&gt;Deserializer&lt;/code&gt; interfaces that need to be implemented&lt;/li&gt;
&lt;li&gt;Return a &lt;code&gt;ByteArray&lt;/code&gt; instead of &lt;code&gt;String&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can define these serializers such that they can be constructed from and &lt;code&gt;ISerializer&lt;/code&gt; interface that we defined previously. This will make it possible for consumers of our library to swap our their serialization strategy to enable other usecases than the simple JSON communication we are considering&lt;/p&gt;
&lt;p&gt;As mentioned above, we need to implement a separate &lt;code&gt;Serializer&lt;/code&gt; and &lt;code&gt;Deserializer&lt;/code&gt; respecively as:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SerdeSerializer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import org.apache.kafka.common.serialization.Serializer

class SerdeSerializer&amp;lt;T : Any&amp;gt;(private val serializer: ISerializer&amp;lt;T&amp;gt;) : Serializer&amp;lt;T&amp;gt; {
    override fun serialize(topic: String?, data: T): ByteArray {
        val result = serializer.serialize(data)
        return result.toByteArray()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SerdeDeserializer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import org.apache.kafka.common.serialization.Deserializer

class SerdeDeserializer&amp;lt;T : Any&amp;gt;(private val serializer: ISerializer&amp;lt;T&amp;gt;) : Deserializer&amp;lt;T?&amp;gt; {
    override fun deserialize(topic: String?, data: ByteArray?): T? {
        try {
            val string = String(data!!)
            return serializer.deserialize(string)
        } catch (error: Error) {
            println(&amp;quot;Error Deserializing Data: $error&amp;quot;)
            return null
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Our implementation is a little basic and will just ignore any data that we can&apos;t serialize, however depending on our usecase we may need to handle this differently&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Lastly, we define the actual &lt;code&gt;Serde&lt;/code&gt; Serializer implementation using the above implementations:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Serializer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import org.apache.kafka.common.serialization.Serde

class Serializer&amp;lt;T : Any&amp;gt;(private val serializer: ISerializer&amp;lt;T&amp;gt;) : Serde&amp;lt;T&amp;gt; {
    override fun serializer() = SerdeSerializer&amp;lt;T&amp;gt;(serializer)

    override fun deserializer() = SerdeDeserializer&amp;lt;T&amp;gt;(serializer)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As far as serialization and deserialization goes, this should be everything we need for working with JSON data&lt;/p&gt;
&lt;h3&gt;Producing Data&lt;/h3&gt;
&lt;p&gt;Producing data is a method by which a client sends data to a Kafka topic. We can define this as a type as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Producer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;typealias Send&amp;lt;T&amp;gt; = (topic: String, message: T) -&amp;gt; Unit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, to provide a functional library interface we will want to provider application code a space in which they will be able to work with the producer that we populate without needing to create a new producer for each message we want to send&lt;/p&gt;
&lt;p&gt;We&apos;ll codify this intent as a type as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Producer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;typealias Produce&amp;lt;T&amp;gt; = suspend (send: Send&amp;lt;T&amp;gt;) -&amp;gt; Unit
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that we define this as a &lt;code&gt;suspend&lt;/code&gt; function that will enable users to send messages from within a coroutine context&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next, we define the type of our producer as method with a way to create a producer instance for users who may want to manage the lifecycle of the &lt;code&gt;KafkaProducer&lt;/code&gt; on their own. This however also means they lose access to the automatic serialization and deserialization that we will provide via our &lt;code&gt;producer&lt;/code&gt; method&lt;/p&gt;
&lt;p&gt;This interface is defined as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Producer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import org.apache.kafka.clients.producer.KafkaProducer
import java.util.*

interface IProducer&amp;lt;T&amp;gt; {
    /**
     * Returns the raw producer used by Kafka
     */
    fun createProducer(): KafkaProducer&amp;lt;String, String&amp;gt;
    fun produce(callback: Produce&amp;lt;T&amp;gt;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the purpose of our implementation we can define some functions ourside of our class that will provde the implementation we require&lt;/p&gt;
&lt;p&gt;For the &lt;code&gt;createProducer&lt;/code&gt; function, we simply provide a wrapper around the &lt;code&gt;KafkaProducer&lt;/code&gt; provided to us by the Java Kafka Client Library:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Producer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import org.apache.kafka.clients.producer.KafkaProducer
import org.apache.kafka.clients.producer.ProducerRecord
import java.util.*
import kotlinx.coroutines.runBlocking

fun createProducer(properties: Properties) =
    KafkaProducer&amp;lt;String, String&amp;gt;(properties)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the sake of consistency, we will do the same for the concept of a &lt;code&gt;ProducerRecord&lt;/code&gt; which will be used by the produce function:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Producer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;fun createRecord(topic: String, message: String) =
    ProducerRecord&amp;lt;String, String&amp;gt;(topic, message)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, the &lt;code&gt;produce&lt;/code&gt; function can be defined. The role of this function is to handle serialization of data and provide a means for a user to send data to a topic&lt;/p&gt;
&lt;p&gt;The producer will take a callback which is the context in which any usage of the &lt;code&gt;send&lt;/code&gt; function should be used before the producer is disposed:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Producer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;fun &amp;lt;T : Any&amp;gt; produce(properties: Properties, serializer: ISerializer&amp;lt;T&amp;gt;, callback: Produce&amp;lt;T&amp;gt;) {
    createProducer(properties).use { producer -&amp;gt;
        val send = fun(topic: String, message: T) {
            val payload = serializer.serialize(message)
            val record = createRecord(topic, payload)
            producer.send(record)
        }

        runBlocking {
            callback(send)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have also added the &lt;code&gt;properties&lt;/code&gt; and &lt;code&gt;serializer&lt;/code&gt; values as an input to the producer as this is needed by Kafka, lastly, we will define our actual &lt;code&gt;Producer&lt;/code&gt; implementation which builds on the functions we defined above&lt;/p&gt;
&lt;p&gt;Note that our &lt;code&gt;Producer&lt;/code&gt; class implements &lt;code&gt;IProducer&lt;/code&gt; and extends &lt;code&gt;Config&lt;/code&gt;, this is because we use the &lt;code&gt;Config&lt;/code&gt; class as the source of truth of the configuration to be used for our Kafka instance and we want to able to access this config&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Producer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;class Producer&amp;lt;T : Any&amp;gt;(
    properties: Properties,
    private val serializer: ISerializer&amp;lt;T&amp;gt;
) : Config(properties),
    IProducer&amp;lt;T&amp;gt; {
    override fun createProducer() = createProducer(properties)

    override fun produce(callback: Produce&amp;lt;T&amp;gt;) = produce&amp;lt;T&amp;gt;(properties, serializer, callback)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point we have a complete implementation of a producer&lt;/p&gt;
&lt;h4&gt;Using the Producer&lt;/h4&gt;
&lt;p&gt;In our application code we can instantiate and use the producer as follows:&lt;/p&gt;
&lt;p&gt;Firstly, we need to define the type of data we are goind to send with the &lt;code&gt;@Serializable&lt;/code&gt; annotation&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;import kotlinx.coroutines.*
import kotlinx.serialization.Serializable
import za.co.nabeelvalley.kafka.*
import java.util.*


@Serializable
data class ProducerData(val message: String, val key: Int)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can define a function for producing data, this will require the &lt;code&gt;properties&lt;/code&gt; we loaded previously:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;fun instantiateAndProduce(properties: Properties): Unit {
    val serializer = JsonSerializer(ProducerData::class)
    val producer = Producer(properties, serializer)

    runBlocking {
        producer.produce { send -&amp;gt;
            val data = ProducerData(&amp;quot;Hello world&amp;quot;, 1)
            send(&amp;quot;my-topic&amp;quot;, data)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We use &lt;code&gt;runBlocking&lt;/code&gt; since our producer needs a coroutine scope in which to send data. Sending data us used within the &lt;code&gt;produce&lt;/code&gt; method in which we create some data and call the &lt;code&gt;send&lt;/code&gt; method provide by the &lt;code&gt;produce&lt;/code&gt; function&lt;/p&gt;
&lt;p&gt;An interesting to note is that we are passing the &lt;code&gt;class&lt;/code&gt; of our data to the serializer to create an instance - this is the usage of the funky reflection thing we saw previously&lt;/p&gt;
&lt;h3&gt;Consuming Data&lt;/h3&gt;
&lt;p&gt;Our code for consuming data will follow a similar pattern to what we use to consume the data in the previous section&lt;/p&gt;
&lt;p&gt;For consuming data, Kafka relies on the concept of polling for records from the part of the consumer, for our client, we will expose using the following type which defines a poll as a method that takes nothing and returns a list of data of type &lt;code&gt;T&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Consumer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;typealias Poll&amp;lt;T&amp;gt; = () -&amp;gt; List&amp;lt;T&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can define the type that defines how we want our data to be consumed. For our sake, this is a suspend function that will receive a poll method that it can call to get data&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Consumer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;typealias Consume&amp;lt;T&amp;gt; = suspend (poll: Poll&amp;lt;T&amp;gt;) -&amp;gt; Unit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, as before, we can define an interface for a &lt;code&gt;Consumer&lt;/code&gt; in which we have a method to create a &lt;code&gt;KafkaConsumer&lt;/code&gt; and a method for actually consuming the data. In the case of consuming we need a list of topics to read from as well as the polling frequency duration.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Consumer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import kotlinx.coroutines.runBlocking
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.clients.consumer.KafkaConsumer
import java.time.Duration
import java.util.*

interface IConsumer&amp;lt;T&amp;gt; {
    /**
     * Returns the raw consumer used by Kafka
     */
    fun createConsumer(): KafkaConsumer&amp;lt;String, String&amp;gt;
    fun consume(topics: List&amp;lt;String&amp;gt;, duration: Long, callback: Consume&amp;lt;T&amp;gt;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can define our &lt;code&gt;createConsumer&lt;/code&gt; method quite simply as:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Consumer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;fun createConsumer(properties: Properties) =
    KafkaConsumer&amp;lt;String, String&amp;gt;(properties)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can define our &lt;code&gt;consume&lt;/code&gt; method such that it takes in the &lt;code&gt;properties&lt;/code&gt; and &lt;code&gt;serializer&lt;/code&gt; as with the producer, but will also take som &lt;code&gt;patterns&lt;/code&gt; to be used for subscribing to and the &lt;code&gt;duration&lt;/code&gt; above, and finally the callback &lt;code&gt;Consume&lt;/code&gt; function:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Consumer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;fun &amp;lt;T : Any&amp;gt; consume(
   properties: Properties,
   serializer: ISerializer&amp;lt;T&amp;gt;,
   patterns: List&amp;lt;String&amp;gt;,
   duration: Long,
   callback: Consume&amp;lt;T&amp;gt;
) {
   createConsumer(properties).use { consumer -&amp;gt;
      consumer.subscribe(patterns)
      val poll = fun(): List&amp;lt;T&amp;gt; {
         val records = consumer.poll(Duration.ofMillis(duration))
         val data = records.toList()
               .map(ConsumerRecord&amp;lt;String, String&amp;gt;::value)
               .map(serializer::deserialize)

         return data
      }

      runBlocking {
         callback(poll)
      }
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;consume&lt;/code&gt; function is very similar to the &lt;code&gt;produce&lt;/code&gt; function we defined previously, however now instead of being provided a function to send data we now have a function that will return that data&lt;/p&gt;
&lt;p&gt;Lastly, we can finish off the definition of our &lt;code&gt;Consumer&lt;/code&gt; using what we have above:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Consumer.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;class Consumer&amp;lt;T : Any&amp;gt;(
    properties: Properties,
    private val serializer: ISerializer&amp;lt;T&amp;gt;
) : Config(properties), IConsumer&amp;lt;T&amp;gt; {
    override fun createConsumer() = createConsumer(properties)

    override fun consume(topics: List&amp;lt;String&amp;gt;, duration: Long, callback: Consume&amp;lt;T&amp;gt;) =
        consume(properties, serializer, topics, duration, callback)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Using the Consumer&lt;/h4&gt;
&lt;p&gt;Using the &lt;code&gt;Consumer&lt;/code&gt; follows a very similar pattern to the producer, however we need to create a loop that will poll for data and handle as necessary when data is received:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;@Serializable
data class ConsumerData(val message: String, val key: Int)

fun instantiateAndConsume(properties: Properties): Unit {
   val serializer = JsonSerializer(ConsumerData::class)
   val consumer = Consumer(properties, serializer)

   runBlocking {
       consumer.consume(listOf(&amp;quot;my-topic&amp;quot;), 1000) { poll -&amp;gt;
         while (true) {
            val messages = poll()
            println(&amp;quot;Received ${messages.size} messages&amp;quot;)
            messages.forEach(fun(message) {
               println(&amp;quot;Received: $message&amp;quot;)
            })
         }
      }
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above, we use a &lt;code&gt;while(true)&lt;/code&gt; loop to re-poll continuously but this can freely change on the implementation, similar to with the producer code&lt;/p&gt;
&lt;h3&gt;Stream Processing&lt;/h3&gt;
&lt;p&gt;In Kafka, we can think of a stream process as a combination of a consumer and producer such that data comes in from a topic and is sent to a different topic&lt;/p&gt;
&lt;p&gt;The thing that makes streams interesting is the builder API that the Kafka Java Library provides to us for defining the operations to be done on the stream data. For our implementation we&apos;ll be referring to this as a &lt;code&gt;TransformProcessor&lt;/code&gt;, this processor needs to take in some data of type &lt;code&gt;TConsume&lt;/code&gt; and return data of type &lt;code&gt;TProduce&lt;/code&gt;, however, since we want to provide users complete flexibility in working with this data, we will instead more generally allow a user to convert a stream between the predefined data types, using the underlying library this is called a &lt;code&gt;KStream&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;From a type perspective, we can define a &lt;code&gt;TransformProcessor&lt;/code&gt; as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SerializedStream.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;typealias TransformProcessor&amp;lt;TConsume, TProduce&amp;gt; = (stream: KStream&amp;lt;String, TConsume&amp;gt;) -&amp;gt; KStream&amp;lt;String, TProduce&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we&apos;re going to be starting this implementation from what we want, assuming that it is possible for us to in some way define a &lt;code&gt;KStream&lt;/code&gt; that is instantiated to work with our connection and the respective &lt;code&gt;TConsume&lt;/code&gt; and &lt;code&gt;TProduce&lt;/code&gt; data.&lt;/p&gt;
&lt;p&gt;We will also be using a type called &lt;code&gt;Produced&lt;/code&gt; which is what the Kafka Client uses to represent the data that the stream will return since this is what we need in order to send data to a processor&lt;/p&gt;
&lt;p&gt;Our implementation will be called a &lt;code&gt;SerializedStream&lt;/code&gt; and this looks like the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SerializedStream.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.apache.kafka.streams.KafkaStreams
import org.apache.kafka.streams.StreamsBuilder
import org.apache.kafka.streams.kstream.KStream
import org.apache.kafka.streams.kstream.Produced
import java.util.*

typealias TransformProcessor&amp;lt;TConsume, TProduce&amp;gt; = (stream: KStream&amp;lt;String, TConsume&amp;gt;) -&amp;gt; KStream&amp;lt;String, TProduce&amp;gt;
typealias Close = () -&amp;gt; Unit
typealias Process = suspend (close: Close) -&amp;gt; Unit

class SerializedStream&amp;lt;TConsume : Any, TProduce : Any&amp;gt;(
    private val properties: Properties,
    private val builder: StreamsBuilder,
    private val producer: Produced&amp;lt;String, TProduce&amp;gt;,
    private val stream: KStream&amp;lt;String, TConsume&amp;gt;
) {
   fun startStreaming(
      topic: String,
      processor: KStream&amp;lt;String, TProduce&amp;gt;,
      process: Process
   ): Job {
      processor.to(topic, producer)

      val streams = KafkaStreams(
         builder.build(),
         properties
      )

      val scope = CoroutineScope(Dispatchers.IO)
      return scope.launch {
         streams.start()
         process()
         streams.close()
      }
   }

   fun getProcessor(
       processor: TransformProcessor&amp;lt;TConsume, TProduce&amp;gt;
   ): KStream&amp;lt;String, TProduce&amp;gt; = processor(stream)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above implementation we have an input to our &lt;code&gt;startStreaming&lt;/code&gt; function called &lt;code&gt;process&lt;/code&gt;, the &lt;code&gt;process&lt;/code&gt; function is a callback that needs to call &lt;code&gt;close&lt;/code&gt; once it is done running. When the &lt;code&gt;process&lt;/code&gt; function returns the processing will stop, the scope of this function also defines lifecycle of the stream processor and is used for that purpose&lt;/p&gt;
&lt;p&gt;So we have defined the processing methodology using a &lt;code&gt;KStream&lt;/code&gt; but have not provided a way to create a &lt;code&gt;KStream&lt;/code&gt;. Since the stream can be defined in many different ways, we can define this using a builder class called &lt;code&gt;StreamBuilder&lt;/code&gt;. This class will be instantiated with the Kafka connection properties and input/output serializers, thereafter it can produce methods for instantiating the &lt;code&gt;SerializedStream&lt;/code&gt; instance that we can use for data processing&lt;/p&gt;
&lt;p&gt;For the sake of our example we will provide a method called &lt;code&gt;fromTopic&lt;/code&gt; which returns a &lt;code&gt;SerializedStream&lt;/code&gt; that is configured to work on a single topic, and a &lt;code&gt;fromTopics&lt;/code&gt; method which will return a &lt;code&gt;SerializedStream&lt;/code&gt; that listens to multiple topics:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;StreamBuilder.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;package za.co.nabeelvalley.kafka

import org.apache.kafka.common.serialization.Serdes
import org.apache.kafka.streams.StreamsBuilder
import org.apache.kafka.streams.kstream.Consumed
import org.apache.kafka.streams.kstream.Produced
import java.util.*

interface IStreamBuilder&amp;lt;TConsume : Any, TProduce : Any&amp;gt; {
    fun fromTopic(topic: String): SerializedStream&amp;lt;TConsume, TProduce&amp;gt;
    fun fromTopics(topics: List&amp;lt;String&amp;gt;): SerializedStream&amp;lt;TConsume, TProduce&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An implementation of this interface is as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;StreamBuilder.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;class StreamBuilder&amp;lt;TConsume : Any, TProduce : Any&amp;gt;(
    properties: Properties,
    consumeSerializer: ISerializer&amp;lt;TConsume&amp;gt;,
    producerSerializer: ISerializer&amp;lt;TProduce&amp;gt;,
) : Config(properties), IStreamBuilder&amp;lt;TConsume, TProduce&amp;gt; {
    private val inputSerde = Serializer&amp;lt;TConsume&amp;gt;(consumeSerializer)
    private val consumed = Consumed.with(Serdes.String(), inputSerde)

    private val outputSerde = Serializer&amp;lt;TProduce&amp;gt;(producerSerializer)
    private val produced = Produced.with(Serdes.String(), outputSerde)

    override fun fromTopic(topic: String): SerializedStream&amp;lt;TConsume, TProduce&amp;gt; {
        val builder = StreamsBuilder()
        val stream = builder.stream(mutableListOf(topic), consumed)

        return SerializedStream(properties, builder, produced, stream)
    }

    override fun fromTopics(topics: List&amp;lt;String&amp;gt;): SerializedStream&amp;lt;TConsume, TProduce&amp;gt; {
        val builder = StreamsBuilder()
        val stream = builder.stream(topics.toMutableList(), consumed)

        return SerializedStream(properties, builder, produced, stream)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above class makes use of the &lt;code&gt;produced&lt;/code&gt; and &lt;code&gt;consumed&lt;/code&gt; properties which are what Kafka will use for serializing and deserializing data in the stream&lt;/p&gt;
&lt;p&gt;And that&apos;s about it as far as our implementation for streaming goes&lt;/p&gt;
&lt;h4&gt;Using the Stream Processor&lt;/h4&gt;
&lt;p&gt;We can use the stream processor code:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;fun initializeAndProcess(properties: Properties): Job {
    val producedSerializer = JsonSerializer(ProducerData::class)
    val consumedSerializer = JsonSerializer(ConsumerData::class)
    val streamBuilder = StreamBuilder(properties, consumedSerializer, producedSerializer)
    val stream = streamBuilder.fromTopic(&amp;quot;input-topic&amp;quot;)

    val processor = stream.getProcessor { kStream -&amp;gt;
        kStream.mapValues { key, value -&amp;gt;
            ProducerData(&amp;quot;Message processed: $key&amp;quot;, value.key)
        }
    }

    val scope = CoroutineScope(Dispatchers.IO)
    return scope.launch {
        stream.startStreaming(&amp;quot;output-topic&amp;quot;, processor) { close -&amp;gt;
            coroutineScope {
                println(&amp;quot;Processor starting&amp;quot;)
                // Non-blocking loop as long as the coroutine is active
                while (isActive) {
                    delay(10_000)
                }

                // close when no longer active
                close()
                println(&amp;quot;Processor closed&amp;quot;)
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most of this is just the normal construction that you will have for any instance of the stream client, what is interesting is the part where we define the processor:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;App.kt&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot;&gt;val processor = stream.getProcessor { kStream -&amp;gt;
    kStream.mapValues { key, value -&amp;gt;
        ProducerData(&amp;quot;Message processed: $key&amp;quot;, value.key)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example we are simply mapping a single record using &lt;code&gt;mapValues&lt;/code&gt;, this is very similar to the Collection methods available in Kotlin but is instead used to define how data will be transformed in the stream&lt;/p&gt;
&lt;p&gt;The processor we define is what will be executed on records or groups of records depending on how we want to handle the resulting data&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post we&apos;ve covered the basic implementation of how we can interact with Kafka using the Kotlin programming language and built a small library that takes us through the basic use cases of Serializing, Producing, Consuming, and Processing stream data&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://kafka.apache.org/intro&quot;&gt;Introduction to Kafka&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.confluent.io/kafka-clients/java/current/overview.html&quot;&gt;Java Kafka Client&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>JPA Queries without the Magic</title><link>https://nabeelvalley.co.za/blog/2023/20-10/jpa-query-specifications/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/20-10/jpa-query-specifications/</guid><description>Defining custom queries for JPA using specifications</description><pubDate>Fri, 20 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;If you&apos;re just looking for the solution you can just &lt;a href=&quot;#the-solutions&quot;&gt;skip ahead&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The go-to way to build web applications with Java or Kotlin is using &lt;a href=&quot;https://spring.io/&quot;&gt;Spring&lt;/a&gt;. Spring is a pretty decent web framework that provides a lot of utilities for handling common web application related tasks&lt;/p&gt;
&lt;p&gt;However I find that Spring does a fair amount of compiler magic to make it work the way it does - of particular concern to this post is how Spring generates implementations for database queries using &lt;a href=&quot;https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#appendix.query.method.subject&quot;&gt;Query kewords&lt;/a&gt; as part of your function names which spring will resolve to a query on the underlying database&lt;/p&gt;
&lt;p&gt;Below is a short example of how we would use Spring to query our database to illustrate the problem:&lt;/p&gt;
&lt;h2&gt;The Example&lt;/h2&gt;
&lt;p&gt;Let us consider an application in which we have some entity in our system that we would like to store in a database and be able to search over&lt;/p&gt;
&lt;p&gt;In order to do this, we need to define a couple of things things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An Entity which represents that data structure for our User&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In Spring we can define entities, like a &lt;code&gt;User&lt;/code&gt; as a class with some annotations&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = &amp;quot;User&amp;quot;)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(unique = true)
    private String email;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;A Repository which is the class through which we will interact with the database for the specific entity&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; { }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the repository all we really need is to use the &lt;code&gt;@Repository&lt;/code&gt; annotation which will register the repository with the Spring dependency injection, and we need to extend &lt;code&gt;JpaRepository&lt;/code&gt; which provides some base methods for our repository such as &lt;code&gt;findAll&lt;/code&gt;, &lt;code&gt;save&lt;/code&gt;, or &lt;code&gt;delete&lt;/code&gt; among others&lt;/p&gt;
&lt;p&gt;Up until this point, we haven&apos;t seen anything too weird and the code thus far is fairly easy to reason about - however, this becomes interesting when we want to add a method like &lt;code&gt;findByEmail&lt;/code&gt; which we define in the interface as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Repository
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; { 
    List&amp;lt;User&amp;gt; findByEmail(String email);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s it, we don&apos;t implement this anywhere - Spring will generate this implementation for us - weird - but okay. We can use this function anywhere we have a repsitory instance and it will behave as expected&lt;/p&gt;
&lt;h2&gt;Growing Pains&lt;/h2&gt;
&lt;p&gt;But now, what if we want the &lt;code&gt;findByEmail&lt;/code&gt; function to be case incensitive? Well seemingly we can just name this however so let&apos;s try:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Repository
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; { 
    List&amp;lt;User&amp;gt; findByEmailCaseInsensitive(String email);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can try using that, but it won&apos;t work - turns out the magic is documented at least, and Spring tells us that we actually need to use &lt;code&gt;IgnoreCase&lt;/code&gt; in the name - this makes use of the Query Keywords I mentioned above&lt;/p&gt;
&lt;p&gt;So sure, we can change this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Repository
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; { 
    List&amp;lt;User&amp;gt; findByEmailIgnoreCase(String email);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And also go and change everwhere we&apos;re using that method, since it&apos;s name now dictates its implementation we will need to keep in mind that if we ever want to change the implementation we will need to update all our clients&lt;/p&gt;
&lt;p&gt;But wait - that&apos;s very UN-Java like isn&apos;t it? This seems to break the entire purpose of using functions - if my function&apos;s behaviour is directly dependant on it&apos;s name then how is this any different to just repeating the implementation everywhere need this? We&apos;re typing the same code either way&lt;/p&gt;
&lt;p&gt;Now, I&apos;m not all complaints - using a half competent IDE we should be able to do this refactor fairly painlessly and move on with our day - this isn&apos;t the main issue yet&lt;/p&gt;
&lt;p&gt;Where we start running into problems is when our queries need to get more complex, for example when we decide that we want the search to extend to something like a secondary email filed, for example if we add a new field to our entity, like &lt;code&gt;companyEmail&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Entity
@Table(name = &amp;quot;User&amp;quot;)
public class User {
    // ... existing code

    // new field
    @Column()
    private String companyEmail;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Limit Does Exist&lt;/h2&gt;
&lt;p&gt;And we now need to update our email function to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Repository
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; { 
    List&amp;lt;User&amp;gt; findByEmailIgnoreCaseOrCompanyEmailIgnoreCase(String email);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s a bit rough right? There&apos;s really no reason our method name should be that long - oh, and it won&apos;t work either - even though this follows the JPA naming convention it&apos;s just a little too complicated for the code generator to get right&lt;/p&gt;
&lt;p&gt;Okay, so now we&apos;re stuck right? No - Why would I go on this rant if I don&apos;t have a solution in my head&lt;/p&gt;
&lt;p&gt;Well, time to share it I guess&lt;/p&gt;
&lt;h2&gt;The Solution(s)&lt;/h2&gt;
&lt;h3&gt;Query Annotations&lt;/h3&gt;
&lt;p&gt;Spring gives us two escape hatches for handling the problem we just ran into - we can use the &lt;code&gt;@Query&lt;/code&gt; annotation which allows us to define a custom &lt;code&gt;JQL&lt;/code&gt; query (Not SQL) that is defined inline and will do the appropriate value substitutions as needed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Repository
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt; { 
    @Query(&amp;quot;SELECT u FROM User u WHERE LOWER(u.email) LIKE LOWER(:query) OR LOWER(u.comanyEmail) LIKE LOWER(:query)&amp;quot;)
    List&amp;lt;User&amp;gt; findByEmail(String email);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if this were the only option, I could live with it, it takes away some of the magic and gives me a decent amount of control over what I&apos;m doing&lt;/p&gt;
&lt;p&gt;... but ... how can i say ... It&apos;s ugly&lt;/p&gt;
&lt;p&gt;Even if we assume that we don&apos;t somehow have any errors in the above string, it&apos;s just a little odd - like other ORMs have lovely fluent interfaces like &lt;code&gt;LINQ&lt;/code&gt; in C# or &lt;code&gt;knex&lt;/code&gt; or &lt;code&gt;prisma&lt;/code&gt; in Javascript/TypeScript that understand SQL and fit naturally into our programming languge&lt;/p&gt;
&lt;h3&gt;Specifications&lt;/h3&gt;
&lt;p&gt;Specifications provide us with a way to define our query within our programming language, and I think that&apos;s nice, so here&apos;s how they work&lt;/p&gt;
&lt;p&gt;In order to use specificiations we need to do a few things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define the specification method&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It doesn&apos;t matter too much where we define the specification, but for our example we&apos;ll put it in a static class so we can use it wherever:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;import org.springframework.data.jpa.domain.Specification;

public class UserSpecification {

    /**
     * Search for an User using a free text search on the email and name fields
     *
     * @param search text to be searched
     * @return a specification that can be used with the `repository.findAll()` on a `JpaSpecificationExecutor`
     */
    public static Specification&amp;lt;User&amp;gt; searchForUserByEmail(String search) {
        var likeSearch = search.toLowerCase();

        return (root, query, criteriaBuilder) -&amp;gt; {
            return criteriaBuilder.or(
                    criteriaBuilder.like(criteriaBuilder.lower(root.get(&amp;quot;email&amp;quot;)), likeSearch),
                    criteriaBuilder.like(criteriaBuilder.lower(root.get(&amp;quot;companyEmail&amp;quot;)), likeSearch)
            );
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The structure of the specification is a little verbose but you could refactor this to be a bit more reusable if you wanted&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Extend the &lt;code&gt;JpaSpeficationExecutor&lt;/code&gt; on our repository&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can delete all the methods in the repository and add the &lt;code&gt;JpaSpecificationExecutor&amp;lt;User&amp;gt;&lt;/code&gt; to the list of things we&apos;re extending&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;// ... existing imports

import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

@Repository
public interface UserRepository extends JpaRepository&amp;lt;User, Long&amp;gt;, JpaSpecificationExecutor&amp;lt;User&amp;gt; { }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above definition will provide us with two nice method on the repository, namely &lt;code&gt;findAll&lt;/code&gt; and &lt;code&gt;findOne&lt;/code&gt; which both take a &lt;code&gt;Speficication&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Use the speficication with our repository&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that we have everything defined, we can use this in some part of our application as such:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;var spec = UserSpecification.searchForUserByEmail(&amp;quot;bob@email.com&amp;quot;);
var result = userRepository.findOne(spec);

// or for findAll
var results = userRepository.findAll(spec)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s it, In my opinion the &lt;code&gt;Specification&lt;/code&gt; solution is a bit easier to manage within the context of the greater codebase without having to worry about too much compile time magic and possible typos in the &lt;code&gt;JQL&lt;/code&gt; query&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I think either of the the provided solutions are fair and give us with a good way to manage more complex queries more flexibly in a way that isolates our implementation from where we intend to use the code&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Oh, and since you made it this far - I&apos;m SO sorry you&apos;re writing Java and I wish your sanity all the best&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Using Type Guards and Unions to prevent bugs and increase maintainability</title><link>https://nabeelvalley.co.za/blog/2023/26-06/type-guards-and-unions-typescript/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/26-06/type-guards-and-unions-typescript/</guid><description>A practical introduction to type guards and union types</description><pubDate>Mon, 26 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When working with a dynamic language, like Javascript, a problem that we can often run into is one where a variable may be of multiple possible types in a given place in our code. Due to this, we often run into a need to check the type of an object&lt;/p&gt;
&lt;h2&gt;The Scene&lt;/h2&gt;
&lt;p&gt;For the sake of introducing the need for type guards, we&apos;re going to consider an imaginary news site in which users can read articles posted to the site. For our site, we want to enable users to add comments and interact with articles. For this purpose, we require that each user is logged in and exists in our database&lt;/p&gt;
&lt;p&gt;The object we use for representing a user who just reads our site is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const reader = {
  username: &apos;john&apos;,
  email: &apos;john@email.com&apos;,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After some time, we decide to make it such that certain users can create articles on the website. To do this, we add a value on the user that states that the user is a writer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const writer = {
  username: &apos;smith&apos;,
  email: &apos;smith@email.com&apos;,
  isWriter: true,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is great, our data now reflects that we have a user type that can post articles to the website.&lt;/p&gt;
&lt;p&gt;The site is growing well and the content available is flourishing, by we seem to be getting a frequent complaints from users that some articles are not appropriate for the site or may be incorrect or misleading&lt;/p&gt;
&lt;p&gt;So, to mitigate this issue, we decide that for our website we want to add a new type of permission that defines users that are responsible for moderating content. However, to prevent a conflict of interest - moderators are not allowed to write articles for the site&lt;/p&gt;
&lt;p&gt;So we choose to add a field for that indicates a user is a moderator:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const moderator = {
  username: &apos;bob&apos;,
  email: &apos;bob@email.com&apos;,
  isWriter: false,
  isModerator: true,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Based on this, we update the application types to account for the new field, and we have the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface User {
  username: string
  email: string
  isWriter: boolean
  isModerator: boolean
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We update the application to handle the above solution. We even add a few helper methods in our code that allow us to determine if a user is a writer or moderator&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const isWriter = (user: User): boolean =&amp;gt; user.isWriter

const isModerator = (user: User): boolean =&amp;gt; user.isModerator
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fantastic! We&apos;re happy with our implementation and we release the code into production&lt;/p&gt;
&lt;p&gt;Everything is going great, our moderators are keeping the content quality up and our writers are writing great content&lt;/p&gt;
&lt;h2&gt;The Bug&lt;/h2&gt;
&lt;p&gt;After a few weeks though, readers start to notice a problem - some articles that are taken down by moderators seem to be reappearing - it looks as if some malicious moderator is re-enabling bad articles&lt;/p&gt;
&lt;p&gt;Upon some further investigation, the team notices that all these articles are ones in which the moderator is the writer of the article - but this shouldn&apos;t have happened right? We said that each moderator should not be able to also function as a writer&lt;/p&gt;
&lt;p&gt;Eventually, we track down the bug that made this possible, it was in the function called &lt;code&gt;convertUserToModerator&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const convertUserToModerator = (user: User): User =&amp;gt; {
  user.isModerator = true

  return user
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The issue was caused by us not setting the &lt;code&gt;isWriter&lt;/code&gt; field to &lt;code&gt;false&lt;/code&gt; in the above function, cool - so we just fix that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const convertUserToModerator = (user: User): User =&amp;gt; {
  user.isModerator = true
  user.isWriter = false

  return user
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Great - we deploy the fix and migrate to ensure that &lt;code&gt;isWriter&lt;/code&gt; is set to &lt;code&gt;false&lt;/code&gt; for all existing moderators. The issue seems to be fixed, but after a while users start reporting that the problem is happening again&lt;/p&gt;
&lt;p&gt;The cause seems to be the same - it looks like users are somehow still having &lt;code&gt;isWriter&lt;/code&gt; and &lt;code&gt;isModerator&lt;/code&gt; simultaneously set to &lt;code&gt;true&lt;/code&gt; and ending up with a permission that shouldn&apos;t be possible in our system&lt;/p&gt;
&lt;h2&gt;Impossible States&lt;/h2&gt;
&lt;p&gt;So we decide to investigate the problem and determine that the reason we are running into this bug seems to be due to some fundamental way that the data has been defined&lt;/p&gt;
&lt;p&gt;Since each user can have &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; for any combination of &lt;code&gt;isWriter&lt;/code&gt; and &lt;code&gt;isModerator&lt;/code&gt; we end up representing something unintended which can be seen in the table of possible combinations below:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;User Type&lt;/th&gt;
&lt;th&gt;&lt;code&gt;isWriter === true&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;isWriter === false&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isModerator === true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unknown&lt;/td&gt;
&lt;td&gt;Moderator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;isModerator === false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Writer&lt;/td&gt;
&lt;td&gt;Reader&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;From the above, we can see that we have a state that is not handled in the current code - this &amp;quot;Unknown&amp;quot; state. In this state, the &lt;code&gt;isModerator&lt;/code&gt; and &lt;code&gt;isWriter&lt;/code&gt; functions return &lt;code&gt;true&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We want this state to be impossible in our code. This is not a state that our application should ever have to consider. From a type-design perspective, it&apos;s not enough to handle these impossible states, we need to prevent them from existing in the first place&lt;/p&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;The problem above stems from the fact that we&apos;re using two different states to represent something that should be a single state. From the above diagram, we can resolve the following valid types of users in our system&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reader - reads and adds comments to articles&lt;/li&gt;
&lt;li&gt;Writer - writes articles&lt;/li&gt;
&lt;li&gt;Moderator - moderates articles, does not write articles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using these user types, we can update the &lt;code&gt;User&lt;/code&gt; definition from above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface User {
  type: &apos;reader&apos; | &apos;writer&apos; | &apos;moderator&apos;

  username: string
  email: string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;type&lt;/code&gt; field allows us to determine the type of a user. We can then use this value to check the type of a user and use this to inform how we use the object down the line&lt;/p&gt;
&lt;h2&gt;Extending the Moderator&lt;/h2&gt;
&lt;p&gt;Our solution is running well and we have managed to fully eliminate the bug.&lt;/p&gt;
&lt;p&gt;But now, the moderators are a little bored with their duties and would like some way that they can compete with each other on the quality of their content moderation - so they decide to create a leaderboard in which they look at how many articles they have read and approved or denied - as interest goes however, the moderators reach out to the development team and ask if it would be possible to add the number of approvals and denials so that the moderators don&apos;t need to calculate this manually every month for their leaderboard&lt;/p&gt;
&lt;p&gt;The development team has the idea to add these scores into the &lt;code&gt;User&lt;/code&gt; definition type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface User {
  type: &apos;reader&apos; | &apos;writer&apos; | &apos;moderator&apos;

  username: string
  email: string

  approvedArticles: number
  deniedArticles: number
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;During a PR review session, the team decides that this is a bit weird since it implies that any user can have some approved or denied articles - this doesn&apos;t make sense, so someone suggests to use a &lt;strong&gt;Discriminated Union&lt;/strong&gt; in which only users of the &lt;code&gt;moderator&lt;/code&gt; type can have these properties - the developer also says that this will make it easier later to add additional fields to any role without having to worry about the implication of this on other roles&lt;/p&gt;
&lt;p&gt;The team decides that they want to have a &lt;code&gt;Base&lt;/code&gt; user which has some shared properties and a union which adds additional fields&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;BaseUser&lt;/code&gt; user has a generic parameter called &lt;code&gt;Type&lt;/code&gt; which is the &lt;code&gt;type&lt;/code&gt; for the user, since we want to ensure that each possible user type has this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface BaseUser&amp;lt;Type extends string&amp;gt; {
  type: Type

  username: string
  email: string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each specialized user type can inherit from &lt;code&gt;BaseUser&lt;/code&gt; with a specific type applied, for the &lt;code&gt;writer&lt;/code&gt; and &lt;code&gt;reader&lt;/code&gt; types, these can just be aliases to the base interface&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ReaderUser = BaseUser&amp;lt;&apos;reader&apos;&amp;gt;
type WriterUser = BaseUser&amp;lt;&apos;writer&apos;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;moderator&lt;/code&gt; however, will need to extend this to add the additional properties:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;interface ModeratorUser extends BaseUser&amp;lt;&apos;moderator&apos;&amp;gt; {
  approvedArticles: number
  deniedArticles: number
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly, the three types above can be used to define a single type called &lt;code&gt;User&lt;/code&gt; which has the same functionality as the &lt;code&gt;User&lt;/code&gt; interface we&apos;ve been using until now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type User = ReaderUser | WriterUser | ModeratorUser
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above is the Typescript syntax for defining a &lt;strong&gt;Union&lt;/strong&gt; which is a type that can be one of multiple types. Each type in the Union is separated by the &lt;code&gt;|&lt;/code&gt;. The union we have above is a special type of union called a &lt;strong&gt;Discriminated Union&lt;/strong&gt; which is a special type of Union that has a field called a &lt;strong&gt;discriminator&lt;/strong&gt; which uniquely identifies each element of the union - in our case this is the &lt;code&gt;type&lt;/code&gt; field of &lt;code&gt;BaseUser&lt;/code&gt; which used the generic &lt;code&gt;Type&lt;/code&gt; parameter&lt;/p&gt;
&lt;p&gt;In our backend code, we can now use the &lt;code&gt;type&lt;/code&gt; property of our user to conditionally fetch the data needed to populate the moderator object&lt;/p&gt;
&lt;h2&gt;Checks, Checks&lt;/h2&gt;
&lt;p&gt;As the codebase grows, the team writes some functions to check the type of the user so that specific computations can be done, for example checking the total number of articles a moderator has been reviewed. An example of one of these checks can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const isModerator = (user: User): boolean =&amp;gt; user.type === &apos;moderator&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above check is used in quite a few places, like when counting the total number of articles reviewed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getTotalArticlesReviewed = (user: User): number | undefined =&amp;gt; {
  if (isModerator(user)) {
    const moderatorUser = user as ModeratorUser

    return moderatorUser.approvedArticles + moderatorUser.deniedArticles
  }

  return undefined
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similar casting patterns as above seem to be cropping up in a lot of places, another example is when listing the moderators that a user follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const moderatorUsers = users.filter(isModerator) as ModeratorUser[]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Type Guards&lt;/h2&gt;
&lt;p&gt;The above solutions use &lt;strong&gt;Type Assertions&lt;/strong&gt; which allow a user to override the Typescript Compiler&apos;s type system to manually state the type of an object - this is dangerous because it essentially means that we give up type checking at that point in the code&lt;/p&gt;
&lt;p&gt;The type assertions around user types are leading to lots of bugs, the team has a discussion about how this problem can be solved and someone suggests using a &lt;strong&gt;Type Guard&lt;/strong&gt;. Type Guards are functions that can be used to check if a given variable meets a specific criterion under which it can be considered a narrower type that the input type. The difference between a Type Guard in this context and a regular function is that a Type Guard returns type information that can be used to inform the Typescript compiler about the state of a variable&lt;/p&gt;
&lt;p&gt;The proposed example is to convert the &lt;code&gt;isModerator&lt;/code&gt; function into an &lt;strong&gt;Assertion Function&lt;/strong&gt; by converting the return type from &lt;code&gt;boolean&lt;/code&gt; to &lt;code&gt;user is ModeratorUser&lt;/code&gt; - this assertion tells the compiler that within the scope that the check is &lt;code&gt;true&lt;/code&gt;, the value is of the stated type and not the original type&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;isModerator&lt;/code&gt; can be updated as such:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const isModerator = (user: User): user is ModeratorUser =&amp;gt;
  user.type === &apos;moderator&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that when using the code above, we no longer need to cast since Typescript can infer the variable appropriately&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getTotalArticlesReviewed = (user: User): number | undefined =&amp;gt; {
  if (isModerator(user)) {
    // within the scope of this condition the `user` type is known to be `ModeratorUser`
    return user.approvedArticles + user.deniedArticles
  }

  return undefined
}

// the `.filter` function accepts the type guard and can now infer that moderatorUsers is `ModeratorUser[]`
const moderatorUsers = users.filter(isModerator)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Discriminated Unions and type Guards are a powerful methods that can be used for working with complex object types and encoding application rules into your type system to minimize bugs and make code easier to extend&lt;/p&gt;
&lt;h2&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;On this site the following posts contain content relative to this one:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2022/31-05/type-narrowing&quot;&gt;Type Narrowing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/javascript/typescript-basics&quot;&gt;Typescript Basics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Typescript documentation also mentions the above topics in a few different places:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions&quot;&gt;Assertion Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions&quot;&gt;Discriminated Unions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions&quot;&gt;Unions and Intersection Types&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And the following series from &lt;a href=&quot;https://fsharpforfunandprofit.com/&quot;&gt;F# for Fun and Profit&lt;/a&gt; is something I often find myself coming back to on the topic of type design:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://fsharpforfunandprofit.com/posts/designing-with-types-intro/&quot;&gt;Designing with types: Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fsharpforfunandprofit.com/posts/designing-with-types-making-illegal-states-unrepresentable/&quot;&gt;Designing with types: Making illegal states unrepresentable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Nvim Error when using Plugins</title><link>https://nabeelvalley.co.za/blog/2023/13-06/vim-errror-when-using-plugins/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/13-06/vim-errror-when-using-plugins/</guid><description>Fix NVim Error Executing Lua with Plugins</description><pubDate>Tue, 13 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When trying to use an NVim plugin you may run into the following error message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error executing lua ...path/to/some/vim/file.lua
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can happen due to a plugin update that was run or another plugin being installed that caused the working tree of the plugin to be out of date or in an invalid state&lt;/p&gt;
&lt;p&gt;To fix this, you may want to try updating and cleaning your plugins. In my case, I am using &lt;code&gt;VimPlug&lt;/code&gt; so the commands are:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;:PlugUpdate
:PlugClean
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thereafter, quitting and reopening vim seems to usually fix the issue, if not then you may need to investigate the plugin itself&lt;/p&gt;
</content:encoded></item><item><title>Generic Object Property Formatter and Validator using Typescript</title><link>https://nabeelvalley.co.za/blog/2023/09-05/generic-transformer-typescript/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/09-05/generic-transformer-typescript/</guid><description>A statically typed, generic method for formatting and validating javascript objects for interchange across system boundaries</description><pubDate>Tue, 09 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At times there&apos;s a need for transforming specific object properties from an input format to some specific output, this can be done using the following code in some generic means&lt;/p&gt;
&lt;h2&gt;The Concept of a Schema&lt;/h2&gt;
&lt;p&gt;The concept of a schema to be used for formatting some data can be defined as follows&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export type Primitive = string | number | boolean | Symbol | Date

/** * Define a formatter that can take in a generic object type and format each entry of that object */
export type FormatterSchema&amp;lt;T&amp;gt; = {
  [K in keyof T]?: T[K] extends Primitive
    ? // if the value is primitive then we can just transform it using a simple function
      (val: T[K]) =&amp;gt; T[K]
    : // if it&apos;s an object then it should either be a formatter schema or a transformer function
      FormatterSchema&amp;lt;T[K]&amp;gt; | ((val: T[K]) =&amp;gt; T[K])
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;An Interpreter&lt;/h2&gt;
&lt;p&gt;The implementation of an interpreter that satisfies the above can done as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Formatter&amp;lt;T&amp;gt; = (val: T) =&amp;gt; T
const isFormatterFn = &amp;lt;T&amp;gt;(
  formatter: FormatterSchema&amp;lt;T&amp;gt;[keyof T]
): formatter is Formatter&amp;lt;T[keyof T]&amp;gt; =&amp;gt; typeof formatter === &apos;function&apos;

const isFormatterObj = &amp;lt;T&amp;gt;(
  formatter: FormatterSchema&amp;lt;T&amp;gt;[keyof T]
): formatter is Exclude&amp;lt;Formatter&amp;lt;T[keyof T]&amp;gt;, Function&amp;gt; =&amp;gt;
  typeof formatter === &apos;object&apos;

export const interpret =
  &amp;lt;T&amp;gt;(schema: FormatterSchema&amp;lt;T&amp;gt;): Formatter&amp;lt;T&amp;gt; =&amp;gt;
  (val) =&amp;gt; {
    const keys = Object.keys(schema) as Array&amp;lt;keyof T&amp;gt;
    return keys.reduce&amp;lt;T&amp;gt;((prev, key) =&amp;gt; {
      const keySchema = schema[key]
      const keyVal = val[key]

      const isSchemaFn = isFormatterFn(keySchema)
      if (isSchemaFn) {
        return {
          ...prev,
          [key]: keySchema(keyVal),
        }
      }

      const isSchemaObj = isFormatterObj(keySchema)
      if (isSchemaObj) {
        return {
          ...prev,
          [key]: interpret(keySchema)(keyVal),
        }
      }

      return prev
    }, val)
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Transformers&lt;/h2&gt;
&lt;p&gt;We can define some general transformers, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const trunc = Math.trunc

const round = Math.round

const length = (len: number) =&amp;gt; (val: string) =&amp;gt; val.slice(0, len)

const trim = (val: string) =&amp;gt; val.trim()

const constant =
  &amp;lt;T&amp;gt;(val: T) =&amp;gt;
  () =&amp;gt;
    val

const optional =
  &amp;lt;T&amp;gt;(fn: (val: T) =&amp;gt; T) =&amp;gt;
  (val?: T) =&amp;gt;
    val === undefined ? undefined : fn(val)

export const formatter = {
  trunc,
  round,
  length,
  trim,
  constant,
  optional,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;For the sake of example we can define a data type to use&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type User = {
  name: string
  location: {
    address: string
    city: string
    gps?: [number, number]
  }
}

const user: User = {
  name: &apos;Bob Smithysmithson&apos;,
  location: {
    city: &apos;Somewhere secret&apos;,
    address: &apos;123 Secret street&apos;,
    gps: [123, 456],
  },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Using as a Transformer&lt;/h3&gt;
&lt;p&gt;We can use the above by defining the transformer and using it to transform the input data according to the defined schema&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const format = interpret&amp;lt;User&amp;gt;({
  name: formatter.length(10),
  location: {
    city: (val) =&amp;gt; ([&apos;Home&apos;, &apos;Away&apos;].includes(val) ? val : &apos;Other&apos;),
    gps: (val) =&amp;gt; (isValidGPS(val) ? val : undefined),
  },
})

const result = format(user)

console.log(result)
// {
//   name: &apos;Bob Smithy&apos;,
//   location: {
//     city: &apos;Other&apos;,
//     adddtess: &apos;123 Secret street&apos;,
//     gps: undefined,
//   }
// }
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Using as a Validator&lt;/h3&gt;
&lt;p&gt;Using the same principal as above we can use it for validaing data. Validation can be done by throwing in the transformer function&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const validate = interpret&amp;lt;User&amp;gt;({
  name: (val) =&amp;gt; {
    if (val.length &amp;gt; 5) {
      throw &apos;Length too long&apos;
    }

    return val
  },
})

// throws with Length too long
validate({
  name: &apos;Jack Smith&apos;,
})
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Exploration&lt;/h2&gt;
&lt;p&gt;It may be worth taking the concept and expanding it into a more fully fledged library with a way to handle validations more simply or to provide more builtin transformers and validators but for the moment it can be stated that there are enough javascript libraries for validation and the formatter alone is likely of limited value but may be worth exploring further if gaps in the existing technology are found&lt;/p&gt;
&lt;p&gt;Regardless of the utility of the particular type above I think the concept and types give some insight into how one can build out a library as the ones discussed above&lt;/p&gt;
&lt;h2&gt;Working Example&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;A working playground with the code from here can be found at &lt;a href=&quot;https://www.typescriptlang.org/play?jsx=0&amp;amp;module=1#code/KYDwDg9gTgLgBDAnmYcAKUCWBbTNMBuqAvHAM4xYB2A5nAD5xUCu2ARsFA3GxBADbAAhlW4BlROwHcAIkJjAA3AChlcAPQAqTXB0zgAM0xVUQuAejZ5CrjAAW8uAGMRCIQGtUxuGZrATWE5wEGwAVsBO8EgoPlQAJuaWjsJOdnD+lIjBBggO8CHhkbrqyqCQsAjIqABiSTA2YqnAVgA8ACoAfHCkAN5qcADaANJw3p6IEDltALoA-ABccG3D0+kgCvFk6Fi4+ET9cBrqozn2qARC-MxeW2A7eISoZ6IA7qguoqHMFAhQImQWKDYUbwb7GOhmMg4MCCczMKiRTAQKgHOCzOAACgu-EWyyG0wAlN0unjpqj1MdMDk8AByLauAoRKJ2fwg8h2CDMfgJYB4FlcDg+RJA6ycchNKzBLhmSj-QHYMUGeGI5Goxa1EX1TiNFmtUldRgYrGXXErInEElmlQAXxUymiNTqNnaXVIxpxS3NJJUTmRP0wZA1Vi1UGqolILox-Xloqg6qd2olQhdA3GkyWZIJixjIdGWyDsfaqeAEym01dXQd6ZzNm6xFINKVCPwyJpdt9VH9gYTUAA8mFunBI9Ge-HNQ0kym02XlFnhcHawG4ABREBOK5xYAtAshovTjMdAA0cGqypbVArlRQ1Z7dYbjMibdUZWg8A7-qoNjuwHgxH6kbIJMxwXRNdWTTo5x3Z1OmJfp3S9OA+kOQ533gcYtlIftChgAA6dCMUAsCiSELYAEEoD+RAWn3ToVGQuAoB-ZgoFEdCcMYuJmCcLdOiNb8CGPcYEKQ+jnD9NCSx1ZozFIQjpOLRBpjo0TULgcYADVLkHbEFKU1RRLEzt4ADKSrDDQcAygzgwwxcZTKEAllPoqlMRMpMwyJESDMYmBmNELyDLgHDgv4w9UQM3TFjspNbJLTT+AJMLArgW1wpS-SVPEvN7Kwizu3HTgsNixB7MctKXIxNywKwzy0sOHy-MQurkOCnDQuaw5ItGT9OG-GBitK4r4sS5rUoM60MvohqWLgfinJS49sTKw5Uv6d8BGAHD+AgGhKp6qA+oJVRVMoZVBwAWXkOwcNOhF2yyqBOXiC6rvYp64nuoy4EEWh7EHDEfsWFh2E4BD3UWChqBoBDsRwsh+EwbiMQABmPH6yuUE6dn+7EIcocEYcuG6dgxDHVNQkRf3-Xjcc9WDDlJ+nkOxT6fggMBzy0v9DkjAwqEWcG6YtIWOjg7EFhF1FsTvOB4U3IwTASdE5cMYxgASbMqHgu0XwqVSazFXp+lupwkoY96zZ+mh7DN-HsDNinPzN9nOf4MLVodOAAFUyENprDioIQFTxqHLYgFxz0WAKhDiOJGLIMgQ-BM2ULwRAk9oFO4BoMAyAlgZgY4KBj0LzgyRW5QJsxrKA3izA4gAcTQMQccufPS+LphWCLwliXMS5fdZ+Acws-a+paH3OA6DERMD4P51jLb-GtuwMQARmRkbDm2iOkX5-3kKcNOBaWvuBhpAAJCAFRpY8aVIl4hEQGlphw4x12YTcyHgtE4GlxYaS9jOFAW+qIc6J0xKfYWtdLj1ybmIH+6J-6y3iKrRWZsJrWiOtXL63wxSLEnlwI2Acg7AAAQAIRCHAMQuw7CIDILQsgrYw672RFHVER8kAALENfYALx+SoF9k4HyoD6IxzjsABOAC14ACYADM1CIg+XIJQYAP5RHIXAYsAYsi5HHgACwAFYABs5d0pV1UvHLkv4F79TwVAbB61BBbR2hiKx-AYCOKytieu8gSDdS-D5CevsoDT1nqQk+lxhKogqrDK2f0uiGNqgZewj0XhwAAEQABll5-RgHwb6yIaAZNRFXKaTEZrYn6Jg7BFJchpK2C8PkTBSEIAKdtWgygfFxD8RiexBIgA&quot;&gt;The Typescript Playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;600px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://www.typescriptlang.org/play?jsx=0&amp;amp;module=1#code/KYDwDg9gTgLgBDAnmYcAKUCWBbTNMBuqAvHAM4xYB2A5nAD5xUCu2ARsFA3GxBADbAAhlW4BlROwHcAIkJjAA3AChlcAPQAqTXB0zgAM0xVUQuAejZ5CrjAAW8uAGMRCIQGtUxuGZrATWE5wEGwAVsBO8EgoPlQAJuaWjsJOdnD+lIjBBggO8CHhkbrqyqCQsAjIqABiSTA2YqnAVgA8ACoAfHCkAN5qcADaANJw3p6IEDltALoA-ABccG3D0+kgCvFk6Fi4+ET9cBrqozn2qARC-MxeW2A7eISoZ6IA7qguoqHMFAhQImQWKDYUbwb7GOhmMg4MCCczMKiRTAQKgHOCzOAACgu-EWyyG0wAlN0unjpqj1MdMDk8AByLauAoRKJ2fwg8h2CDMfgJYB4FlcDg+RJA6ycchNKzBLhmSj-QHYMUGeGI5Goxa1EX1TiNFmtUldRgYrGXXErInEElmlQAXxUymiNTqNnaXVIxpxS3NJJUTmRP0wZA1Vi1UGqolILox-Xloqg6qd2olQhdA3GkyWZIJixjIdGWyDsfaqeAEym01dXQd6ZzNm6xFINKVCPwyJpdt9VH9gYTUAA8mFunBI9Ge-HNQ0kym02XlFnhcHawG4ABREBOK5xYAtAshovTjMdAA0cGqypbVArlRQ1Z7dYbjMibdUZWg8A7-qoNjuwHgxH6kbIJMxwXRNdWTTo5x3Z1OmJfp3S9OA+kOQ533gcYtlIftChgAA6dCMUAsCiSELYAEEoD+RAWn3ToVGQuAoB-ZgoFEdCcMYuJmCcLdOiNb8CGPcYEKQ+jnD9NCSx1ZozFIQjpOLRBpjo0TULgcYADVLkHbEFKU1RRLEzt4ADKSrDDQcAygzgwwxcZTKEAllPoqlMRMpMwyJESDMYmBmNELyDLgHDgv4w9UQM3TFjspNbJLTT+AJMLArgW1wpS-SVPEvN7Kwizu3HTgsNixB7MctKXIxNywKwzy0sOHy-MQurkOCnDQuaw5ItGT9OG-GBitK4r4sS5rUoM60MvohqWLgfinJS49sTKw5Uv6d8BGAHD+AgGhKp6qA+oJVRVMoZVBwAWXkOwcNOhF2yyqBOXiC6rvYp64nuoy4EEWh7EHDEfsWFh2E4BD3UWChqBoBDsRwsh+EwbiMQABmPH6yuUE6dn+7EIcocEYcuG6dgxDHVNQkRf3-Xjcc9WDDlJ+nkOxT6fggMBzy0v9DkjAwqEWcG6YtIWOjg7EFhF1FsTvOB4U3IwTASdE5cMYxgASbMqHgu0XwqVSazFXp+lupwkoY96zZ+mh7DN-HsDNinPzN9nOf4MLVodOAAFUyENprDioIQFTxqHLYgFxz0WAKhDiOJGLIMgQ-BM2ULwRAk9oFO4BoMAyAlgZgY4KBj0LzgyRW5QJsxrKA3izA4gAcTQMQccufPS+LphWCLwliXMS5fdZ+Acws-a+paH3OA6DERMD4P51jLb-GtuwMQARmRkbDm2iOkX5-3kKcNOBaWvuBhpAAJCAFRpY8aVIl4hEQGlphw4x12YTcyHgtE4GlxYaS9jOFAW+qIc6J0xKfYWtdLj1ybmIH+6J-6y3iKrRWZsJrWiOtXL63wxSLEnlwI2Acg7AAAQAIRCHAMQuw7CIDILQsgrYw672RFHVER8kAALENfYALx+SoF9k4HyoD6IxzjsABOAC14ACYADM1CIg+XIJQYAP5RHIXAYsAYsi5HHgACwAFYABs5d0pV1UvHLkv4F79TwVAbB61BBbR2hiKx-AYCOKytieu8gSDdS-D5CevsoDT1nqQk+lxhKogqrDK2f0uiGNqgZewj0XhwAAEQABll5-RgHwb6yIaAZNRFXKaTEZrYn6Jg7BFJchpK2C8PkTBSEIAKdtWgygfFxD8RiexBIgA&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Postman Flows</title><link>https://nabeelvalley.co.za/blog/2023/23-03/postman-flows/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/23-03/postman-flows/</guid><description>First impressions playing with the new Postman Flows</description><pubDate>Fri, 03 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Postman is a tool used for making HTTP requests during development that enables easy testing and experimentation with HTTP/REST APIs&lt;/p&gt;
&lt;p&gt;Recently Postman released something called Flows which is a visual editor for building API flows between different applications and stitching them together into some kind of output view&lt;/p&gt;
&lt;p&gt;Flows can be done to DO things but can also be used to SHOW information based on the data that passes through them&lt;/p&gt;
&lt;p&gt;Below is an example of a Postman Flow that reads the posts from my website and lists/counts them when run from postman&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2023/23-03/postman-flow-example.png&quot; alt=&quot;Postman flow example&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another example of a Postman Flow is of their &lt;a href=&quot;https://www.postman.com/postman/workspace/utility-flows/flow/64123b57c224290033fcb089&quot;&gt;Stock dashboard example&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;References&lt;/h1&gt;
&lt;p&gt;For more information on how to build an use a flow you can take a look at the &lt;a href=&quot;https://learning.postman.com/docs/postman-flows/gs/flows-overview/&quot;&gt;Postman Flows Overview&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Postman flows seems targeted at more technical users. In addition to this I think &lt;a href=&quot;http://ifttt.com/&quot;&gt;IFTTT&lt;/a&gt; is worth taking a look at if you&apos;re interested in doing some small flow-style automations&lt;/p&gt;
&lt;p&gt;For a bit of a more self-hosted alernative, you can also take a look at &lt;a href=&quot;https://nodered.org&quot;&gt;Node-RED&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Update or Append to DynamoDB Attributes</title><link>https://nabeelvalley.co.za/blog/2023/28-02/dynamo-db-update-attribute/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/28-02/dynamo-db-update-attribute/</guid><description>Use UpdateExpressions to modify DynamoDB items without reading them from the database</description><pubDate>Tue, 28 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;DynamoDB Overview&lt;/h2&gt;
&lt;p&gt;DynamoDB is AWS&apos;s No SQL Database Service. Dynamo uses partition keys and sort keys to uniquely identify and partion item in the database which allows for high scalability and throughput&lt;/p&gt;
&lt;p&gt;When working with traditional SQL databases a common operation is to update the value of a specific column without having to first fetch the entire row. DynamoDB offers us similar functionality using the AWS SDK&lt;/p&gt;
&lt;h2&gt;The Update Command&lt;/h2&gt;
&lt;p&gt;DynamoDB commands are simple objects that consist of a few different parts. When looking to update an item the following are relavant:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Key&lt;/code&gt; - which is an object that uniquely identifies an item in the database&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UpdateExpression&lt;/code&gt; - which is an expression that describes the upadate operation to be done using placeholders for attribute names and values (&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html&quot;&gt;AWS Documentation - Update Expressions&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExpressionAttributeNames&lt;/code&gt; - generic placehodlders for attribute names&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExpresssionAtributeValues&lt;/code&gt; - generic placeholders for values&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When defining &lt;code&gt;UpdateExpression&lt;/code&gt; we use placeholders for the attribute names and values to prevent any escaping/unsupported character related issues. A common convention for this is to use &lt;code&gt;#&lt;/code&gt; at the start of attribute names and &lt;code&gt;:&lt;/code&gt; at the start of attribute values to make expressions a bit easier to negotiate, for example, if I wanted to set &lt;code&gt;name&lt;/code&gt; to &lt;code&gt;bob&lt;/code&gt; I would do &lt;code&gt;&apos;#name&apos;: &apos;name&apos;&lt;/code&gt; in the &lt;code&gt;ExpressionAttributeNames&lt;/code&gt; and &lt;code&gt;&apos;#name&apos;: &apos;bob&apos;&lt;/code&gt; in the &lt;code&gt;ExpressionAttributeValues&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;DynamoDB uses an object representation that is a bit inconvenient to work with, we can use the &lt;code&gt;marshall&lt;/code&gt; and &lt;code&gt;unmarshall&lt;/code&gt; functions from &lt;code&gt;@aws-sdk/util-dynamodb&lt;/code&gt; to simplify things a bit but if you&apos;d like to know more about the data format used you can look towards the end of this post&lt;/p&gt;
&lt;h2&gt;Our Example&lt;/h2&gt;
&lt;p&gt;For our example, imagine we have a table of user check-ins with data structured as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Item = {
  // partition key
  group: number
  // sort key
  username: string

  status: string
  checkIns: {
    place: string
    time: number
  }[]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Update an Attribute&lt;/h2&gt;
&lt;p&gt;We can use a bit of a generic structure to outline our data that we plan to update a single attribute. To do this, we can use the &lt;code&gt;SET&lt;/code&gt; command&lt;/p&gt;
&lt;p&gt;The update expression for setting a value will look like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET #attr = :value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yup, that&apos;s pretty much it as far as the expression goes, the actual names of the fields we want to update aren&apos;t relevant here, instead they&apos;re mentioned in the &lt;code&gt;ExpressionAtrributeNames&lt;/code&gt; and &lt;code&gt;ExpressionAttributeValues&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The overall command with all of that is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { DynamoDBClient } from &apos;@aws-sdk/client-dynamodb&apos;
import { marshall, unmarshall } from &apos;@aws-sdk/util-dynamodb&apos;

const client = new DynamoDBClient({})

const pk = &apos;bob&apos;
const sk = 12
const updateValue = &apos;available&apos;

const command = new UpdateItemCommand({
  TableName: &apos;my-table-name&apos;,
  Key: marshall({
    username: pk,
    group: sk,
  }),
  UpdateExpression: &apos;SET #attr = :value&apos;,
  ExpressionAttributeNames: {
    &apos;#attr&apos;: &apos;status&apos;,
  },
  ExpressionAtrributeValues: marshall({
    &apos;:value&apos;: updateValue,
  }),
})

await client.send()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s pretty much the process for updating an attribute witha specific value&lt;/p&gt;
&lt;h2&gt;Append to a List Attribute That Exists&lt;/h2&gt;
&lt;p&gt;In the above data structure we have the &lt;code&gt;checkIns&lt;/code&gt; field which is a list of objects&lt;/p&gt;
&lt;p&gt;We can use the same method as above to define the &lt;code&gt;UpdateExpression&lt;/code&gt;, however this time we can use the &lt;code&gt;list_append&lt;/code&gt; function in our expression to state that we would like to append a value to&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;list_append&lt;/code&gt; function appends one list to another - this means that it needs two lists to operate on. To update a list we can just use itself as the first input and the new list as the second. The &lt;code&gt;UpdateExpression&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET #attr = list_append(#attr, :value)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For our sake we only want to append a single item, so we can just wrap it in an array when we pass it on in the command. The command for the above update looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { DynamoDBClient } from &apos;@aws-sdk/client-dynamodb&apos;
import { marshall, unmarshall } from &apos;@aws-sdk/util-dynamodb&apos;

const client = new DynamoDBClient({})

const pk = &apos;bob&apos;
const sk = 12
const updateValue = {
  place: &apos;home&apos;,
  time: Date.now(),
}

const command = new UpdateItemCommand({
  TableName: &apos;my-table-name&apos;,
  Key: marshall({
    username: pk,
    group: sk,
  }),
  UpdateExpression: &apos;SET #attr = list_append(#attr, :value)&apos;,
  ExpressionAttributeNames: {
    &apos;#attr&apos;: &apos;checkIns&apos;,
  },
  ExpressionAtrributeValues: marshall({
    // array since the update expression works on two lists
    &apos;:value&apos;: [updateValue],
  }),
})

await client.send()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Append to a List Attribute That May Not Exist&lt;/h2&gt;
&lt;p&gt;In some cases, we can end up trying to append to an attribute that may not exist, under these circumstances we can use the &lt;code&gt;is_not_exists&lt;/code&gt; function that takes an attribute name and a fallback value and will return the fallback if the attribute does not exist in the item&lt;/p&gt;
&lt;p&gt;We can change the &lt;code&gt;UpdateExpression&lt;/code&gt; to make use of this as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;SET #attr = list_append(if_not_exists(#attr, :fallback), :value)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the full command looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { DynamoDBClient } from &apos;@aws-sdk/client-dynamodb&apos;
import { marshall, unmarshall } from &apos;@aws-sdk/util-dynamodb&apos;

const client = new DynamoDBClient({})

const pk = &apos;bob&apos;
const sk = 12
const updateValue = {
  place: &apos;home&apos;,
  time: Date.now(),
}

const command = new UpdateItemCommand({
  TableName: &apos;my-table-name&apos;,
  Key: marshall({
    username: pk,
    group: sk,
  }),
  UpdateExpression:
    &apos;SET #attr = list_append(if_not_exists(#attr, :fallback), :value)&apos;,
  ExpressionAttributeNames: {
    &apos;#attr&apos;: &apos;checkIns&apos;,
  },
  ExpressionAtrributeValues: marshall({
    &apos;:value&apos;: [updateValue],
    // fallback to an empty array if the value does not exist before appending
    &apos;:fallback&apos;: [],
  }),
})

await client.send()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above expresson helps us append an item to the list while also providing a fallback for the case where the list item may not exist&lt;/p&gt;
&lt;h2&gt;A Note on Marshalled/Unmarshalled data&lt;/h2&gt;
&lt;p&gt;DynamoDB works with data in the &amp;quot;marshalled&amp;quot; form, which is an object representation for primitive data types (&lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_AttributeValue.html&quot;&gt;AWS Documentation - Attribute Value&lt;/a&gt;). Some examples of marshalled and unmarshalled data can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// STRING
// Unmarshalled
&amp;quot;hello&amp;quot;

// Marshalled
{
  &amp;quot;S&amp;quot;: &amp;quot;Hello&amp;quot;
}

// NUMBER
// Unmarshalled
25

// Marshalled
{
  &amp;quot;N&amp;quot;: &amp;quot;25&amp;quot;
}


// MAP
// Unmarshalled
{
  name: &amp;quot;bob&amp;quot;
}

/// Marshalled
{
  &amp;quot;M&amp;quot;:{
    &amp;quot;name&amp;quot;:{
      &amp;quot;S&amp;quot;:&amp;quot;hello&amp;quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Additional Resources&lt;/h2&gt;
&lt;p&gt;Speaking of DynamoDB updates, it looks like there&apos;s a library for building queries which seems promising and may bwe worth taking a look at called &lt;a href=&quot;https://electrodb.dev/en/core-concepts/introduction/&quot;&gt;ElectroDB&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Draggable Div with XState and React</title><link>https://nabeelvalley.co.za/blog/2023/31-01/xstate-draggable-div/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/31-01/xstate-draggable-div/</guid><description>A simple example of using XState with UI Events to build interactivity</description><pubDate>Tue, 31 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Why State Management&lt;/h2&gt;
&lt;p&gt;Recently I&apos;ve been interested in understanding non-standard user interactions and about how different applications develop this functionality. A particularly good example for me has been looking into the codebase for &lt;a href=&quot;https://www.tldraw.com/&quot;&gt;TLDraw&lt;/a&gt; where I ran into state machines&lt;/p&gt;
&lt;p&gt;Now, I&apos;ve played around with a few state machine libraries and I&apos;m fairly familiar with them and have implemented some fairly simple examples for working with multi-step forms and the like, but I haven&apos;t really used them in the specific context of designing state&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.state-designer.com&quot;&gt;State Designer Library&lt;/a&gt; mentions the idea of &lt;a href=&quot;https://www.state-designer.com/designing-state&quot;&gt;Designing State&lt;/a&gt; which suggests that the design of how the user interface should work and the implementation of it should be treated as independent, in order to do so, we should design the states that we would like to work with separately from the UI that implements the state&lt;/p&gt;
&lt;p&gt;This provides us with a decent abstraction which should make things about state a lot less tangled and easier to reason about&lt;/p&gt;
&lt;h3&gt;XState&lt;/h3&gt;
&lt;p&gt;State management libraries provide us with a set of abstractions and tools for designing state. There are a few that are commonly used, of which I&apos;ll be using &lt;a href=&quot;https://xstate.js.org/&quot;&gt;XState&lt;/a&gt; in this post. XState has pretty good TypeScript support as well as some great tooling for visualizing and designing state on &lt;a href=&quot;https://stately.ai&quot;&gt;Stately&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;For this post I&apos;ve chosen to build a simple draggable div component that makes use of XState. The idea here was to get a feel for the library and see how it can be used to tackle problems around UI interaction&lt;/p&gt;
&lt;h3&gt;Visualizing the State&lt;/h3&gt;
&lt;p&gt;Defining the state can be done using the XState visual editor that can be used in VSCode or Stately, this is useful because it lets you visualize different ways that the state can be represented in a relatively low-friction setting&lt;/p&gt;
&lt;p&gt;The structure I&apos;ve decided on for the representing my component&apos;s state can be seen below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2023/31-01/draggable-state-diagram.png&quot; alt=&quot;XState Diagram of Draggable UI Component&quot;&gt;&lt;/p&gt;
&lt;h3&gt;State Machine Code&lt;/h3&gt;
&lt;p&gt;The code for the above state machine, with some added type information, can be seen below:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Draggable.machine.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { createMachine, assign } from &apos;xstate&apos;

type Position = {
  x: number
  y: number
}

type Delta = {
  dx: number
  dy: number
}

type Focus = {
  focused: boolean
}

export const machine = createMachine(
  {
    schema: {
      context: {} as Position,
      events: {} as
        | { type: &apos;MOVE&apos;; position: Delta }
        | { type: &apos;FOCUS&apos; }
        | { type: &apos;BLUR&apos; },
    },

    initial: &apos;inactive&apos;,
    states: {
      inactive: {
        on: {
          FOCUS: &apos;active&apos;,
        },
      },

      active: {
        on: {
          MOVE: {
            target: &apos;active&apos;,
            internal: true,
            actions: &apos;updatePosition&apos;,
          },
          BLUR: &apos;inactive&apos;,
        },
      },
    },
  },
  {
    actions: {
      updatePosition: assign((context, event) =&amp;gt; ({
        x: event.position.dx + (context.x || 0),
        y: event.position.dy + (context.y || 0),
      })),
    },
  }
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above, we can also see the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;initial&lt;/code&gt; state that is &lt;code&gt;inactive&lt;/code&gt; with an event of &lt;code&gt;FOCUS&lt;/code&gt; which sets the state to &lt;code&gt;active&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;active&lt;/code&gt; state that has an internal event of &lt;code&gt;MOVE&lt;/code&gt; which will trigger the &lt;code&gt;updatePosition&lt;/code&gt; action and an event of &lt;code&gt;BLUR&lt;/code&gt; which sets the state to &lt;code&gt;inactive&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;There is a &lt;code&gt;context&lt;/code&gt; that will store the coordinates of the dragged element&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;actions&lt;/code&gt; object which has an action called &lt;code&gt;updatePosition&lt;/code&gt; which assigns the context to the new position&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can also see that in the schema the type of &lt;code&gt;events&lt;/code&gt; is specified. This makes it so that XState can infer the type of &lt;code&gt;event&lt;/code&gt; passed to the &lt;code&gt;updatePosition&lt;/code&gt; function&lt;/p&gt;
&lt;h3&gt;Attach the State to the UI&lt;/h3&gt;
&lt;p&gt;In order to move from one state to another we use the &lt;code&gt;send&lt;/code&gt; method from XState&lt;/p&gt;
&lt;p&gt;To use a state machine in React we use the &lt;code&gt;useMachine&lt;/code&gt; hook from XState:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Draggable.tsx&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import { useMachine } from &amp;quot;@xstate/react&amp;quot;;
import React from &amp;quot;react&amp;quot;;
import { machine } from &amp;quot;./Draggable.machine&amp;quot;;

interface DraggableProps {
  children: React.ReactNode;
}

export const Draggable = ({ children }: DraggableProps) =&amp;gt; {
  const [current, send] = useMachine(machine);


  // rest of component
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can use the &lt;code&gt;current&lt;/code&gt; to figure out if we are in an active state so that we can do some styling based on that:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Draggable.tsx&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const isActive = current.matches(&apos;active&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And lastly we can hook up the UI Events to the state machine:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Draggable.tsx&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;export const Draggable = ({ children }: DraggableProps) =&amp;gt; {
  const [current, send] = useMachine(machine)

  const isActive = current.matches(&apos;active&apos;)

  return (
    &amp;lt;div style={{ position: &apos;relative&apos; }}&amp;gt;
      &amp;lt;div
        onMouseDown={() =&amp;gt; send(&apos;FOCUS&apos;)}
        onMouseUp={() =&amp;gt; send(&apos;BLUR&apos;)}
        onMouseLeave={() =&amp;gt; send(&apos;BLUR&apos;)}
        onMouseMove={(ev) =&amp;gt; {
          send({
            type: &apos;MOVE&apos;,
            position: {
              dx: ev.movementX,
              dy: ev.movementY,
            },
          })
        }}
        style={{
          position: &apos;absolute&apos;,
          backgroundColor: isActive ? &apos;skyblue&apos; : &apos;red&apos;,
          userSelect: &apos;none&apos;,
          top: current.context.y,
          left: current.context.x,
          padding: 20,
        }}
      &amp;gt;
        {children}
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above will result in a draggable div like so:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://replit.com/@nabeelvalley/DraggableDiv?v=1&quot;&gt;Repl.it link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe frameborder=&amp;quot;0&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;500px&amp;quot; src=&amp;quot;https://replit.com/@nabeelvalley/DraggableDiv?embed=true&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h3&gt;Possible Improvements&lt;/h3&gt;
&lt;p&gt;If you play around with the above example you&apos;ll probably notice that it&apos;s not perfect. Though the states we&apos;ve defined are correct,the complexity in mapping the UI events becomes apparent, as well as the various edge cases that may arise around how DOM events fire in response to user interaction&lt;/p&gt;
&lt;p&gt;Though I don&apos;t aim to solve all of these points for the sake of the example, it&apos;s worth pointing out as a source of exploration. Some possible solutions that may help are things like changing where we listen to specific events, for example listening to the &lt;code&gt;mouseUp&lt;/code&gt; events on only the wrapper and not the draggable component, or changing which specific events we&apos;re listening to&lt;/p&gt;
&lt;p&gt;The idea is that the handling of the UI events is now separated from the actual state management which should make fixing interaction bugs simpler while also decoupling our state from any specific implementation of the UI&lt;/p&gt;
&lt;h2&gt;Further Reading&lt;/h2&gt;
&lt;p&gt;For more information, you can take a look at the &lt;a href=&quot;https://xstate.js.org/docs/&quot;&gt;XState Documentation&lt;/a&gt; or the &lt;a href=&quot;https://www.youtube.com/playlist?list=PLvWgkXBB3dd4ocSi17y1JmMmz7S5cV8vI&quot;&gt;XState YouTube Course&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In addition, I also have a more complex example using XState for building a &lt;a href=&quot;https://replit.com/@nabeelvalley/XStateTodoApp&quot;&gt;Todo App&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Structuring HTML Content</title><link>https://nabeelvalley.co.za/blog/2023/26-01/html-to-structured-content/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/26-01/html-to-structured-content/</guid><description>Transforming HTML into structured data to work with EditorJS</description><pubDate>Thu, 26 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Isn&apos;t HTML a structure?&lt;/h2&gt;
&lt;p&gt;HTML content is structured as a tree - while this is useful for the medium, this structure isn&apos;t very convenient for transforming into data that can be used outside of the web or with libraries that use content in a more flat structure&lt;/p&gt;
&lt;p&gt;While building &lt;a href=&quot;https://articly.vercel.app&quot;&gt;Articly&lt;/a&gt; I wanted to use a library called &lt;a href=&quot;https://editorjs.io&quot;&gt;EditorJS&lt;/a&gt; for displaying and making text content interactive. An immediate problem I ran into was importing content into the editor since it requires the data in a specific format - which is not HTML but rather an array of objects with simplified content&lt;/p&gt;
&lt;h2&gt;StackOverflow is helpful sometimes&lt;/h2&gt;
&lt;p&gt;In order to get the content into the EditorJS format, I needed to find a way to transform the HTML that I had from scraping the web and reading RSS feeds into something I could use as some kind of base&lt;/p&gt;
&lt;p&gt;After a little bit of searching, I found this handy function on &lt;a href=&quot;https://stackoverflow.com/questions/12980648/map-html-to-json&quot;&gt;StackOverflow&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;//Recursively loop through DOM elements and assign properties to object
function treeHTML(element, object) {
  object[&apos;type&apos;] = element.nodeName
  var nodeList = element.childNodes
  if (nodeList != null) {
    if (nodeList.length) {
      object[&apos;content&apos;] = []
      for (var i = 0; i &amp;lt; nodeList.length; i++) {
        if (nodeList[i].nodeType == 3) {
          object[&apos;content&apos;].push(nodeList[i].nodeValue)
        } else {
          object[&apos;content&apos;].push({})
          treeHTML(nodeList[i], object[&apos;content&apos;][object[&apos;content&apos;].length - 1])
        }
      }
    }
  }
  if (element.attributes != null) {
    if (element.attributes.length) {
      object[&apos;attributes&apos;] = {}
      for (var i = 0; i &amp;lt; element.attributes.length; i++) {
        object[&apos;attributes&apos;][element.attributes[i].nodeName] =
          element.attributes[i].nodeValue
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the above as a guideline, I concluded that the main thing that I need was to iterate over the HTML content in a way that would allow me to build a content array which is recursive - the idea at this point is not to remove the tree structure, but rather to transform it into something that&apos;s a bit easier to work with&lt;/p&gt;
&lt;h2&gt;A different tree&lt;/h2&gt;
&lt;p&gt;Now that I had an idea of how to approach the problem, the next step was to define the structure I wanted, below is the final structure I decided on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The source HTML element object needs to be stored as this may useful to downstream processors&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;tagName&lt;/code&gt; of the element will be needed to determine how a specific element needs to be handled&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;textContent&lt;/code&gt; and &lt;code&gt;innerHTML&lt;/code&gt; of the element to be stored - this is the core data of the element&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;attributes&lt;/code&gt; of the HTML element should be unwrapped to make it easier for downstream code to read&lt;/li&gt;
&lt;li&gt;The children of the element need to be converted into the the same type by recursively following steps 1-5&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Based on the above, the type definition can be seen below along with the implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type TagName = Uppercase&amp;lt;keyof HTMLElementTagNameMap&amp;gt;

type HTMLStringContent = string

type TransformResult = {
  element: Element
  tagName: TagName
  textContent?: string
  htmlContent?: HTMLStringContent
  attrs: Record&amp;lt;string, string&amp;gt;
  children: TransformResult[]
}

const transform = (el: Element): TransformResult =&amp;gt; ({
  element: el,
  // tag names are strings internally but that&apos;s not very informative downstream
  tagName: el.tagName as TagName,
  textContent: el.textContent || undefined,
  htmlContent: el.innerHTML,
  children: Array.from(el.children).map(transform),
  attrs: Array.from(el.attributes).reduce(
    (acc, { name, value }) =&amp;gt; ({ ...acc, [name]: value }),
    {}
  ),
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that I have the data as a tree structure, we can pass in some simple HTML to see what pops out the other end.&lt;/p&gt;
&lt;p&gt;Given the following HTML content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;

  &amp;lt;section&amp;gt;
    &amp;lt;img src=&amp;quot;hello.jpg&amp;quot; alt=&amp;quot;this is an image&amp;quot; /&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can transform it like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// use the DOM to parse it from a string
const el = new DOMParser().parseFromString(html, &apos;text/html&apos;).body

// the convertHtmlToBlocks function takes an HTML ELement
const transformed = transform(el)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;transformed&lt;/code&gt; data looks something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;element&amp;quot;: {},
  &amp;quot;tagName&amp;quot;: &amp;quot;BODY&amp;quot;,
  &amp;quot;textContent&amp;quot;: &amp;quot;\n  Hello World\n\n  \n    \n  \n&amp;quot;,
  &amp;quot;htmlContent&amp;quot;: &amp;quot;&amp;lt;div&amp;gt;\n  &amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;\n\n  &amp;lt;section&amp;gt;\n    &amp;lt;img src=\&amp;quot;hello.jpg\&amp;quot; alt=\&amp;quot;this is an image\&amp;quot;&amp;gt;\n  &amp;lt;/section&amp;gt;\n&amp;lt;/div&amp;gt;&amp;quot;,
  &amp;quot;children&amp;quot;: [
    {
      &amp;quot;element&amp;quot;: {},
      &amp;quot;tagName&amp;quot;: &amp;quot;DIV&amp;quot;,
      &amp;quot;textContent&amp;quot;: &amp;quot;\n  Hello World\n\n  \n    \n  \n&amp;quot;,
      &amp;quot;htmlContent&amp;quot;: &amp;quot;\n  &amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;\n\n  &amp;lt;section&amp;gt;\n    &amp;lt;img src=\&amp;quot;hello.jpg\&amp;quot; alt=\&amp;quot;this is an image\&amp;quot;&amp;gt;\n  &amp;lt;/section&amp;gt;\n&amp;quot;,
      &amp;quot;children&amp;quot;: [
        {
          &amp;quot;element&amp;quot;: {},
          &amp;quot;tagName&amp;quot;: &amp;quot;P&amp;quot;,
          &amp;quot;textContent&amp;quot;: &amp;quot;Hello World&amp;quot;,
          &amp;quot;htmlContent&amp;quot;: &amp;quot;Hello World&amp;quot;,
          &amp;quot;children&amp;quot;: [],
          &amp;quot;attrs&amp;quot;: {}
        },
        {
          &amp;quot;element&amp;quot;: {},
          &amp;quot;tagName&amp;quot;: &amp;quot;SECTION&amp;quot;,
          &amp;quot;textContent&amp;quot;: &amp;quot;\n    \n  &amp;quot;,
          &amp;quot;htmlContent&amp;quot;: &amp;quot;\n    &amp;lt;img src=\&amp;quot;hello.jpg\&amp;quot; alt=\&amp;quot;this is an image\&amp;quot;&amp;gt;\n  &amp;quot;,
          &amp;quot;children&amp;quot;: [
            {
              &amp;quot;element&amp;quot;: {},
              &amp;quot;tagName&amp;quot;: &amp;quot;IMG&amp;quot;,
              &amp;quot;htmlContent&amp;quot;: &amp;quot;&amp;quot;,
              &amp;quot;children&amp;quot;: [],
              &amp;quot;attrs&amp;quot;: { &amp;quot;src&amp;quot;: &amp;quot;hello.jpg&amp;quot;, &amp;quot;alt&amp;quot;: &amp;quot;this is an image&amp;quot; }
            }
          ],
          &amp;quot;attrs&amp;quot;: {}
        }
      ],
      &amp;quot;attrs&amp;quot;: {}
    }
  ],
  &amp;quot;attrs&amp;quot;: {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not too dissimilar to the structure raw HTML we would have had if we just used &lt;code&gt;DOMParser&lt;/code&gt; directly, however it now has a lot less noise&lt;/p&gt;
&lt;h2&gt;Deforestation&lt;/h2&gt;
&lt;p&gt;As I mentioned earlier, we need to transform the data into a flat array of items - so the question that comes up now is - how do we do that?&lt;/p&gt;
&lt;p&gt;Looking at the input HTML we used, we can break things up into two types of elements - containers and content&lt;/p&gt;
&lt;p&gt;Containers are pretty much useless to the content structure we&apos;re trying to build - the content is all we really care about&lt;/p&gt;
&lt;p&gt;This is an important distinction because it tells us what we can throw away&lt;/p&gt;
&lt;p&gt;Secondly, we can think of the content inside of a container as an array of content, once we remove all the containers, this content will become flat&lt;/p&gt;
&lt;p&gt;So for example, this HTML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;

  &amp;lt;section&amp;gt;
    &amp;lt;img src=&amp;quot;hello.jpg&amp;quot; alt=&amp;quot;this is an image&amp;quot; /&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we remove the containers can be thought of as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;

&amp;lt;img src=&amp;quot;hello.jpg&amp;quot; alt=&amp;quot;this is an image&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which can be thought of as an array like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;;[paragraph, image]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is our end goal. In order to get here we still have to figure out two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How can we separate out the containers from the content&lt;/li&gt;
&lt;li&gt;How can we transform the content into the structure that&apos;s useful to us&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Separating the leaves from the wood&lt;/h2&gt;
&lt;p&gt;If we think as containers as having no meaningful data, and just being containers for content, then we can conclude that a way to view the data structure is as an array of content - the container is the array, and the content is the items in the array&lt;/p&gt;
&lt;p&gt;So, we can write a transformer for a container as something that just returns an array of content&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const removeContainer = (data: TransformResult) =&amp;gt; data.children
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above is pretty useful, since this means that the following HTML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;

  &amp;lt;section&amp;gt;
    &amp;lt;img src=&amp;quot;hello.jpg&amp;quot; alt=&amp;quot;this is an image&amp;quot; /&amp;gt;
  &amp;lt;/section&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Will be essentially be converted to this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;

&amp;lt;section&amp;gt;
  &amp;lt;img src=&amp;quot;hello.jpg&amp;quot; alt=&amp;quot;this is an image&amp;quot; /&amp;gt;
&amp;lt;/section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we still see that there&apos;s a &lt;code&gt;section&lt;/code&gt; leftover since we only returned one layer of children. Since we already have a way to get rid of the wrapper, we can just apply that to the child that&apos;s a section,&lt;/p&gt;
&lt;p&gt;So we could have something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const removeContainer = (data: TransformResult) =&amp;gt;
  data.children.map((child) =&amp;gt;
    isContainer(child) ? removeContainer(child) : child
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the function is a bit weird because the inner map is either returning an array if the &lt;code&gt;child&lt;/code&gt; is a container, or a single &lt;code&gt;child&lt;/code&gt; if it&apos;s not - for consistency, let&apos;s just always return an array:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const removeContainer = (data: TransformResult) =&amp;gt;
  data.children.map((child) =&amp;gt;
    isContainer(child) ? removeContainer(child) : [child]
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Much better, but now we&apos;ve introduced something weird - instead of just returning a &lt;code&gt;TransformResult[]&lt;/code&gt; we&apos;re now returning a &lt;code&gt;TransformResult[][]&lt;/code&gt; - let&apos;s just leave this here for now, we can always unwrap the arrays later - importantly we now know that we&apos;ve eliminated the wrappers, so the content we&apos;re left with now represents:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;p&amp;gt;Hello World&amp;lt;/p&amp;gt;

&amp;lt;img src=&amp;quot;hello.jpg&amp;quot; alt=&amp;quot;this is an image&amp;quot; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So this is pretty great, and is the general idea of how we can unwrap things - next up we can talk about transforming the specific elements into useful data blocks&lt;/p&gt;
&lt;h2&gt;Building blocks&lt;/h2&gt;
&lt;p&gt;EditorJS has different sections - blocks as it calls them - of content. These are simple Javascript objects that represent the data for the block&lt;/p&gt;
&lt;p&gt;For the sake of our discussion, we&apos;re going to consider two blocks - &lt;code&gt;ParagraphBlock&lt;/code&gt; and &lt;code&gt;ImageBlock&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The simplified types that represent their data can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export type ParagraphBlock = {
  type: &apos;paragraph&apos;
  data: {
    text: string
  }
}

export type SimpleImageBlock = {
  type: &apos;image&apos;
  data: {
    url: string
    caption: string
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can look at the the &lt;code&gt;TransformResult&lt;/code&gt; for each of the above elements from when we passed the HTML into our &lt;code&gt;transform&lt;/code&gt; function previously, we can see&lt;/p&gt;
&lt;p&gt;For the paragraph:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;element&amp;quot;: {},
  &amp;quot;tagName&amp;quot;: &amp;quot;P&amp;quot;,
  &amp;quot;textContent&amp;quot;: &amp;quot;Hello World&amp;quot;,
  &amp;quot;htmlContent&amp;quot;: &amp;quot;Hello World&amp;quot;,
  &amp;quot;children&amp;quot;: [],
  &amp;quot;attrs&amp;quot;: {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which can be translated to the &lt;code&gt;ParagraphBlock&lt;/code&gt; data as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;{
  type: &amp;quot;paragraph&amp;quot;,
  data: {
    text: &amp;quot;Hello World&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A function for doing this could look something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const convertParagraph = (data: TransformResult): ParagraphBlock | undefined =&amp;gt;
  data.textContent
    ? {
        type: &apos;paragraph&apos;,
        data: {
          text: data.textContent,
        },
      }
    : undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cool, this lets us transform a paragraph into some structured data.&lt;/p&gt;
&lt;p&gt;We can do something similar for images:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const convertImage = (data: TransformResult): ImageBlock | undefined =&amp;gt;
  data.attrs.src
    ? {
        type: &apos;image&apos;,
        data: {
          url: data.attrs.src,
          caption: data.attrs.alt || &apos;&apos;,
        },
      }
    : undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;So now that we know how to transform the HTML into something useful, remove the wrappers, and represent individual HTML sections as content blocks, we can put it all together into something that lets us convert a section of HTML fully:&lt;/p&gt;
&lt;p&gt;First, we can update the &lt;code&gt;removeContainer&lt;/code&gt; function to call the converter on the type of tag that it finds:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// note that we need a handler for BODY since the `DOMParser` will always add a body element when parsing
const isContainer = (data: TransformResult) =&amp;gt;
  data.tagName === &apos;BODY&apos; ||
  data.tagName === &apos;DIV&apos; ||
  data.tagName === &apos;SECTION&apos;

const removeContainer = (data: TransformResult) =&amp;gt;
  data.children.map((child) =&amp;gt; {
    if (isContainer(child)) {
      return removeContainer(child)
    } else {
      if (child.tagName === &apos;IMG&apos;) {
        const block = convertImage(child)

        return block ? [block] : []
      } else if (child.tagName === &apos;P&apos;) {
        const block = convertParagraph(child)

        return block ? [block] : []
      }
    }
  })
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, you can probably see a pattern that&apos;s going to arise as we add more and more elements that we want to handle - so it may be better to create a list of handlers for different tag types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Block = ParagraphBlock | ImageBlock

const handlers: Partial&amp;lt;Record&amp;lt;TagName, (data: TransformResult) =&amp;gt; Block[]&amp;gt;&amp;gt; = {
  // content blocks
  IMG: convertImage,
  P: convertParagraph,

  // container blocks - we will always want to remove these
  DIV: removeContainer,
  SECTION: removeContainer,
  BODY: removeContainer,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the above structure, we can tweak the &lt;code&gt;convertImage&lt;/code&gt; and &lt;code&gt;convertParagraph&lt;/code&gt; functions a bit so that they return the &lt;code&gt;Block[]&lt;/code&gt; consistently:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const convertParagraph = (data: TransformResult): ParagraphBlock[] =&amp;gt;
  data.textContent
    ? [
        {
          type: &apos;paragraph&apos;,
          data: {
            text: data.textContent,
          },
        },
      ]
    : []

const convertImage = (data: TransformResult): ImageBlock[] =&amp;gt;
  data.attrs.src
    ? [
        {
          type: &apos;image&apos;,
          data: {
            url: data.attrs.src,
            caption: data.attrs.alt || &apos;&apos;,
          },
        },
      ]
    : []
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can update the &lt;code&gt;removeContainer&lt;/code&gt; function to handle things a bit more genericallly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const removeContainer = (data: TransformResult): Block[] =&amp;gt; {
  const contentArr = data.children.map((child) =&amp;gt; {
    const handler = handlers[child.tagName]

    if (!handler) {
      return []
    }

    return handler(child)
  })

  return contentArr.flat(1)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&apos;re really attentive, you&apos;ll notice the &lt;code&gt;contentArr.flat(1)&lt;/code&gt; that was added in the above snippet, this flattens the &lt;code&gt;Block[][]&lt;/code&gt; into a &lt;code&gt;Block[]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Once we&apos;ve got that, we can define a &lt;code&gt;convert&lt;/code&gt; function that will take the HTML and output the structured blocks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const convert = (el: Element): Block[] =&amp;gt; {
  const transformed = transform(el)

  const initialHandler = handlers[transformed.tagName]

  if (!initialHandler) {
    throw new Error(&apos;No handler found for top-level wrapper&apos;)
  }

  return initialHandler(transformed)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Adding more content types&lt;/h2&gt;
&lt;p&gt;That&apos;s about it, to handle more specific types of content or other HTML elements is just a matter of following the recipe that we did above:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define if an element is a container or content&lt;/li&gt;
&lt;li&gt;If it&apos;s a container, just use the &lt;code&gt;removeContainer&lt;/code&gt; handler&lt;/li&gt;
&lt;li&gt;If it&apos;s content then define a handler for the specific kind of content&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you roll this out for loads of elements you&apos;ll eventually have a pretty robust converter&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That&apos;s it! We&apos;ve covered the basics for building a transformer like this, and once you have a good feel for how this works, the concepts can be applied to loads of different usecases&lt;/p&gt;
&lt;p&gt;If you&apos;d like to see the completed version of my converter, you can take a look at the &lt;a href=&quot;https://github.com/nabeelvalley/html-editorjs&quot;&gt;&lt;code&gt;html-editorjs&lt;/code&gt; GitHub repo&lt;/a&gt; and if you&apos;d like to look at it in action in an application then take a look at &lt;a href=&quot;https://articly.vercel.app&quot;&gt;Articly&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Let&apos;s talk about Feeds</title><link>https://nabeelvalley.co.za/blog/2023/24-01/about-rss/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2023/24-01/about-rss/</guid><description>A short introduction to RSS feeds</description><pubDate>Tue, 24 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Order Up&lt;/h2&gt;
&lt;p&gt;Life&apos;s busy and disastrous and trying to pop in and talk to myself for a few hours is unattainable most of the time&lt;/p&gt;
&lt;p&gt;Recently I&apos;ve gotten really into RSS. RSS is short for &lt;code&gt;Really Simple Syndication&lt;/code&gt; and it&apos;s basically just a format/standard that enables websites to share their content in a way that&apos;s easy for other websites or applications to consume&lt;/p&gt;
&lt;h2&gt;Starter&lt;/h2&gt;
&lt;p&gt;An RSS Feed is really just an XML file that contains information on a website&apos;s content, and depending on the nature of the website this is usually something like a blog or podcast feed, but I&apos;ve also seen RSS used for things like project statuses or website uptime information&lt;/p&gt;
&lt;h2&gt;Main Course&lt;/h2&gt;
&lt;p&gt;Here&apos;s a sample RSS Feed that I found on &lt;a href=&quot;http://www.rss-tools.com/rss-example.htm&quot;&gt;RSS Tools&lt;/a&gt; that I modified a bit to represent something you might see when working with websites or blog content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;rss version=&amp;quot;2.0&amp;quot;&amp;gt;
  &amp;lt;channel&amp;gt;
    &amp;lt;title&amp;gt;RSS Example&amp;lt;/title&amp;gt;
    &amp;lt;description&amp;gt;This is an example of an RSS feed&amp;lt;/description&amp;gt;
    &amp;lt;link&amp;gt;http://www.domain.com/link.htm&amp;lt;/link&amp;gt;
    &amp;lt;lastBuildDate&amp;gt;Mon, 28 Aug 2006 11:12:55 -0400&amp;lt;/lastBuildDate&amp;gt;
    &amp;lt;pubDate&amp;gt;Tue, 29 Aug 2006 09:00:00 -0400&amp;lt;/pubDate&amp;gt;
    &amp;lt;item&amp;gt;
      &amp;lt;title&amp;gt;Item Example&amp;lt;/title&amp;gt;
      &amp;lt;description&amp;gt;This is an example of an Item&amp;lt;/description&amp;gt;
      &amp;lt;link&amp;gt;http://www.domain.com/link.htm&amp;lt;/link&amp;gt;
      &amp;lt;guid isPermaLink=&amp;quot;false&amp;quot;&amp;gt;1102345&amp;lt;/guid&amp;gt;
      &amp;lt;pubDate&amp;gt;Tue, 29 Aug 2006 09:00:00 -0400&amp;lt;/pubDate&amp;gt;
      &amp;lt;content:encoded&amp;gt;This is some content&amp;lt;/content:encoded&amp;gt;
    &amp;lt;/item&amp;gt;
  &amp;lt;/channel&amp;gt;
&amp;lt;/rss&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example we can see a &lt;code&gt;channel&lt;/code&gt; which defines a source for content&lt;/p&gt;
&lt;p&gt;Next up we&apos;ve got the &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;link&lt;/code&gt;, &lt;code&gt;lastBuildDate&lt;/code&gt;, and &lt;code&gt;pubDate&lt;/code&gt; which are the metadata for the overall feed and are required for readers that may be accessing the feed&lt;/p&gt;
&lt;p&gt;Now, all of that is really cool, but we&apos;re not into the juicy bits yet - diving into the content itself we see in the &lt;code&gt;item&lt;/code&gt; section.&lt;/p&gt;
&lt;p&gt;A feed can define multiple &lt;code&gt;item&lt;/code&gt; tags - each of these would have some metadata as well as the actual content associated with the post&lt;/p&gt;
&lt;p&gt;In the example, each &lt;code&gt;item&lt;/code&gt; has the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;title&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;link&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;guid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;content:encoded&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The above fields are pretty so-so, but the part I find intriguing is the &lt;code&gt;guid&lt;/code&gt; which is any unique identifier for an item in a feed, this doesn&apos;t have a specific format but just needs to be unique to the feed.&lt;/p&gt;
&lt;p&gt;Next, is the &lt;code&gt;content:encoded&lt;/code&gt; section which is what the feed uses to share it&apos;s content - this can either be plain text or HTML, and it&apos;s up to the client to figure it out - based on this I suppose you could really share any content or data which is a pretty cool concept&lt;/p&gt;
&lt;h2&gt;Dessert&lt;/h2&gt;
&lt;p&gt;Overall, RSS is pretty simple as a format and has some issues and limitation - versions prior to RSS 2.0 can also be a bit difficult to work with as it&apos;s not totally standardised&lt;/p&gt;
&lt;p&gt;Another issue I&apos;ve encountered when working with RSS is the size of the file itself. Some feeds post frequently and may have very long posts. This can lead to very long posts&lt;/p&gt;
&lt;p&gt;I&apos;ve noticed that some blogs with large RSS feeds choose to only store their latest items on the RSS feed, this means that consumer interested in reading older items need to have some cache of their own which was made when the items were initially posted - you could use the &lt;code&gt;guid&lt;/code&gt; for this or some kind of diffing method but pretty much anything outside of the XML file delivered is the job of a consumer to work with&lt;/p&gt;
&lt;h2&gt;The Bill&lt;/h2&gt;
&lt;p&gt;I&apos;ve seen a lot of revived interest in the RSS format but there are also competitors to the format like ATOM which is a more complete standard and supports features like paged feeds and explicit content type definitions&lt;/p&gt;
&lt;p&gt;ATOM seems to solve the few issues I have with RSS but RSS is still &lt;strong&gt;literally everywhere&lt;/strong&gt; which is tough to fight&lt;/p&gt;
&lt;p&gt;My latest side project is an RSS reader called &lt;a href=&quot;https://articly.vercel.app&quot;&gt;Articly&lt;/a&gt; which is built with Svelte/SvelteKit since I really wanted to get a feeling for the framework to build a full application and this seemed like a fun opportunity to do that&lt;/p&gt;
</content:encoded></item><item><title>Virtual Machine vs Containers</title><link>https://nabeelvalley.co.za/blog/2022/20-12/vms-vs-containers-diagram/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/20-12/vms-vs-containers-diagram/</guid><description>Diagrams Comparing Virtual Machines and Containers</description><pubDate>Tue, 20 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Virtual Machines&lt;/h2&gt;
&lt;p&gt;The below diagram illustrates a VM as it would traditionally be run along with it&apos;s relevant applications and dependencies:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/20-12/virtual-machines.svg&quot; alt=&quot;Traditional Virtual Machine Diagram&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Containers&lt;/h2&gt;
&lt;p&gt;The below diagram shows conainers running on a Container runtime in which they share dependencies as well as shows the relationship between an image and container instances&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/20-12/containers.svg&quot; alt=&quot;Containers and Images&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>Smooth Bottom Navigator with Secondary Actions</title><link>https://nabeelvalley.co.za/blog/2022/15-12/smooth-bottom-nav-with-actions/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/15-12/smooth-bottom-nav-with-actions/</guid><description>A Smooth Bottom Navigator using CSS Transitions and Svelte</description><pubDate>Thu, 15 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Not dissimilar from my previous post on the &lt;a href=&quot;/blog/2022/13-11/svelte-expanding-nav&quot;&gt;expanding bottom nav&lt;/a&gt; this expands on the idea of animating between states in the navigator in a more global way, this version makes use of a similar animation/transition pattern but does so by modifying the heights as well as the absolute positioning of different components&lt;/p&gt;
&lt;p&gt;The implementation below takes the overall concept to the simplest possible state, however some refinements that can still be made include being responsive to the size of the additional content as well as doing a more accurate calculation on how large the sliding tab should be and how it&apos;s placed&lt;/p&gt;
&lt;p&gt;The values for the padding/positions are very hardcoded, but in practice you&apos;d likely want to make these respond to data provided and size appropriately in regards to rest of the component&lt;/p&gt;
&lt;p&gt;Here&apos;s the svelte code below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script&amp;gt;
  import {
    InboxIcon,
    HomeIcon,
    DatabaseIcon,
    MessageCircleIcon,
    MicIcon,
    MusicIcon,
  } from &amp;quot;svelte-feather-icons&amp;quot;;

  let selected = &amp;quot;home&amp;quot;;

  const icons = [
    {
      id: &amp;quot;home&amp;quot;,
      icon: HomeIcon,
    },
    {
      id: &amp;quot;database&amp;quot;,
      icon: DatabaseIcon,
    },
    {
      id: &amp;quot;message&amp;quot;,
      icon: MessageCircleIcon,
    },
    {
      id: &amp;quot;mic&amp;quot;,
      icon: MicIcon,
    },
  ];

  $: selectedIndex = icons.findIndex((item) =&amp;gt; item.id === selected);
  $: expanded = selected === &amp;quot;mic&amp;quot;;
&amp;lt;/script&amp;gt;

&amp;lt;h1&amp;gt;{selected}&amp;lt;/h1&amp;gt;

&amp;lt;div class=&amp;quot;wrapper&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;background&amp;quot; class:expanded class:collapsed={!expanded}&amp;gt;
    &amp;lt;div
      class=&amp;quot;slider&amp;quot;
      style=&amp;quot;--left: {(selectedIndex / icons.length) * 100}%;--right: {((selectedIndex+1) / icons.length) * 100}%;&amp;quot;
    /&amp;gt;
    &amp;lt;div class=&amp;quot;content&amp;quot; class:expanded class:collapsed={!expanded}&amp;gt;
      &amp;lt;MusicIcon /&amp;gt;
      &amp;lt;p&amp;gt;Recording: 00:01:23&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div class=&amp;quot;items&amp;quot;&amp;gt;
    {#each icons as icon}
      &amp;lt;div
        class=&amp;quot;item&amp;quot;
        on:click={() =&amp;gt; (selected = icon.id)}
        on:keypress={console.log}
      &amp;gt;
        &amp;lt;svelte:component this={icon.icon} /&amp;gt;
      &amp;lt;/div&amp;gt;
    {/each}
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;style global&amp;gt;
  /* uses fixed postion in order to lock it to lock the component to the bototom of the screen */
  .wrapper {
    position: fixed;
    width: 100vw;
    bottom: 0px;
  }

  /* ensure the background and items are all placed the same since they need to overlap	 */
  .items,
  .background {
    height: 0px;
    position: absolute;
    left: 0px;
    bottom: 20px;
    right: 0px;
    max-width: 80vw;
    margin-left: auto;
    margin-right: auto;
  }

  .background {
    border: solid 1px black;
    border-radius: 16px;
    background-color: white;
    height: 52px;

    transition: height 300ms ease-in-out;
  }

  .background.collapsed {
    transition-delay: 150ms;
  }

  .background.expanded {
    height: 100px;
    transition-delay: 0ms;
  }

  .content {
    overflow: hidden;
    display: flex;
    flex-direction: row;
    gap: 16px;
    height: 24px;
    opacity: 1;
    padding: 20px 40px;
    transition: all 300ms ease-in-out;
  }

  .content.collapsed {
    height: 0;
    opacity: 0;
    padding: 0px 40px;
    transition-delay: 0ms;
  }

  .content.expanded {
    height: 24px;
    opacity: 1;
    transition-delay: 150ms;
  }

  .content p {
    margin: 0;
  }

  .slider {
    position: absolute;
    left: calc(var(--left) + 6px);
    right: va(--left);
    bottom: 6px;
    height: 40px;
    width: calc(var(--right) - var(--left) - 12px);
    border-radius: 12px;
    background-color: #87b5eb70;
    transition: left 300ms ease-in-out;
  }

  .items {
    display: flex;
    flex-direction: row;
    justify-content: space-around;
    height: 40px;
  }

  /* set the icon color	 */
  .item {
    color: black;
  }

  /* select a better default font */
  * {
    font-family: Arial, Helvetica, sans-serif;
    margin: 0;
    padding: 0;
  }
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the current version of the component can be seen here:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/AnimatedBottomNav?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Podcast and RSS Reader App Design</title><link>https://nabeelvalley.co.za/blog/2022/14-12/rss-podcast-app-design/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/14-12/rss-podcast-app-design/</guid><description>A design study in building an RSS and Podcasting App in Figma with light and dark mode</description><pubDate>Wed, 14 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve been developing an app for reading RSS feeds and listening to podcasts for personal use recently, and I finally had some inspiration as far as the design goes. Though it&apos;s ever-changing, here&apos;s a preview of the design at this point&lt;/p&gt;
&lt;p&gt;The app is meant to provide a reading space for RSS feeds as well as allow a user to bookmark articles and tweets for later reading. In addition, it provides a way to listen to podcasts while browsing other content that&apos;s been added in a way that feels consistent and easy to use across all platforms&lt;/p&gt;
&lt;h2&gt;Mobile&lt;/h2&gt;
&lt;p&gt;I&apos;ve tried to remove anything that&apos;s not absolutely essential from the overall app with the goal of preventing clutter on the mobile app. In order to do this I&apos;ve made the bottom navigation something that adapts and shows the user relevant actions based on the screen they&apos;re on as opposed to providing a combination of local and global menus as is normally seen in mobile apps&lt;/p&gt;
&lt;p&gt;For the navigation I&apos;m liking the idea of a static bottom navigation that transforms and adapts as the user moves through the app - this is a decision that&apos;s persisted with the desktop design as well because of how it aids in delivering a cohesive cross-platform experience&lt;/p&gt;
&lt;h3&gt;Light&lt;/h3&gt;
&lt;p&gt;For the light theme I&apos;ve settled on a warm-ish background to link up with the idea of &amp;quot;highlighting&amp;quot; when reading as one might do on paper&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/14-12/mobile-light.png&quot; alt=&quot;Mobile Light&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Dark&lt;/h3&gt;
&lt;p&gt;For the dark color scheme I wanted to bring something interesting to the color palette since the typical &amp;quot;black&amp;quot; style was feeling boring. I figured color was a way to add some interest to the relatively text-heavy UI and the green was chosen for the feeling of comfort it brings which should bring a softer feel for reading&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/14-12/mobile-dark.png&quot; alt=&quot;Mobile Dark&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Desktop&lt;/h2&gt;
&lt;p&gt;For the desktop view my focus was to keep things pretty minimal and reduce the visual noise, focusing on the reader experience while being consistent with the mobile view, offering some simple style and layout modifications to better make use of the available space&lt;/p&gt;
&lt;p&gt;As far as the inbox view goes, there are some simple tabs at the top that allow switching between the different article types as in the mobile case but aside from some spacing and font size tweaks everything else is pretty much aligned to the mobile style&lt;/p&gt;
&lt;p&gt;For the article view I&apos;m taking advantage of the added space in the bottom to add some of the actions that are at the top of the screen in the mobile view - this helps make better use of the space and keep the reading canvas clean as well as isolate actions into a single place which should make it easier to navigate around the app using a mouse&lt;/p&gt;
&lt;h3&gt;Light&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/14-12/desktop-light.png&quot; alt=&quot;Desktop Light&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Dark&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/14-12/desktop-dark.png&quot; alt=&quot;Desktop Dark&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>Typescript Utilities</title><link>https://nabeelvalley.co.za/blog/2022/13-12/typescript-utilities/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/13-12/typescript-utilities/</guid><description>Some general purpose utility types</description><pubDate>Mon, 12 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;import Snippet from &apos;@/components/Snippet.astro&apos;&lt;/p&gt;
&lt;p&gt;Here&apos;s a collection of some utility types I&apos;ve put together:&lt;/p&gt;
&lt;h2&gt;Functions&lt;/h2&gt;
&lt;p&gt;&amp;lt;Snippet  path=&amp;quot;ts-utils/functions.ts&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Arrays&lt;/h2&gt;
&lt;p&gt;&amp;lt;Snippet  path=&amp;quot;ts-utils/arrays.ts&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Objects&lt;/h2&gt;
&lt;p&gt;&amp;lt;Snippet  path=&amp;quot;ts-utils/objects.ts&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;Strings&lt;/h2&gt;
&lt;p&gt;&amp;lt;Snippet  path=&amp;quot;ts-utils/strings.ts&amp;quot; /&amp;gt;&lt;/p&gt;
&lt;h2&gt;JSON Schema&lt;/h2&gt;
&lt;p&gt;Type for inferring a simple JSON Schema into a TypeScript type. I think this will become super useful once Typescript adds support for importing JSON values as &lt;code&gt;const&lt;/code&gt;. This will mean that using the schema would be something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// currently the `const` part doesn&apos;t exist, but would be super cool if we could get here
import schema from &apos;./my-schema.json&apos; with { type: &apos;json&apos;, const: true };

export type MySchema = FromJSONSchema&amp;lt;typeof schema&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The open issue that would make the above possible is this: https://github.com/microsoft/TypeScript/issues/32063&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&apos;s relatively trivial to implement some kind of pre-build script that could do this for all JSON schemas but I think it&apos;s worth waiting till the TS part of this solution exists because it would be great to be able to infer this statically&lt;/p&gt;
&lt;p&gt;&amp;lt;Snippet  path=&amp;quot;ts-utils/json-schema.ts&amp;quot; /&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Un-editable sections inside of a content editable</title><link>https://nabeelvalley.co.za/blog/2022/16-11/uneditable-sections-inside-of-conteneditable/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/16-11/uneditable-sections-inside-of-conteneditable/</guid><description>Block user interactions and editing within a contenteditable or specific parts of it</description><pubDate>Wed, 16 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was working on an &lt;a href=&quot;https://editorjs.io/&quot;&gt;EditorJS&lt;/a&gt; plugin and needed to have a way of creating a block that would restrict certain user interactions&lt;/p&gt;
&lt;p&gt;Initially, I tried to make use of event listeners to block the undesirable events, but the behavior on mobile was inconsistent and I wanted to avoid the mobile keyboard popping up as well when needed&lt;/p&gt;
&lt;p&gt;In addition to the above, I also noticed that even when blocking the events using JavaScript, though the debugger didn&apos;t register the event, the user was still able to make changes to the sections being blocked&lt;/p&gt;
&lt;p&gt;The solution proved to be fairly simple, though only tested on chrome so it may not be robust.&lt;/p&gt;
&lt;p&gt;In my case, what worked was the following:&lt;/p&gt;
&lt;p&gt;&amp;lt;style&amp;gt;
.demo-editable {
padding: 10px;
background-color: skyblue;
}&lt;/p&gt;
&lt;p&gt;.demo-uneditable {
padding: 10px;
background-color: salmon;
}
&amp;lt;/style&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div contenteditable=&amp;quot;true&amp;quot;&amp;gt;
  &amp;lt;div contenteditable=&amp;quot;false&amp;quot;&amp;gt;
    I should be uneditable, and on mobile won&apos;t even trigger a keyboard popup
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;div class=&amp;quot;demo-editable&amp;quot; contenteditable=&amp;quot;true&amp;quot;&amp;gt;
&amp;lt;div contenteditable=&amp;quot;false&amp;quot;&amp;gt;
I should be uneditable, and on mobile won&apos;t even trigger a keyboard popup
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;Now, more generally, we can have other editable content while still having uneditable sections&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div contenteditable=&amp;quot;true&amp;quot;&amp;gt;
  I continue to be editable

  &amp;lt;div contenteditable=&amp;quot;false&amp;quot;&amp;gt;
    But I should be uneditable, and on mobile won&apos;t even trigger a keyboard
    popup
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;div class=&amp;quot;demo-editable&amp;quot; contenteditable=&amp;quot;true&amp;quot;&amp;gt;
I continue to be editable&lt;/p&gt;
&lt;p&gt;&amp;lt;div  class=&amp;quot;demo-uneditable&amp;quot; contenteditable=&amp;quot;false&amp;quot;&amp;gt;
But I should be uneditable, and on mobile won&apos;t even trigger a keyboard popup
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Expanding Bottom Navigation with CSS Transitions</title><link>https://nabeelvalley.co.za/blog/2022/13-11/svelte-expanding-nav/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/13-11/svelte-expanding-nav/</guid><description>A bottom navigation with expanding icons using CSS Transitions and Svelte</description><pubDate>Sun, 13 Nov 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So I was looking around on YouTube and came across a video about this library called &lt;code&gt;google_nav_bar&lt;/code&gt; for flutter and I really liked the idea of how it works and wanted to implement something similar in an app I&apos;ve been working on&lt;/p&gt;
&lt;p&gt;The basic functionality of the of the library can be seen on &lt;a href=&quot;https://pub.dev/packages/google_nav_bar&quot;&gt;&lt;code&gt;google_nav_bar&lt;/code&gt; package page&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I thought the main challenge of this would be implementing the fade-in of the text with the expanding content section, I took a first shot with the result below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;script&amp;gt;

	let selected = &apos;home&apos;;

	let items = [&apos;home&apos;, &apos;search&apos;, &apos;archive&apos;, &apos;settings&apos;];
	let colors = {
		home: &apos;lightpink&apos;,
		search: &apos;violet&apos;,
		archive: &apos;skyblue&apos;,
		settings: &apos;lightgrey&apos;
	};
&amp;lt;/script&amp;gt;

&amp;lt;svelte:head&amp;gt;
	&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://unpkg.com/mono-icons@1.0.5/iconfont/icons.css&amp;quot; /&amp;gt;
&amp;lt;/svelte:head&amp;gt;

&amp;lt;nav class=&amp;quot;wrapper&amp;quot;&amp;gt;
	&amp;lt;ul class=&amp;quot;list&amp;quot;&amp;gt;
		{#each items as item (item)}
			&amp;lt;li class=&amp;quot;item&amp;quot; class:selected={selected === item} on:click={() =&amp;gt; (selected = item)}&amp;gt;
				&amp;lt;div class=&amp;quot;icon&amp;quot; style={`--bg: ${colors[item]}`}&amp;gt;
					&amp;lt;i class={`mi mi-${item}`} /&amp;gt;
				&amp;lt;/div&amp;gt;
				&amp;lt;div class=&amp;quot;text&amp;quot;&amp;gt;
					{item}
				&amp;lt;/div&amp;gt;
			&amp;lt;/li&amp;gt;
		{/each}
	&amp;lt;/ul&amp;gt;
&amp;lt;/nav&amp;gt;

&amp;lt;style&amp;gt;
	.mi {
		font-size: 24px;
	}

	.wrapper {
		display: flex;
		width: 100%;
	}

	.list {
		flex: 1;
		display: flex;
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		padding: 10px 20px;
	}

	.item {
		display: flex;
		flex-direction: row;
		align-items: center;
		gap: 8px;
		justify-content: flex-start;
	}

	.item .text {
		width: 0px;
		opacity: 0;
		overflow: hidden;
		transition: width 0.15s 0s, opacity 0.15s 0s;
	}

	.item.selected .text {
		width: 100px;
		opacity: 1;
		transition: width 0.15s 0s, opacity 0.15s 0.075s;
	}

	.icon {
		display: flex;
		align-items: center;
		justify-content: center;
		color: var(--bg);
		line-height: 0;
	}

	/* resets	 */
	ul {
		padding: 0;
		margin: 0;
	}

	li {
		margin: 0;
		list-style: none;
	}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I like the overall feel and I think the finicky bits of using the transition are done, but I&apos;d still like to play around a bit more to see how close to the original library I can get it&lt;/p&gt;
&lt;p&gt;For now though, here&apos;s the REPL with the current working state of the component:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/ExpandingBottomNavItems?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Education App Design Ideas</title><link>https://nabeelvalley.co.za/blog/2022/27-09/open-education-app/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/27-09/open-education-app/</guid><description>Some design snips for a learning app</description><pubDate>Tue, 27 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;General App Overview&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/27-09/image1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Content Creation and Editing Experience&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/27-09/image3.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Alternate Themes&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2022/27-09/image2.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
</content:encoded></item><item><title>Read Metadata from Images using Rust</title><link>https://nabeelvalley.co.za/blog/2022/25-08/read-image-metadata/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/25-08/read-image-metadata/</guid><description>Using Rust to parse EXIF metadata from image files</description><pubDate>Thu, 25 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;The complete Rust code discussed in this post can be found in the &lt;a href=&quot;https://github.com/nabeelvalley/exiflib&quot;&gt;exiflib GitHub repo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Image files, such as JPEG, PNG, and RAW formats from digital cameras and software, contain metadata about the image. This metadata can contain information ranging from the make and model of the camera used to the specific shooting conditions under which a picture was taken&lt;/p&gt;
&lt;p&gt;Reading this data depends on the image format used. This post looks at specifically reading metadata from images that use the Exchangeable Image File Format (EXIF) for storing metadata&lt;/p&gt;
&lt;h2&gt;The Rust Programming Language&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust programming language&lt;/a&gt; is used to read and process the image files. Rust is a general-purpose programming language with an emphasis on performance and type safety&lt;/p&gt;
&lt;p&gt;While this post doesn&apos;t cover the specifics of programming in Rust, any code samples are accompanied by a description of what the code does but it&apos;s useful to have a basic understanding of programming for understanding exactly what the code is doing&lt;/p&gt;
&lt;p&gt;It&apos;s also worth noting that this post covers a lot of bit-level processing of image files, to get a basic understanding of binary data works take a look at the previous post on &lt;a href=&quot;../20-08/understanding-binary-files&quot;&gt;Understanding Binary File Formats&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Exchangeable Image File Format (EXIF)&lt;/h2&gt;
&lt;p&gt;The Exchangeable Image File Format (EXIF) is based on the Tag Image File Format (TIFF) specification for storing metadata. This data is organised into Image File Directories (IFDs) within an image file&lt;/p&gt;
&lt;p&gt;The EXIF section in an image file is structured as follows:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;Subsection&lt;/th&gt;
&lt;th&gt;Number of Bytes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Header&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;EXIF Marker (Exif00)&lt;/td&gt;
&lt;td&gt;6 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IFD&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Byte Order (II or MM)&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Magic Number (42)&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Data Start Location&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Data Count&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Data Entries&lt;/td&gt;
&lt;td&gt;Data Count x 12 bytes/entry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Additional Data Section&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&gt;Reading EXIF Data&lt;/h2&gt;
&lt;p&gt;Reading EXIF data is done by reading the bytes in the file. The following examples will use a JPEG from a Fujifilm X-T200 as a reference, though the same concepts can be applied to understanding data from any file format that stores metadata using the EXIF structure&lt;/p&gt;
&lt;h3&gt;Under the Hood of an Image File&lt;/h3&gt;
&lt;p&gt;Below is a snippet of the Hex data for a JPEG file alongside the bytes decoded as text:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hex Data                                           Decoded Text                       Approximate EXIF Subsections

FF D8 FF E1 57 FE 45 78 69 66 00 00 49 49 2A 00    . . . . W . E x i f . . I I * .    Header, Byte Order, Magic Number
08 00 00 00 0C 00 0F 01 02 00 09 00 00 00 9E 00    . . . . . . . . . . . . . . . .    Data Count, Data Start Location
00 00 10 01 02 00 07 00 00 00 A8 00 00 00 12 01    . . . . . . . . . . . . . . . .    |
03 00 01 00 00 00 01 00 00 00 1A 01 05 00 01 00    . . . . . . . . . . . . . . . .    |
00 00 B0 00 00 00 1B 01 05 00 01 00 00 00 B8 00    . . . . . . . . . . . . . . . .    | Data Entries
00 00 28 01 03 00 01 00 00 00 02 00 00 00 31 01    . . ( . . . . . . . . . . . 1 .    |
02 00 1E 00 00 00 C0 00 00 00 32 01 02 00 14 00    . . . . . . . . . . 2 . . . . .    |_
00 00 DE 00 00 00 13 02 03 00 01 00 00 00 02 00    . . . . . . . . . . . . . . . .    |
00 00 98 82 02 00 05 00 00 00 F2 00 00 00 69 87    . . . . . . . . . . . . . . i .    |
04 00 01 00 00 00 14 01 00 00 A5 C4 07 00 1C 00    . . . . . . . . . . . . . . . .    | Additional Data Section
00 00 F8 00 00 00 EC 29 00 00 46 55 4A 49 46 49    . . . . . . . ) . . F U J I F I    |
4C 4D 00 00 58 2D 54 32 30 30 00 00 48 00 00 00    L M . . X - T 2 0 0 . . H . . .    |
01 00 00 00 48 00 00 00 01 00 00 00 44 69 67 69    . . . . H . . . . . . . D i g i    |
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above snippet shows the hex data, in here the EXIF marker can be found on the first line - &lt;code&gt;45 78 69 66 00 00&lt;/code&gt; which decodes to &lt;code&gt;EXIF\0\&lt;/code&gt;, followed by the byte order &lt;code&gt;49 49&lt;/code&gt; - &lt;code&gt;II&lt;/code&gt; which means that the byte order for the file is Little Endian - which means that the smallest value in a sequence is the first byte - this can be used to decode &lt;code&gt;2A 00&lt;/code&gt; to &lt;code&gt;42&lt;/code&gt; if the byte order was Big endian the bytes representing &lt;code&gt;42&lt;/code&gt; would be flipped&lt;/p&gt;
&lt;p&gt;The byte order section is the most important thing to note on this first line as it tells an application how to read the data in the IFD as well as it is what any byte offsets should be calculated relative to&lt;/p&gt;
&lt;p&gt;Additionally, the data entries section and the additional data section are broadly marked off, to understand where data is located in this file&lt;/p&gt;
&lt;h3&gt;Reading a File as Bytes&lt;/h3&gt;
&lt;p&gt;Rust provides a method for reading a file in the standard library is &lt;code&gt;fs::read&lt;/code&gt; which can be used by providing it with a path to the file to read, the code for this looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let file = fs::read(&amp;quot;./sample.jpg&amp;quot;).unwrap();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.unwrap()&lt;/code&gt; at the end tells rust to either get the file data or exit the program with an error if it could not read the file&lt;/p&gt;
&lt;p&gt;The result of this is a &lt;code&gt;Vec[u8]&lt;/code&gt; which means a vector (or list) of bytes - the bytes in the list are represented as integer values between 0 and 255, these are equivalent to the hex values in the snippet above&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;file&lt;/code&gt; is what is used to read the bytes from and will be the data source for reading the EXIF data&lt;/p&gt;
&lt;h3&gt;Finding the EXIF Starting Point&lt;/h3&gt;
&lt;p&gt;To find the starting point of the EXIF data we can scan through the file until we find the &lt;code&gt;Exif\0\0&lt;/code&gt; pattern, a function can be defined for searching for a pattern in a list of bytes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;pub fn get_sequence_range(bytes: &amp;amp;[u8], pattern: &amp;amp;[u8]) -&amp;gt; Option&amp;lt;Range&amp;lt;usize&amp;gt;&amp;gt; {
    let start = bytes
        .windows(pattern.len())
        .position(|window| window == pattern)?;

    let end = start + pattern.len();

    Some(start..end)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function above called &lt;code&gt;get_sequence_range&lt;/code&gt; searches the &lt;code&gt;bytes&lt;/code&gt; for a &lt;code&gt;pattern&lt;/code&gt;. This uses the &lt;code&gt;windows&lt;/code&gt; function in rust which creates a bunch of smaller lists and finds the &lt;code&gt;position&lt;/code&gt; where the &lt;code&gt;window&lt;/code&gt;, which is a section of bytes that&apos;s the same length as the search &lt;code&gt;pattern&lt;/code&gt; and checks if the value is equal to the &lt;code&gt;pattern&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If the pattern can be found, then the function will return a range (basically, a start and end point) that goes from the &lt;code&gt;start&lt;/code&gt; of the found pattern until the &lt;code&gt;end&lt;/code&gt; of the pattern, which is simply the &lt;code&gt;start&lt;/code&gt; value plus the length of the pattern&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Option&lt;/code&gt; indicates that the function returns either a value if it finds one (denoted by &lt;code&gt;Some&lt;/code&gt;) or will return nothing if no value is found, denoted by &lt;code&gt;None&lt;/code&gt;. The above function uses the shorthand for the &lt;code&gt;None&lt;/code&gt; case which is done by placing a &lt;code&gt;?&lt;/code&gt; at the end of the check for the pattern - which will cause the function to end early if it could not find the pattern&lt;/p&gt;
&lt;p&gt;The above function for finding the starting point can be used by passing it the file&apos;s bytes like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;const EXIF_MARKER: &amp;amp;[u8] = &amp;quot;Exif\0\0&amp;quot;.as_bytes();

let exif_range = get_sequence_range(file, EXIF_MARKER)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that in the above function the &lt;code&gt;EXIF_MARKER&lt;/code&gt; is defined as the &lt;code&gt;Exif\0\0&lt;/code&gt; text converted to bytes, this is passed as the search pattern to the &lt;code&gt;get_sequence_range&lt;/code&gt; function. This gets the EXIF header location which is used to find the Byte order (Endian) marker&lt;/p&gt;
&lt;h3&gt;Getting the Byte Order&lt;/h3&gt;
&lt;p&gt;Once we know the location of the EXIF marker, the byte order values go from the 6th and 7th byte after the start of the marker. Since this is done using a range, this means that the range goes from 6 to 8, since the end value is not included in the range, this can be see defined below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;const ENDIAN_RANGE_FROM_EXIF_MARKER: Range&amp;lt;usize&amp;gt; = 6..8;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bytes for the endian value can be found relative to the &lt;code&gt;exif_range&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let start = exif_range.start + ENDIAN_RANGE_FROM_EXIF_MARKER.start;

let bytes = file.get(start..)?;
let endian_bytes = bytes.get(0..2)?;
let endian = get_endian(endian_bytes)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above makes use of a &lt;code&gt;get_endian&lt;/code&gt; function to get the byte order which can be defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;fn get_endian(endian_bytes: &amp;amp;[u8]) -&amp;gt; Option&amp;lt;Endian&amp;gt; {
    let endian = parsing::full_bytes_string(endian_bytes)?;

    match endian.as_str() {
        &amp;quot;MM&amp;quot; =&amp;gt; Some(Endian::Big),
        &amp;quot;II&amp;quot; =&amp;gt; Some(Endian::Little),
        _ =&amp;gt; None,
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above function takes the bytes which start at the endian location and converts them to a string (text) value&lt;/p&gt;
&lt;p&gt;These values are then compared using a &lt;code&gt;match&lt;/code&gt;. If it is &lt;code&gt;II&lt;/code&gt; or &lt;code&gt;MM&lt;/code&gt; the function returns Big Endian (&lt;code&gt;Endian::Big&lt;/code&gt;) or Little Endian (&lt;code&gt;Endian::Little&lt;/code&gt;) respectively. If no matching value is found, then &lt;code&gt;None&lt;/code&gt; is returned instead&lt;/p&gt;
&lt;p&gt;The code above also finds the &lt;code&gt;bytes&lt;/code&gt;, which defines the file&apos;s bytes but trims off all the bytes that are before the endian marker - this is important since any data in the IFD needs to be read relative to the this location&lt;/p&gt;
&lt;p&gt;Following the Endian bytes are 2 bytes which specify the Magic Number (42) as mentioned above - this can also be checked to verify the byte order of the file but is not covered in this post&lt;/p&gt;
&lt;h3&gt;Getting the IFD Data Start Location and Count&lt;/h3&gt;
&lt;p&gt;Immediately after the Magic Number is four bytes that specify where the IFD data starts, in the snippet above, these bytes are &lt;code&gt;08 00 00 00&lt;/code&gt; which convert to the value of &lt;code&gt;8&lt;/code&gt;, this informs us that the IFD data starts from 8 bytes from the Endian marker&lt;/p&gt;
&lt;p&gt;By following the offset value, the number of entries in the IFD can be found at the 8 bytes from the Endian marker, in this case, bytes &lt;code&gt;0C 00&lt;/code&gt; which convert to the value of &lt;code&gt;12&lt;/code&gt;, which indicates that there are 12 entries in the IFD&lt;/p&gt;
&lt;p&gt;The code applying the above logic can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let ifd0_offset = get_ifd_offset(&amp;amp;endian, ifd)? as usize;
let ifd0_entry_offset = ifd0_offset + 2;

let ifd0_count = u16::from_offset_endian_bytes(&amp;amp;endian, ifd, ifd0_offset)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function which gets the &lt;code&gt;ifd0_offset&lt;/code&gt; does the lookup of bytes from the range 4 to 8, relative to the Endian marker&lt;/p&gt;
&lt;h3&gt;Reading Entries in the IFD&lt;/h3&gt;
&lt;p&gt;As a reference example, the bytes for the first entry in the IFD above will be used to understand the data and how it&apos;s stored&lt;/p&gt;
&lt;p&gt;After the bytes indicate the count, the next section consists of the entries. Each entry consists of 12 bytes and is structured like so:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Data Format&lt;/th&gt;
&lt;th&gt;Component Length&lt;/th&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;2 Bytes&lt;/td&gt;
&lt;td&gt;4 Bytes&lt;/td&gt;
&lt;td&gt;4 Bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0F 01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;02 00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;09 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;9E 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;The Tag is an identifier that specifies what the value of the entry represents&lt;/li&gt;
&lt;li&gt;The Data format states how the data should be read&lt;/li&gt;
&lt;li&gt;The Component Length states how many bytes the data for the entry consists of&lt;/li&gt;
&lt;li&gt;The data can either be the actual data, or a value that gives the offset to the data, depending on the Component Lenght&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Tag ID&lt;/h4&gt;
&lt;p&gt;Reading the Tag is done by parsing the first two bytes of an entry - This converts the value into a 16-bit unsigned integer (a positive integer)&lt;/p&gt;
&lt;p&gt;The TagID is read like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let tag = u16::from_endian_bytes(endian, entry)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value of the tag is a 16-bit unsigned integer, but it&apos;s more commonly represented as Hex value in the tag lookup tables, a lookup table for these can be found at the &lt;a href=&quot;https://exiftool.org/TagNames/EXIF.html&quot;&gt;EXIF Tool Tag Names Doc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The value of the tag above &lt;code&gt;0F 01&lt;/code&gt; can be converted to hex for the Little Endian notation resulting in &lt;code&gt;0x010F&lt;/code&gt;, the lookup table states that this tag identifies the &lt;code&gt;Make&lt;/code&gt; property in the Exif data&lt;/p&gt;
&lt;h4&gt;Data Format&lt;/h4&gt;
&lt;p&gt;The data stored in an entry can be of 12 different formats, each of these associated with a format value - the format value can be read by reading from byte index 2 in the entry, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let format_value = u16::from_offset_endian_bytes(endian, entry, 2)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The format value is a 16-bit unsigned integer, the same as the Tag, though this is used as an integer value and not hex. Each integer value maps to a specific format type, as seen in the below table:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Format Value&lt;/th&gt;
&lt;th&gt;Format&lt;/th&gt;
&lt;th&gt;Bytes per Component&lt;/th&gt;
&lt;th&gt;Data Type&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Unsigned Byte&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;u8&lt;/td&gt;
&lt;td&gt;8-bit positive integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;ASCII String&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Text/String value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Unsigned Short&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;u16&lt;/td&gt;
&lt;td&gt;16-bit positive integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Unsigned Long&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;u32&lt;/td&gt;
&lt;td&gt;32-bit positive integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Unsigned Rational&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;u32, u32&lt;/td&gt;
&lt;td&gt;positive fraction - numerator and denominator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Signed Byte&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;i8&lt;/td&gt;
&lt;td&gt;8-bit integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Undefined&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;[u8]&lt;/td&gt;
&lt;td&gt;list of bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Signed Short&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;i16&lt;/td&gt;
&lt;td&gt;16-bit integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Signed Long&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;i32&lt;/td&gt;
&lt;td&gt;32-bit integer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Signed Rational&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;i32, i32&lt;/td&gt;
&lt;td&gt;fraction value - numerator and denominator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Single Float&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;f32&lt;/td&gt;
&lt;td&gt;floating point/decimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Double Float&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;f64&lt;/td&gt;
&lt;td&gt;double precision floating point&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The above table is implemented in code by first defining a type that states all the possible format types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;pub enum TagFormat {
    UnsignedByte,
    AsciiString,
    UnsignedShort,
    UnsignedLong,
    UnsignedRational,
    SignedByte,
    Undefined,
    SignedShort,
    SignedLong,
    SignedRational,
    SingleFloat,
    DoubleFloat,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each type of value can also be described in terms of the data type it stores as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;pub enum ExifValue&amp;lt;&apos;a&amp;gt; {
    UnsignedByte(u8),
    AsciiString(String),
    UnsignedShort(u16),
    UnsignedLong(u32),
    UnsignedRational(u32, u32),
    SignedByte(i8),
    Undefined(&amp;amp;&apos;a [u8]),
    SignedShort(i16),
    SignedLong(i32),
    SignedRational(i32, i32),
    SingleFloat(f32),
    DoubleFloat(f64),
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thereafter, a function to go from the given Format Value to the type of the tag being used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;fn get_tag_format(value: &amp;amp;u16) -&amp;gt; Option&amp;lt;TagFormat&amp;gt; {
    match value {
        1 =&amp;gt; Some(TagFormat::UnsignedByte),
        2 =&amp;gt; Some(TagFormat::AsciiString),
        3 =&amp;gt; Some(TagFormat::UnsignedShort),
        4 =&amp;gt; Some(TagFormat::UnsignedLong),
        5 =&amp;gt; Some(TagFormat::UnsignedRational),
        6 =&amp;gt; Some(TagFormat::SignedByte),
        7 =&amp;gt; Some(TagFormat::Undefined),
        8 =&amp;gt; Some(TagFormat::SignedShort),
        9 =&amp;gt; Some(TagFormat::SignedLong),
        10 =&amp;gt; Some(TagFormat::SignedRational),
        11 =&amp;gt; Some(TagFormat::SingleFloat),
        12 =&amp;gt; Some(TagFormat::DoubleFloat),
        _ =&amp;gt; None,
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As done previously, if the correct value can&apos;t be found, the function returns &lt;code&gt;None&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;So, adding to the above code, the code for reading the tag value is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let format_value = u16::from_offset_endian_bytes(endian, entry, 2)?;
let format = get_tag_format(&amp;amp;format_value)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Component Length&lt;/h4&gt;
&lt;p&gt;The Component length specifies the number of components for the tag format being read - for most tag formats this will be 1, however, for specific values like &lt;code&gt;AsciiString&lt;/code&gt; or &lt;code&gt;Undefined&lt;/code&gt;, this may be different in which case it specifies the length of the string or how many bytes are required respectively&lt;/p&gt;
&lt;p&gt;The value for the component length can be found by reading the relevant bytes in the entry and converting them to a 32-bit unsigned integer, starting from byte index 4, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let component_length = u32::from_offset_endian_bytes(endian, entry, 4)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Data&lt;/h4&gt;
&lt;p&gt;Once the component length is known, getting the total length of the data to be read is done by multiplying the component length by the bytes per component - since different components need different amounts of data&lt;/p&gt;
&lt;p&gt;A function that gets the bytes per component for a given tag format can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;fn get_bytes_per_component(format: &amp;amp;TagFormat) -&amp;gt; u32 {
    match format {
        TagFormat::UnsignedByte =&amp;gt; 1,
        TagFormat::AsciiString =&amp;gt; 1,
        TagFormat::UnsignedShort =&amp;gt; 2,
        TagFormat::UnsignedLong =&amp;gt; 4,
        TagFormat::UnsignedRational =&amp;gt; 8,
        TagFormat::SignedByte =&amp;gt; 1,
        TagFormat::Undefined =&amp;gt; 1,
        TagFormat::SignedShort =&amp;gt; 2,
        TagFormat::SignedLong =&amp;gt; 4,
        TagFormat::SignedRational =&amp;gt; 8,
        TagFormat::SingleFloat =&amp;gt; 4,
        TagFormat::DoubleFloat =&amp;gt; 8,
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is based on the table shown previously on component formats&lt;/p&gt;
&lt;p&gt;Next, the total length can be defined as the component length multiplied by the bytes per component which can be seen in the code below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let component_length = u32::from_offset_endian_bytes(endian, entry, 4)?;

let bytes_per_component = get_bytes_per_component(&amp;amp;format);

let total_length = component_length * bytes_per_component;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The data can be read from the data bytes, which start at index 8 of the entry&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let data = entry.get(8..12)?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The data value must be the raw bytes because depending on the resulting length it needs to be processed differently&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;total_length&lt;/code&gt; is less than or equal to 4, the data can be read directly from the data bytes, this can be done using a function that converts a &lt;code&gt;TagFormat&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt; to the relevant value as defined in the table:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;fn parse_tag_value&amp;lt;&apos;a&amp;gt;(
    format: &amp;amp;TagFormat,
    endian: &amp;amp;&apos;a Endian,
    bytes: &amp;amp;&apos;a [u8],
) -&amp;gt; Option&amp;lt;ExifValue&amp;lt;&apos;a&amp;gt;&amp;gt; {
    match format {
        TagFormat::UnsignedByte =&amp;gt; parsing::bytes_to_unsigned_byte(endian, bytes),
        TagFormat::AsciiString =&amp;gt; parsing::bytes_to_ascii_string(bytes),
        TagFormat::UnsignedShort =&amp;gt; parsing::bytes_to_unsigned_short(endian, bytes),
        TagFormat::UnsignedLong =&amp;gt; parsing::bytes_to_unsigned_long(endian, bytes),
        TagFormat::UnsignedRational =&amp;gt; parsing::bytes_to_unsigned_rational(endian, bytes),
        TagFormat::SignedByte =&amp;gt; parsing::bytes_to_signed_byte(endian, bytes),
        TagFormat::Undefined =&amp;gt; parsing::bytes_to_undefined(bytes),
        TagFormat::SignedShort =&amp;gt; parsing::bytes_to_signed_short(endian, bytes),
        TagFormat::SignedLong =&amp;gt; parsing::bytes_to_signed_long(endian, bytes),
        TagFormat::SignedRational =&amp;gt; parsing::bytes_to_signed_rational(endian, bytes),
        TagFormat::SingleFloat =&amp;gt; parsing::bytes_to_single_float(endian, bytes),
        TagFormat::DoubleFloat =&amp;gt; parsing::bytes_to_double_float(endian, bytes),
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the data value can be obtained using the function above like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;let value = parse_tag_value(&amp;amp;format, endian, data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, if the &lt;code&gt;total_length&lt;/code&gt; is greater than 4, the data value needs to be read as an offset from the IFD which is then converted, again, using the &lt;code&gt;parse_tag_value&lt;/code&gt; function above&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rs&quot;&gt;// the value needs to be checked at the offset and used from there
let offset = u32::from_endian_bytes(endian, data)?;

let start = (offset) as usize;
let end = start + (length) as usize;

let range = start..end;

let value_bytes = bytes.get(range)?;

let result = parse_tag_value(&amp;amp;format, endian, value_bytes)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting all the above together, reading the tag above will give:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Data Format&lt;/th&gt;
&lt;th&gt;Component Length&lt;/th&gt;
&lt;th&gt;Data&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;2 Bytes&lt;/td&gt;
&lt;td&gt;4 Bytes&lt;/td&gt;
&lt;td&gt;4 Bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0F 01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;02 00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;09 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;9E 00 00 00&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x010f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ASCII String&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;FUJIFILM\0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;Reading Additional Entries&lt;/h4&gt;
&lt;p&gt;Once a single entry can be read - reading additional entries follows the same pattern. Since the bytes per entry is fixed - always 12 - and the number of entries is known from the IFD count, each entry can be iterated over by going 12 bytes at a time and reading their data individually. A more detailed implementation of this as well as the rest of the code can be found on the &lt;a href=&quot;https://github.com/nabeelvalley/exiflib&quot;&gt;exiflib GitHub repo&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This post provides a basic outline on reading EXIF data from an image, as well as covers the byte structure for reading EXIF entries from an image file. There&apos;s a lot more to reading EXIF data from images, but at a high level the parsing covered here should form a basic grounding in how reading this data works&lt;/p&gt;
&lt;p&gt;For further reference and inspiration take a look a the reference list at the end of this post as well as the &lt;a href=&quot;https://github.com/nabeelvalley/exiflib&quot;&gt;exiflib GitHub repo&lt;/a&gt; mentioned previously&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;Implementation details and guidance for reading metadata from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://exiftool.org/TagNames/EXIF.html&quot;&gt;EXIF Tool Tag Names&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://exif-viewer.com/&quot;&gt;EXIF Viewer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://greybeard.org.uk/exif3/&quot;&gt;Fujifilm EXIF Viewer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://people.cs.umass.edu/~liberato/courses/2018-spring-compsci365+590f/lecture-notes/05-bit-twiddling-file-formats-parsing-exif/&quot;&gt;COMPSCI 365/590F - Bit Twiddling File Formats, Parsing EXIF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.media.mit.edu/pia/Research/deepview/exif.html&quot;&gt;Description of Exif file format (MIT Media)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://gvsoft.no-ip.org/exif/exif-explanation.html#ExifIFDTags&quot;&gt;Exif Explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://web.archive.org/web/20131019050323/http://www.exif.org/specifications.html&quot;&gt;Exif Specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20190624045241if_/http://www.cipa.jp:80/std/documents/e/DC-008-Translation-2019-E.pdf&quot;&gt;TIFF Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some reference implementations and libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.rs/rawloader/latest/rawloader/index.html&quot;&gt;rawloader docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://libopenraw.freedesktop.org/&quot;&gt;libopenraw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.rs/image/0.5.4/image/index.html&quot;&gt;rust image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Binary Data and File Formats</title><link>https://nabeelvalley.co.za/blog/2022/20-08/understanding-binary-files/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/20-08/understanding-binary-files/</guid><description>An introduction to bits, bytes, and binary file formats</description><pubDate>Sat, 20 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Computers work with data stored in binary formats. Reading and interpreting binary data is an important part of understanding file formats so their data can be read and interpreted&lt;/p&gt;
&lt;h2&gt;Bits and Bytes, and Binary&lt;/h2&gt;
&lt;p&gt;Binary files store data using bits&lt;/p&gt;
&lt;p&gt;A bit can be either a 1 or 0. When working with bit-data, it&apos;s useful to group them into sets of 8, known as bytes&lt;/p&gt;
&lt;p&gt;A byte is a sequence of 8-bits which can contain a value ranging from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;255&lt;/code&gt; - these are referred to as the decimal representation&lt;/p&gt;
&lt;p&gt;Bytes consist of 8-bit, with each position representing a power of 2 from 2^0 to 2^7, as seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 0 0 0 0 0
| | | | | | | |
| | | | | | | |__ 2^0 - 0 or 1
| | | | | | |____ 2^1 - 0 or 2
| | | | | |______ 2^2 - 0 or 4
| | | | |________ 2^3 - 0 or 8
| | | |__________ 2^4 - 0 or 16
| | |____________ 2^5 - 0 or 32
| |______________ 2^6 - 0 or 64
|________________ 2^7 - 0 or 128

total:                  0 to 255
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The byte above represents the value for 0, this is because all the bits have a value of 0&lt;/p&gt;
&lt;p&gt;Using the above explanation, the number 1 is represented using the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 0 0 0 0 1
| | | | | | | |
| | | | | | | |__ 2^0 - 1
| | | | | | |____ 2^1 - 0
| | | | | |______ 2^2 - 0
| | | | |________ 2^3 - 0
| | | |__________ 2^4 - 0
| | |____________ 2^5 - 0
| |______________ 2^6 - 0
|________________ 2^7 - 0

total:                  1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where the position for 2^0 is the only bit with a value (1)&lt;/p&gt;
&lt;p&gt;Similarly, 2 is represented as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 0 0 0 2 0
| | | | | | | |
| | | | | | | |__ 2^0 - 0
| | | | | | |____ 2^1 - 2
| | | | | |______ 2^2 - 0
| | | | |________ 2^3 - 0
| | | |__________ 2^4 - 0
| | |____________ 2^5 - 0
| |______________ 2^6 - 0
|________________ 2^7 - 0

total:                  2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where the bit for 2^1 has a value&lt;/p&gt;
&lt;p&gt;Or the number 5 with bits 2^0 and 2^2 having a value:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 0 0 1 0 1
| | | | | | | |
| | | | | | | |__ 2^0 - 1
| | | | | | |____ 2^1 - 0
| | | | | |______ 2^2 - 4
| | | | |________ 2^3 - 0
| | | |__________ 2^4 - 0
| | |____________ 2^5 - 0
| |______________ 2^6 - 0
|________________ 2^7 - 0

total:                  5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is calculated by adding 2^0 + 2^2 = 1 + 4 = 5&lt;/p&gt;
&lt;p&gt;A larger number, like 234 is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1 1 1 0 1 0 1 0
| | | | | | | |
| | | | | | | |__ 2^0 - 0
| | | | | | |____ 2^1 - 2
| | | | | |______ 2^2 - 0
| | | | |________ 2^3 - 8
| | | |__________ 2^4 - 0
| | |____________ 2^5 - 32
| |______________ 2^6 - 64
|________________ 2^7 - 128

total:                  234
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The calculation for the above value is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2^1 + 2^3 + 2^5 + 2^6 + 2^7 = total = 234
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When substituting the powers of 2:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2 + 8 + 32 + 64 + 128 = total = 234
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The numbers discussed above are all 1-byte (8-bit) numbers, which have a range between 0 and 255, adding bits to the value will allow the representation of bigger numbers, for example, a 2-byte (16-bit) number can have a value from 0 to 65,535&lt;/p&gt;
&lt;h2&gt;Hexadecimal (Hex)&lt;/h2&gt;
&lt;p&gt;In the above example, numbers are represented in binary format (e.g. &lt;code&gt;000000020&lt;/code&gt;), or decimal format (e.g. 2)&lt;/p&gt;
&lt;p&gt;When looking at binary data, it can be a bit easier to navigate around by representing data in hexadecimal (hex) format - which represents every 4 bits as a value ranging from 0-15, so, similar to the byte example above, but instead using 4-bits:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 0 0 0
| | | |
| | | |__ 2^0 - 0 or 1
| | |____ 2^1 - 0 or 2
| |______ 2^2 - 0 or 4
|________ 2^3 - 0 or 8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using what&apos;s already been discussed, the number 12 can be represented in bits as &lt;code&gt;1100&lt;/code&gt;,&lt;/p&gt;
&lt;p&gt;Hex numbers additionally convert each of these values into a value from 0-9 or A-F, as seen in the following table:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decimal&lt;/th&gt;
&lt;th&gt;Bits&lt;/th&gt;
&lt;th&gt;Hex&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0010&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0011&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0100&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0101&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0110&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;6&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0111&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;7&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;8&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;9&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1010&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;A&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1011&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;B&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1100&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;C&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1101&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;D&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1110&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;E&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1111&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;F&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Using the binary representation, a byte can be represented using 2 Hex values which are taken by using the first 4-bits as the first hex value, and the second 4-bits as the second hex value&lt;/p&gt;
&lt;p&gt;For example, the value for 234, represented as bits: &lt;code&gt;11101010&lt;/code&gt; can be split into 2 sets of 4-bits &lt;code&gt;1110 1010&lt;/code&gt;, using the table above, this becomes &lt;code&gt;EA&lt;/code&gt; in hex&lt;/p&gt;
&lt;h3&gt;Binary Files&lt;/h3&gt;
&lt;p&gt;Binary files encode data using bits, when viewing them, it&apos;s convenient to view the data in them using bytes represented as hex values as was shown above&lt;/p&gt;
&lt;p&gt;Binary files usually require some knowledge of how their data is structured to correctly interpret the information. This is usually described in the specification for the file format&lt;/p&gt;
&lt;h2&gt;Text Files&lt;/h2&gt;
&lt;p&gt;Plain text files are usually in the UTF-8 or UTF-16 format - this means that they use 8-bits or 16-bits to represent each character, but there are lots of other formats that a text file can use&lt;/p&gt;
&lt;p&gt;UTF-8 data can be read by converting the binary data to text data using a table which maps the byte/hex value to the character -for the UTF-8 format, the character &amp;quot;A&amp;quot; is encoded in hex as &lt;code&gt;41&lt;/code&gt; and &amp;quot;z&amp;quot; is &lt;code&gt;7a&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The Hexadecimal representation for a text file that contains the following UTF-8 data:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Hello World!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Would be stored as a binary file which contains:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;48 65 6C 6C 6F 20 57 6F 72 6C 64 21
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting the hex below the text content, the hex to character mapping can be seen:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;H  e  l  l  o     W  o  r  l  d  !
48 65 6C 6C 6F 20 57 6F 72 6C 64 21
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Binary files can be viewed in a hex editor to see the raw binary data, but interpreting these files depends on the format used and will differ between file formats&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Computers store data using bits. Bits can be structured into sets of 8-bits, called a byte&lt;/p&gt;
&lt;p&gt;Data can be represented using bits, bytes, decimal values, or hexadecimal values&lt;/p&gt;
&lt;p&gt;Files store data using binary. Binary data can be represented as decimal or hex depending and can be viewed as whichever is appropriate&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=bin&quot;&gt;UTF-8 Character Table&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hexed.it/&quot;&gt;HexEdit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cs.cmu.edu/~fgandon/documents/lecture/uk1999/binary/HandOut.pdf&quot;&gt;Bits, Bytes, and Binary Summary&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Using React.memo for Controlling Component Rendering</title><link>https://nabeelvalley.co.za/blog/2022/16-08/react-memo-top-level-api/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/16-08/react-memo-top-level-api/</guid><description>Using the react top-level API for debouncing and selectively rendering a component for better performance</description><pubDate>Tue, 16 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;React Top Level API&lt;/h2&gt;
&lt;p&gt;The React library contains some functions at it&apos;s top level scope. Amongst these are the built-in hooks (like &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useCallback&lt;/code&gt;, etc.) as well as some other functions for manipulating React Elements directly - which I&apos;ve covered in a previous post on &lt;a href=&quot;../01-03/react-top-level-api.md&quot;&gt;The React Top Level API&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Component Rendering&lt;/h2&gt;
&lt;p&gt;By default, React will trigger a component render whenever there is a change to its &lt;code&gt;state&lt;/code&gt; or &lt;code&gt;props&lt;/code&gt;. &lt;code&gt;React.memo&lt;/code&gt; allows us to take control of the &lt;code&gt;props&lt;/code&gt; triggered render by giving us a way to look into the prop-change process&lt;/p&gt;
&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt; is a higher order component (HOC) that allows us to wrap a component and control whether or not it is updated/re-rendered by defining a function that tells react whether or not it&apos;s props are different - and effectively whether this should trigger a new render&lt;/p&gt;
&lt;p&gt;Doing the above is useful for complex components that don&apos;t necessarily need to be rendered every time their props are changed&lt;/p&gt;
&lt;h2&gt;API Definition&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactmemo&quot;&gt;The React Docs&lt;/a&gt; give us the following example for the &lt;code&gt;React.memo&lt;/code&gt; HOC:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const MyComponent = (props) =&amp;gt; {
  /* render using props */
}

const areEqual = (prevProps, nextProps) =&amp;gt; {
  /*
  return true if passing nextProps to render would return
  the same result as passing prevProps to render,
  otherwise return false
  */
}

const MyComponentMemo = React.memo(MyComponent, areEqual)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component &lt;code&gt;MyComponent&lt;/code&gt; will be rendered whenever props are changed, however, using &lt;code&gt;React.memo&lt;/code&gt; lets us define a function called &lt;code&gt;areEqual&lt;/code&gt; that we can can use to tell &lt;code&gt;React.memo&lt;/code&gt; whether or not the new props would render a different result to the old props&lt;/p&gt;
&lt;p&gt;We can then use &lt;code&gt;MyComponentMemo&lt;/code&gt; in place of &lt;code&gt;MyComponent&lt;/code&gt; to take control of when the component is rendered&lt;/p&gt;
&lt;h2&gt;Rendering On a Specific Type of Change&lt;/h2&gt;
&lt;p&gt;Say we have the specific component &lt;code&gt;TimeDisplay&lt;/code&gt; which shows the time that&apos;s being passed into it from &lt;code&gt;App&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import &apos;./App.css&apos;
import React, { useState, useEffect } from &apos;react&apos;

interface TimeDisplayProps {
  time: number
}

const TimeDisplay: React.FC&amp;lt;TimeDisplayProps&amp;gt; = ({ time }) =&amp;gt; {
  const display = new Date(time).toString()

  return &amp;lt;h1&amp;gt;{display}&amp;lt;/h1&amp;gt;
}

export default function App() {
  const [time, setTime] = useState(Date.now())

  useEffect(() =&amp;gt; {
    const handle = setInterval(() =&amp;gt; {
      setTime(Date.now())
    }, 100)

    return () =&amp;gt; {
      clearInterval(handle)
    }
  }, [])

  return (
    &amp;lt;main&amp;gt;
      &amp;lt;TimeDisplay time={time} /&amp;gt;
    &amp;lt;/main&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;TimeDisplay&lt;/code&gt; component in our case only displays time to the second, so any millisecond-level changes don&apos;t matter to the component and so we can save on those renders by checking if the difference in &lt;code&gt;time&lt;/code&gt; is similar to the previous render&apos;s &lt;code&gt;time&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s assume for our purpose that it&apos;s acceptable for the time to be delayed by about 5 seconds, we then can define a function called &lt;code&gt;areTimesWithinOneSecond&lt;/code&gt; which compares the next render&apos;s props with the previous and returns if they are within 5 seconds of each other:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const areTimesWithinFiveSeconds = (
  prev: TimeDisplayProps,
  next: TimeDisplayProps
): boolean =&amp;gt; {
  const diff = next.time - prev.time

  return diff &amp;lt; 5000
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use the above function in a &lt;code&gt;React.memo&lt;/code&gt; to define a version of the &lt;code&gt;TimeDisplay&lt;/code&gt; component which will prevent unnecessary renders:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const TimeDisplayMemo = React.memo(TimeDisplay, areTimesWithinFiveSeconds)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it can then be used as a drop-in replacement for the &lt;code&gt;TimeDisplay&lt;/code&gt; component:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;export default function App() {
  const [time, setTime] = useState(Date.now())

  useEffect(() =&amp;gt; {
    const handle = setInterval(() =&amp;gt; {
      setTime(Date.now())
    }, 100)

    return () =&amp;gt; {
      clearInterval(handle)
    }
  }, [])

  return (
    &amp;lt;main&amp;gt;
      &amp;lt;TimeDisplayMemo time={time} /&amp;gt;
    &amp;lt;/main&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;From the above implementation we can see that it&apos;s possible to delay rendering of a component using &lt;code&gt;React.memo&lt;/code&gt; if the component doesn&apos;t need to be re-rendered, hence improving performance by decreasing the number of renders react needs to carry out&lt;/p&gt;
&lt;h2&gt;REPL&lt;/h2&gt;
&lt;p&gt;The REPL with the example above can seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;700px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://replit.com/@nabeelvalley/react-memo-demo?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactmemo&quot;&gt;The React Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Dev Tools Update</title><link>https://nabeelvalley.co.za/blog/2022/03-08/dev-tools-update/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/03-08/dev-tools-update/</guid><description>Software development tools and languages I&apos;m using at the moment</description><pubDate>Wed, 03 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Programming Languages&lt;/h2&gt;
&lt;p&gt;I&apos;ve primarily switched over to Typescript as my language for building applications, but I&apos;ve also been learning Rust for the purpose of building some low-level libraries&lt;/p&gt;
&lt;p&gt;For Typescript, something I&apos;ve been finding to be really informative is the &lt;a href=&quot;https://github.com/type-challenges/type-challenges&quot;&gt;Type Challenges Repository&lt;/a&gt; which has a lot of challenges along with solutions for modeling and solving complex problems using Typescript&apos;s type system&lt;/p&gt;
&lt;p&gt;For Rust, the &lt;a href=&quot;https://doc.rust-lang.org/book/&quot;&gt;Rust Book&lt;/a&gt; along with the &lt;a href=&quot;https://www.youtube.com/c/NoBoilerplate&quot;&gt;No Boilerplate YouTube Channel&lt;/a&gt; have been really informative&lt;/p&gt;
&lt;h2&gt;Frameworks&lt;/h2&gt;
&lt;p&gt;The current version of my website is built using &lt;a href=&quot;https://www.11ty.dev&quot;&gt;11ty&lt;/a&gt; which is a static site generator which uses Javascript and templates for generating HTML from a variety of data sources - in my case just JSON and Markdown files&lt;/p&gt;
&lt;p&gt;A lot of the professional work I do revolves around the React and React-Native ecosystem, but I&apos;ve made some changes to my stack for personal projects due to the overhead that comes with using React&lt;/p&gt;
&lt;p&gt;For now I&apos;m using 11ty for my website as well as &lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt; for some smaller projects&lt;/p&gt;
&lt;p&gt;I&apos;ve moved on from Gatsby for my site due to the slow build times as a static site builder - and the unnecessary complexity of graphql for this purpose along with the overall burden of node modules that comes with it&lt;/p&gt;
&lt;p&gt;For other projects I&apos;d like to give the &lt;a href=&quot;https://remix.run&quot;&gt;Remix Framework&lt;/a&gt; a shot for full stack apps. Remix is a full stack framework for building React applications with a pretty cool looking data fetching and project structure&lt;/p&gt;
&lt;p&gt;I&apos;ve also been playing around with &lt;a href=&quot;https://tauri.app/&quot;&gt;Tauri&lt;/a&gt; for building desktop applications. Tauri uses a Rust backend with a bring-your-own client approach and pretty much uses any client side javascript framework - I&apos;m looking towards &lt;a href=&quot;https://svelte.dev/&quot;&gt;Svelte&lt;/a&gt; for this since it keeps things a lot more vanilla which is a good break from working with the other major frameworks&lt;/p&gt;
&lt;h2&gt;Code Editor&lt;/h2&gt;
&lt;p&gt;I&apos;m back to VSCode after a short stint with &lt;a href=&quot;http://neovim.io&quot;&gt;NeoVim&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My reasons for leaving NeoVim were mostly due to the amount of setup when switching devices as well as the issues I experienced on Windows where configuration management was a bit inconsistent as well as the dependency management for some plugins became a lot of admin. Even preconfigured solutions like &lt;a href=&quot;https://github.com/LunarVim/LunarVim&quot;&gt;LunarVim&lt;/a&gt; and &lt;a href=&quot;https://github.com/AstroNvim/AstroNvim&quot;&gt;AstroNvim&lt;/a&gt; didn&apos;t work well due to lots of compat issues on Windows&lt;/p&gt;
&lt;p&gt;As far as VSCode is concerned, some things I&apos;ve been using are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.dev/&quot;&gt;The GitHub Online Editor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The GitHub Colorblind Theme (GitHub.github-vscode-theme)&lt;/li&gt;
&lt;li&gt;Code Spell Checker Extension (streetsidesoftware.code-spell-checker)&lt;/li&gt;
&lt;li&gt;GitLens Extension (eamodio.gitlens)&lt;/li&gt;
&lt;li&gt;Hex Editor (ms-vscode.hexeditor)&lt;/li&gt;
&lt;li&gt;Rust Analyzer Extension (rust-lang.rust-analyzer)&lt;/li&gt;
&lt;li&gt;Fix Extension (withfig.fig)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Terminal&lt;/h2&gt;
&lt;p&gt;Some terminal tools I&apos;ve been enjoying recently are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://hyper.is&quot;&gt;Hyper&lt;/a&gt; - An alternative terminal that&apos;s so far been less sluggish and more customizable than the Windows Terminal application&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://fig.io&quot;&gt;Fig&lt;/a&gt; - Provides autocomplete for commands and integrates with loads of CLI tools to provide detailed suggestions and documentations&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nushell.sh&quot;&gt;NuShell&lt;/a&gt; - A shell that works with the idea of command output as data that can be manipulated and transformed which adds a lot of cool data processing functionality on top of your normal shell comands&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>A Simple JSON Backed Database in Typescript</title><link>https://nabeelvalley.co.za/blog/2022/06-07/typescript-json-database/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/06-07/typescript-json-database/</guid><description>Create a simple database that&apos;s backed to a JSON file using Typescript and Node.js</description><pubDate>Thu, 07 Jul 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Define the database&lt;/h1&gt;
&lt;p&gt;The database is defined as a class which has an in-memory store &lt;code&gt;data&lt;/code&gt; and a &lt;code&gt;persist&lt;/code&gt; method that allows for persisting the database to a file as well as content when an instance is created from an existing JSON file&lt;/p&gt;
&lt;p&gt;The code for the database can be seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { existsSync, readFileSync, writeFileSync } from &apos;fs&apos;

export class Database&amp;lt;TData&amp;gt; {
  public data: TData

  constructor(private readonly dbPath: string, initial: TData) {
    this.data = this.load(initial)
  }

  public update = (data: Partial&amp;lt;TData&amp;gt;) =&amp;gt;
    (this.data = { ...this.data, ...data })

  public commit = () =&amp;gt; this.persist(this.data)

  private persist = (data: TData) =&amp;gt;
    writeFileSync(this.dbPath, JSON.stringify(data))

  private read = (): TData =&amp;gt;
    JSON.parse(readFileSync(this.dbPath).toString()) as TData

  private load = (initial: TData): TData =&amp;gt; {
    if (!existsSync(this.dbPath)) {
      this.persist(initial)
    }

    const current = this.read()

    return {
      ...initial,
      ...current,
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;The database can be used by creating an instance and modifying the data in it by using the &lt;code&gt;update&lt;/code&gt; method, and can be written to a file using the &lt;code&gt;commit&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { Database } from &apos;./db&apos;

interface User {
  name: string
  age: number
}

interface DB {
  users: User[]
}

const initial: DB = {
  users: [],
}

const db = new Database&amp;lt;DB&amp;gt;(&apos;./data.json&apos;, initial)

db.update({
  users: [
    {
      name: &apos;Test&apos;,
      age: 20,
    },
  ],
})

db.commit()
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Functional Example&lt;/h2&gt;
&lt;p&gt;The above code is found in the below REPL as a runnable example:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;700px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://replit.com/@nabeelvalley/SimpleJSONDB?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>A type for getting properties common in all objects from a union</title><link>https://nabeelvalley.co.za/blog/2022/08-07/common-object-type/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/08-07/common-object-type/</guid><description>Using typescript type conditions and Exclude to get keys commmon in parts of a union and an object with only common keys from that union</description><pubDate>Wed, 08 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;Something that may come up in practice is a use for a type that allows us to enforce that an object has only the common properties for a given object&lt;/p&gt;
&lt;p&gt;For example, given the two objects below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type AThing = {
  name: string
  age: number
  email: string
  phone: number
}

type BThing = {
  businessName: string[]
  email: string
  phone: string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I would like a type that contains only the things that these objects have in common, namely &lt;code&gt;phone&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;A Type for Common Object Keys&lt;/h2&gt;
&lt;p&gt;This isn&apos;t something that typescript has out-of-the-box, however it can be implemented by using some type juggling&lt;/p&gt;
&lt;p&gt;First, we define a type called &lt;code&gt;CommonKeys&lt;/code&gt; which gets us all the keys which are common in the two objects&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type CommonKeys&amp;lt;T, R = {}&amp;gt; = R extends T
  ? keyof T &amp;amp; CommonKeys&amp;lt;Exclude&amp;lt;T, R&amp;gt;&amp;gt;
  : keyof T
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;CommonKeys&lt;/code&gt; type makes use of a condition to check if &lt;code&gt;R&lt;/code&gt; which is the recursive type extends &lt;code&gt;T&lt;/code&gt; which is the input type. Based on this, we cut down &lt;code&gt;T&lt;/code&gt; one type at a time until there is no more object that can extend &lt;code&gt;R&lt;/code&gt;, then for an input type &lt;code&gt;T&lt;/code&gt; which is the same as &lt;code&gt;R&lt;/code&gt; (an empty object) the result of &lt;code&gt;CommonKeys&amp;lt;{}&amp;gt;&lt;/code&gt; will be &lt;code&gt;never&lt;/code&gt; since &lt;code&gt;{}&lt;/code&gt; has no keys, and will end the recursion&lt;/p&gt;
&lt;p&gt;Applying this to the above types, we get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ABCommonKeys = CommonKeys&amp;lt;AThing | BThing&amp;gt;
// type ABCommonKeys = &amp;quot;email&amp;quot; | &amp;quot;phone&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And as a sanity check, we can also apply this to &lt;code&gt;{}&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Basic = CommonKeys&amp;lt;{}&amp;gt;
// type Basic = never
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;A Type for Common Object&lt;/h2&gt;
&lt;p&gt;Next, we can use the &lt;code&gt;CommonKeys&lt;/code&gt; type defined above to create a &lt;code&gt;Common&lt;/code&gt; type which wne used with the intersection will result in a type that has all the keys common in all types from the intersection&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Common&amp;lt;T&amp;gt; = Pick&amp;lt;T, CommonKeys&amp;lt;T&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can apply this now to a type of &lt;code&gt;AThing | BThing&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ABCommonObject = Common&amp;lt;AThing | BThing&amp;gt;
// type ABCommonObject = {
//   email: string;
//   phone: string | number;
// }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can see that we have the desired result which is an object with the properties that are common between both input object types&lt;/p&gt;
&lt;h2&gt;Final Solution&lt;/h2&gt;
&lt;p&gt;We can put the code from above together into the final solution which is just the two above types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;/** Gets the keys common to any type/union of `T` */
type CommonKeys&amp;lt;T, R = {}&amp;gt; = R extends T
  ? keyof T &amp;amp; CommonKeys&amp;lt;Exclude&amp;lt;T, R&amp;gt;&amp;gt;
  : keyof T

/** Gets an object type containing all keys that exist within a type/union `T` */
type Common&amp;lt;T&amp;gt; = Pick&amp;lt;T, CommonKeys&amp;lt;T&amp;gt;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Type Narrowing in Typescript</title><link>https://nabeelvalley.co.za/blog/2022/31-05/type-narrowing/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/31-05/type-narrowing/</guid><description>Using Type Narrowing for better handling of dynamic variables in typescript</description><pubDate>Tue, 31 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Type Narrowing allows us create conditions under which an object of one type can be used as if it is of another type. We usually use this in conjunction with union types to allow us to specify different handling of the types based on the resulting value&lt;/p&gt;
&lt;h2&gt;Using &lt;code&gt;typeof&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We can use the &lt;code&gt;typeof&lt;/code&gt; keyword in javascript to find out whether what type an object is. This is useful if we have an object that can take on different structures, for example&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Data = string[]
type GetData = Data | (() =&amp;gt; Data)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, we have a type called &lt;code&gt;GetData&lt;/code&gt; which can be either some data or a function to get data. Using this, we can can create a function which fetches data like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const fetchData = (getData: GetData): Data =&amp;gt; {
  if (typeof getData === &apos;function&apos;) {
    return getData()
  }

  return getData
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Using &lt;code&gt;in&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Javascript also has the &lt;code&gt;in&lt;/code&gt; operator which can be used to infer types by us checking a property of an object&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type SimpleData = {
  name: string
}

type ComplexData = {
  name: {
    first: string
    last: string
  }
  isComplex: true
}

type AnyData = SimpleData | ComplexData
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use the &lt;code&gt;in&lt;/code&gt; operator to check the existence of a property of an object by using it along with a key that we expect to be in one object but not another&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getComplexName = (data: AnyData): string =&amp;gt; {
  // isComplex is the name of the key that we expect in `ComplexData` but not `SimpleData`
  if (&apos;isComplex&apos; in data) {
    return [data.name.first, data.name.last].join(&apos; &apos;)
  }

  return data.name
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Using &lt;code&gt;is&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We can use the typescript &lt;code&gt;is&lt;/code&gt; keyword to specify that the return of a boolean means that a variable satisfies a specific condition&lt;/p&gt;
&lt;p&gt;For example, we can create a function that basically does what the &lt;code&gt;in&lt;/code&gt; operator in the above function does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const isComplex = (data: AnyData): data is ComplexData =&amp;gt; {
  return (data as ComplexData).isComplex
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be used in place of the &lt;code&gt;in&lt;/code&gt; check in the above example like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getComplexName2 = (data: AnyData): string =&amp;gt; {
  // isComplex is the name of the key that we expect in `ComplexData` but not `SimpleData`
  if (isComplex(data)) {
    return [data.name.first, data.name.last].join(&apos; &apos;)
  }

  return data.name
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/docs/javascript/typescript-basics&quot;&gt;My TS Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in&quot;&gt;MDN The &lt;code&gt;in&lt;/code&gt; operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof&quot;&gt;MDN The &lt;code&gt;typeof&lt;/code&gt; operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/2/narrowing.html&quot;&gt;TS Docs on Narrowing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>Localhost HTTP Proxy with Node.js</title><link>https://nabeelvalley.co.za/blog/2022/08-03/http-proxy-node-js/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/08-03/http-proxy-node-js/</guid><pubDate>Tue, 08 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;An localhost HTTP proxy is useful for debugging and can be easily defined using Node.js by installing &lt;code&gt;http-proxy&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;yarn add http-proxy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then adding the following to an &lt;code&gt;index.js&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const httpProxy = require(&apos;http-proxy&apos;)

const target = &apos;http://my-target-website.com:1234&apos;

httpProxy.createProxyServer({ target }).listen(8080)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will create a server that listens on &lt;code&gt;8080&lt;/code&gt; and will proxy requests to the target&lt;/p&gt;
</content:encoded></item><item><title>React Top Level API</title><link>https://nabeelvalley.co.za/blog/2022/01-03/react-top-level-api/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/01-03/react-top-level-api/</guid><description>Building complex react components using the React top-level API and TypeScript</description><pubDate>Tue, 01 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;For a reference on the React Top-Level API you can take a look at &lt;a href=&quot;https://reactjs.org/docs/react-api.html&quot;&gt;the React Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;React allows us to do lots of different things using concepts like composition and higher order components. Most of the time these methods are good enough for us to do what we want, however there are some cases where these methods can prove to be insufficient such as when building complex library components or components that need to allow for dynamic composition or do runtime modification of things like child component props, etc.&lt;/p&gt;
&lt;p&gt;For the above purposes we can make use of the React Top-Level API. For the purpose of this writeup I&apos;ll be making use of the parts of this API that allow us to modify a component&apos;s children and modify their props as well as how they&apos;re rendered&lt;/p&gt;
&lt;h2&gt;Our Goal&lt;/h2&gt;
&lt;p&gt;For the purpose of this doc I&apos;ll be using the React API to get to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Show the count of children (&lt;code&gt;Items&lt;/code&gt;) passed to a component (&lt;code&gt;Wrapper&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Render each child in a sub-wrapper &lt;code&gt;ItemWrapper&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Modify the props of the children by adding a &lt;code&gt;position&lt;/code&gt; prop&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When this is done, we want to render a component that results in the following markup:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Wrapper&amp;gt;
  &amp;lt;Count /&amp;gt;
  &amp;lt;ItemWrapper&amp;gt;
    &amp;lt;Item name=&amp;quot;&amp;quot; position=&amp;quot;&amp;quot; /&amp;gt;
  &amp;lt;/ItemWrapper&amp;gt;
  &amp;lt;ItemWrapper&amp;gt;
    &amp;lt;Item name=&amp;quot;&amp;quot; position=&amp;quot;&amp;quot; /&amp;gt;
  &amp;lt;/ItemWrapper&amp;gt;
  &amp;lt;ItemWrapper&amp;gt;
    &amp;lt;Item name=&amp;quot;&amp;quot; position=&amp;quot;&amp;quot; /&amp;gt;
  &amp;lt;/ItemWrapper&amp;gt;
&amp;lt;/Wrapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But a consumer can be used like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&amp;lt;Wrapper&amp;gt;
  &amp;lt;Item name=&amp;quot;&amp;quot;&amp;gt;
  &amp;lt;Item name=&amp;quot;&amp;quot;&amp;gt;
  &amp;lt;Item name=&amp;quot;&amp;quot;&amp;gt;
&amp;lt;/Wrapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Using &lt;code&gt;React.Children&lt;/code&gt; to work with a component&apos;s &lt;code&gt;children&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;React.Children&lt;/code&gt; API (see &lt;a href=&quot;https://reactjs.org/docs/react-api.html#reactchildren&quot;&gt;docs&lt;/a&gt;) provides us with some utilities for traversing the children passed to a component&lt;/p&gt;
&lt;p&gt;Before we can do any of the following, we need to define the structure of an item. Our &lt;code&gt;Item&lt;/code&gt; component is defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;interface ItemProps {
  name: string
  position?: number
}

const Item: React.FC&amp;lt;ItemProps&amp;gt; = ({ name, position }) =&amp;gt; (
  &amp;lt;div&amp;gt;
    {name}, {position}
  &amp;lt;/div&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Use &lt;code&gt;React.Children.count&lt;/code&gt; to get the count&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;React.Children.count&lt;/code&gt; function counts the number of child nodes passed to a React component,
we can use it like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const count = React.Children.count(children)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For our example, let&apos;s start off by creating a &lt;code&gt;Count&lt;/code&gt; component that simply takes a &lt;code&gt;count&lt;/code&gt; prop and displays some text:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;interface CountProps {
  count: number
}

const Count: React.FC&amp;lt;CountProps&amp;gt; = ({ count }) =&amp;gt; &amp;lt;p&amp;gt;Total: {count}&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can define our &lt;code&gt;Wrapper&lt;/code&gt; which will take &lt;code&gt;children&lt;/code&gt; and pass the &lt;code&gt;count&lt;/code&gt; to our &lt;code&gt;Count&lt;/code&gt; component:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const Wrapper: React.FC = ({ children }) =&amp;gt; {
  const count = React.Children.count(children)

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Count count={count} /&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Use &lt;code&gt;React.Children.map&lt;/code&gt; to wrap each child&lt;/h3&gt;
&lt;p&gt;Next, the &lt;code&gt;React.Children.map&lt;/code&gt; function allows us to map over the children of an element and do stuff with it, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const items = React.Children.map(children, (child) =&amp;gt; {
  return &amp;lt;ItemWrapper&amp;gt;{child}&amp;lt;/ItemWrapper&amp;gt;
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Based on the above, we can define an &lt;code&gt;ItemWrapper&lt;/code&gt; as so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const ItemWrapper: React.FC = ({ children }) =&amp;gt; (
  &amp;lt;li
    style={{
      backgroundColor: &apos;lightgrey&apos;,
      padding: &apos;10px&apos;,
      margin: &apos;20px&apos;,
    }}
  &amp;gt;
    {children}
  &amp;lt;/li&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can update the &lt;code&gt;Wrapper&lt;/code&gt; to make use of &lt;code&gt;React.children.map&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const Wrapper: React.FC = ({ children }) =&amp;gt; {
  const count = React.Children.count(children)

  const items = React.Children.map(children, (child) =&amp;gt; {
    return &amp;lt;ItemWrapper&amp;gt;{child}&amp;lt;/ItemWrapper&amp;gt;
  })

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Count count={count} /&amp;gt;
      &amp;lt;ul&amp;gt;{items}&amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Use &lt;code&gt;React.cloneElement&lt;/code&gt; to change child props&lt;/h2&gt;
&lt;p&gt;Lastly, we want to append a &lt;code&gt;position&lt;/code&gt; prop to the &lt;code&gt;Item&lt;/code&gt;. To do this we can make use of the &lt;code&gt;React.cloneElement&lt;/code&gt; function which allows us to clone an element and modify the props of it. Using this function looks like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const childProps = child.props
const newProps = { ...child.props, position: index }

const newChild = React.cloneElement(child, newProps)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Integrating this into the &lt;code&gt;React.Children.map&lt;/code&gt; function above will result in our &lt;code&gt;Wrapper&lt;/code&gt; looking like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const Wrapper: React.FC = ({ children }) =&amp;gt; {
  const count = React.Children.count(children)

  const items = React.Children.map(children, (child, index) =&amp;gt; {
    const childProps = child.props
    const newProps = { ...child.props, position: index }

    const newChild = React.cloneElement(child, newProps)

    return &amp;lt;ItemWrapper&amp;gt;{newChild}&amp;lt;/ItemWrapper&amp;gt;
  })

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Count count={count} /&amp;gt;
      &amp;lt;ul&amp;gt;{items}&amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Use &lt;code&gt;React.isValidElement&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We&apos;ve completed most of what&apos;s needed, however if for some reason our &lt;code&gt;child&lt;/code&gt; is not a valid react element our component may still crash. To get around this we can use the &lt;code&gt;React.isValidElement&lt;/code&gt; function&lt;/p&gt;
&lt;p&gt;We can update our &lt;code&gt;map&lt;/code&gt; function above to return &lt;code&gt;null&lt;/code&gt; if the element is not value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const items = React.Children.map(children, (child, index) =&amp;gt; {
  if (!React.isValidElement(child)) return null

  const childProps = child.props
  const newProps = { ...child.props, position: index }

  const newChild = React.cloneElement(child, newProps)

  return &amp;lt;ItemWrapper&amp;gt;{newChild}&amp;lt;/ItemWrapper&amp;gt;
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which results in our &lt;code&gt;Wrapper&lt;/code&gt; now being:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const Wrapper: React.FC = ({ children }) =&amp;gt; {
  const count = React.Children.count(children)
  const items = React.Children.map(children, (child, index) =&amp;gt; {
    if (!React.isValidElement(child)) return null

    const childProps = child.props
    const newProps = { ...child.props, position: index }

    const newChild = React.cloneElement(child, newProps)

    return &amp;lt;ItemWrapper&amp;gt;{newChild}&amp;lt;/ItemWrapper&amp;gt;
  })

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Count count={count} /&amp;gt;
      &amp;lt;ul&amp;gt;{items}&amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Result&lt;/h2&gt;
&lt;p&gt;Lastly, we&apos;ll render the above using the &lt;code&gt;App&lt;/code&gt; component, the API for the above components should be composable as we outlined initially. The &lt;code&gt;App&lt;/code&gt; component will now look like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const App: React.FC = () =&amp;gt; {
  return (
    &amp;lt;Wrapper&amp;gt;
      &amp;lt;Item name=&amp;quot;Apple&amp;quot; /&amp;gt;
      &amp;lt;Item name=&amp;quot;Banana&amp;quot; /&amp;gt;
      &amp;lt;Item name=&amp;quot;Chocolate&amp;quot; /&amp;gt;
    &amp;lt;/Wrapper&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the rendered HTML:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;p&amp;gt;Total: 3&amp;lt;/p&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li style=&amp;quot;background-color: lightgrey; padding: 10px; margin: 20px;&amp;quot;&amp;gt;
      &amp;lt;div&amp;gt;Apple, 0&amp;lt;/div&amp;gt;
    &amp;lt;/li&amp;gt;
    &amp;lt;li style=&amp;quot;background-color: lightgrey; padding: 10px; margin: 20px;&amp;quot;&amp;gt;
      &amp;lt;div&amp;gt;Banana, 1&amp;lt;/div&amp;gt;
    &amp;lt;/li&amp;gt;
    &amp;lt;li style=&amp;quot;background-color: lightgrey; padding: 10px; margin: 20px;&amp;quot;&amp;gt;
      &amp;lt;div&amp;gt;Chocolate, 2&amp;lt;/div&amp;gt;
    &amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;div&amp;gt;
&amp;lt;p&amp;gt;Total: 3&amp;lt;/p&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li style=&amp;quot;background-color: lightgrey; padding: 10px; margin: 20px;&amp;quot;&amp;gt;
&amp;lt;div&amp;gt;Apple, 0&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li style=&amp;quot;background-color: lightgrey; padding: 10px; margin: 20px;&amp;quot;&amp;gt;
&amp;lt;div&amp;gt;Banana, 1&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li style=&amp;quot;background-color: lightgrey; padding: 10px; margin: 20px;&amp;quot;&amp;gt;
&amp;lt;div&amp;gt;Chocolate, 2&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;&lt;/p&gt;
&lt;p&gt;And lastly, if you&apos;d like to interact with the code from this sample you can see it in &lt;a href=&quot;https://replit.com/@nabeelvalley/ReactTopLevelAPIExample#src/App.tsx&quot;&gt;this Repl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;700px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://replit.com/@nabeelvalley/ReactTopLevelAPIExample?lite=true#src/App.tsx&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Visualizations with React</title><link>https://nabeelvalley.co.za/blog/2022/11-02/d3-with-react/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2022/11-02/d3-with-react/</guid><description>Create SVG Graphs and Visualizations in React using D3</description><pubDate>Fri, 11 Feb 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Data Visualization with D3 and React&lt;/h1&gt;
&lt;p&gt;React is a library for building reactive user interfaces using JavaScript (or Typescript) and D3 (short for &lt;em&gt;Data-Driven Documents&lt;/em&gt;) is a set of libraries for working with visualizations based on data&lt;/p&gt;
&lt;p&gt;Before getting started, I would recommend familiarity with SVG, React, and D3&lt;/p&gt;
&lt;p&gt;Some good references for SVG are on the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial&quot;&gt;MDN SVG Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A good place to start for React would be the &lt;a href=&quot;https://reactjs.org/&quot;&gt;React Docs&lt;/a&gt; or &lt;a href=&quot;/docs/react/complete-react.md&quot;&gt;my React Notes&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And lastly, the &lt;a href=&quot;https://github.com/d3/d3/wiki&quot;&gt;D3 Docs&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Getting Stared&lt;/h2&gt;
&lt;p&gt;To follow along, you will need to install &lt;a href=&quot;https://nodejs.org/en/&quot;&gt;Node.js&lt;/a&gt; and be comfortable using the terminal&lt;/p&gt;
&lt;p&gt;I&apos;m going to be using a React App with TypeScript initialized with Vite as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;yarn create vite
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then selecting the &lt;code&gt;react-ts&lt;/code&gt; option when prompted. Next, install &lt;code&gt;d3&lt;/code&gt; from the project root with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;yarn add d3
yarn add --dev @types/d3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we&apos;ve got a basic project setup, we can start talking about D3&lt;/p&gt;
&lt;h2&gt;Scales (&lt;code&gt;d3-scale&lt;/code&gt;)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/d3/d3-scale&quot;&gt;&lt;code&gt;d3-scale&lt;/code&gt; Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Broadly, scales allow us to map from one set of values to another set of values,&lt;/p&gt;
&lt;p&gt;Scales in D3 are a set of tools which map a dimension of data to a visual variable. They help us go from something like &lt;code&gt;count&lt;/code&gt; in our data to something like &lt;code&gt;width&lt;/code&gt; in our rendered SVG&lt;/p&gt;
&lt;p&gt;We can create scales for a sample dataset like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Datum = {
  name: string
  count: number
}

export const data: Datum[] = [
  { name: &apos;🍊&apos;, count: 21 },
  { name: &apos;🍇&apos;, count: 13 },
  { name: &apos;🍏&apos;, count: 8 },
  { name: &apos;🍌&apos;, count: 5 },
  { name: &apos;🍐&apos;, count: 3 },
  { name: &apos;🍋&apos;, count: 2 },
  { name: &apos;🍎&apos;, count: 1 },
  { name: &apos;🍉&apos;, count: 1 },
]
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Also, a common thing to do when working with scales is to define margins around out image, this is done simply as an object like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const margin = {
  top: 20,
  right: 20,
  bottom: 20,
  left: 35,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This just helps us simplify some position/layout things down the line&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Scales work by taking a value from the &lt;code&gt;domain&lt;/code&gt; (data space) and returning a value from &lt;code&gt;range&lt;/code&gt; (visual space):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const width = 600
const height = 400

const x = d3
  .scaleLinear()
  .domain([0, 10]) // values of the data space
  .range([0, width]) // values of the visual space

const position = x(3) // position = scale(value)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, there&apos;s also the &lt;code&gt;invert&lt;/code&gt; method which goes the other way - from &lt;code&gt;range&lt;/code&gt; to &lt;code&gt;domain&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const position = x(3) // position === 30
const value = x.invert(30) // value === 3
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;invert&lt;/code&gt; method is useful for things like calculating a &lt;code&gt;value&lt;/code&gt; from a mouse &lt;code&gt;position&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;D3 has different Scale types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Continuous (Linear, Power, Log, Identity, Time, Radial)&lt;/li&gt;
&lt;li&gt;Sequential&lt;/li&gt;
&lt;li&gt;Diverging&lt;/li&gt;
&lt;li&gt;Quantize&lt;/li&gt;
&lt;li&gt;Quantile&lt;/li&gt;
&lt;li&gt;Threshold&lt;/li&gt;
&lt;li&gt;Ordinal (Band, Point)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Continuous Scales&lt;/h3&gt;
&lt;p&gt;These scales map continuous data to other continuous data&lt;/p&gt;
&lt;p&gt;D3 has a few different continuous scale types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linear&lt;/li&gt;
&lt;li&gt;Power&lt;/li&gt;
&lt;li&gt;Log&lt;/li&gt;
&lt;li&gt;Identity&lt;/li&gt;
&lt;li&gt;Radial&lt;/li&gt;
&lt;li&gt;Time&lt;/li&gt;
&lt;li&gt;Sequential Color&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For my purposes at the moment I&apos;m going to be looking at the methods for Linear and Sequential Color scales, but the documentation explains all of the above very thoroughly and is worth a read for additional information on their usage&lt;/p&gt;
&lt;h4&gt;Linear&lt;/h4&gt;
&lt;p&gt;We can use a &lt;code&gt;linear&lt;/code&gt; scale in the fruit example for mapping count to an x width:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const maxX = d3.max(data, (d) =&amp;gt; d.count) as number

const x = d3
  .scaleLinear&amp;lt;number&amp;gt;()
  .domain([0, maxX])
  .range([margin.left, width - margin.right])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we don&apos;t want the custom &lt;code&gt;domain&lt;/code&gt; to &lt;code&gt;range&lt;/code&gt; interpolation we can create a custom &lt;code&gt;interpolator&lt;/code&gt;. An &lt;code&gt;interpolator&lt;/code&gt; is a function that takes a value from the &lt;code&gt;domain&lt;/code&gt; and returns the resulting &lt;code&gt;range&lt;/code&gt; value&lt;/p&gt;
&lt;p&gt;D3 has a few different &lt;code&gt;interpolators&lt;/code&gt; included for tasks such as interpolating colors or rounding values&lt;/p&gt;
&lt;p&gt;We can create a custom color domain to interpolate over and use the &lt;code&gt;interpolateHsl&lt;/code&gt; or &lt;code&gt;interpolateRgb&lt;/code&gt; functions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const color = d3
  .scaleLinear&amp;lt;string&amp;gt;()
  .domain([0, maxX])
  .range([&apos;pink&apos;, &apos;lightgreen&apos;])
  .interpolate(d3.interpolateHsl)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sequential Color&lt;/h3&gt;
&lt;p&gt;If for some reason we want to use the pre-included color scales&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;scaleSequential&lt;/code&gt; scale is a method that allows us to map to a &lt;code&gt;color&lt;/code&gt; range using an &lt;code&gt;interpolator&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;D3 has a few different interpolators we can use with this function like &lt;code&gt;d3.interpolatePurples&lt;/code&gt;, &lt;code&gt;d3.interpolateRainbow&lt;/code&gt; or &lt;code&gt;d3.interpolateCool&lt;/code&gt; among others which look quite nice&lt;/p&gt;
&lt;p&gt;We can create a color scale using the &lt;code&gt;d3.interpolatePurples&lt;/code&gt; which will map the data to a scale of purples:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const color = d3
  .scaleSequential()
  .domain([0, maxX])
  .interpolator(d3.interpolatePurples)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These can be used instead of the &lt;code&gt;scaleLinear&lt;/code&gt; with &lt;code&gt;interpolateHsl&lt;/code&gt; for example above but to provide a pre-calibrated color scale&lt;/p&gt;
&lt;h3&gt;Ordinal Scales&lt;/h3&gt;
&lt;p&gt;Ordinal scales have a discrete domain and range and are used for the mapping of discrete data. These are a good fit for mapping a scale with categorical data. D3 offers us the following scales:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Band Scale&lt;/li&gt;
&lt;li&gt;Point Scale&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Band Scale&lt;/h4&gt;
&lt;p&gt;A Band Scale is a type of Ordinal Scale where the output &lt;code&gt;range&lt;/code&gt; is continuous and numeric&lt;/p&gt;
&lt;p&gt;We can create a mapping for where each of our labels should be positioned with &lt;code&gt;scaleBand&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const names = data.map((d) =&amp;gt; d.name)

const y = d3
  .scaleBand()
  .domain(names)
  .range([margin.top, height - margin.bottom])
  .padding(0.1)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The domain can be any size array, unlike in the case of continuous scales where the are usually start and end values&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Building a Bar Graph&lt;/h2&gt;
&lt;p&gt;When creating visuals with D3 there are a few different ways we can output to SVG data. D3 provides us with some methods for creating shapes and elements programmatically via a builder pattern - similar to how we create scales.&lt;/p&gt;
&lt;p&gt;However, there are also cases where we would want to define out SVG elements manually, such as when working with React so that the react renderer can handle the rendering of the SVG elements and we can manage our DOM structure in a way that&apos;s a bit more representative of the way we work in React&lt;/p&gt;
&lt;h3&gt;The SVG Root&lt;/h3&gt;
&lt;p&gt;Every SVG image has to have an &lt;code&gt;svg&lt;/code&gt; root element. To help ensure that this root scales correctly we also use it with a &lt;code&gt;viewBox&lt;/code&gt; attribute which specifies which portion of the SVG is visible since the contents can go outside of the bounds of the View Box and we may not want to display this overflow content by default&lt;/p&gt;
&lt;p&gt;Using the definitions for &lt;code&gt;margin&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; from before we can get the &lt;code&gt;viewBox&lt;/code&gt; for the SVG we&apos;re trying to render like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const viewBox = `0 ${margin.top} ${width} ${height - margin.top}`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then, using that value in the &lt;code&gt;svg&lt;/code&gt; element:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;return &amp;lt;svg viewBox={viewBox}&amp;gt;{/* we will render the graph in here */}&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point we don&apos;t really have anything in the SVG, next up we&apos;ll do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add Bars to the SVG&lt;/li&gt;
&lt;li&gt;Add Y Labels to the SVG&lt;/li&gt;
&lt;li&gt;Add X Labels to the SVG&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Bars&lt;/h3&gt;
&lt;p&gt;We can create Bars using the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const bars = data.map((d) =&amp;gt; (
  &amp;lt;rect
    key={y(d.name)}
    fill={color(d.count)}
    y={y(d.name)}
    x={x(0)}
    width={x(d.count) - x(0)}
    height={y.bandwidth()}
  /&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We make use of the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; functions which help us get the positions for the &lt;code&gt;rect&lt;/code&gt; as well as &lt;code&gt;y.bandWidth()&lt;/code&gt; and &lt;code&gt;x(d.count)&lt;/code&gt; to &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; for the element&lt;/p&gt;
&lt;p&gt;We can then add that into the SVG using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;return (
  &amp;lt;svg viewBox={viewBox}&amp;gt;
    &amp;lt;g&amp;gt;{bars}&amp;lt;/g&amp;gt;
  &amp;lt;/svg&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, the resulting SVG will look like this:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg viewBox=&amp;quot;0 20 600 380&amp;quot;&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(38, 165, 219)&amp;quot; y=&amp;quot;26&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;208&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(68, 121, 223)&amp;quot; y=&amp;quot;70&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;130&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(175, 240, 91)&amp;quot; y=&amp;quot;114&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;545&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(97, 83, 199)&amp;quot; y=&amp;quot;158&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;52&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(32, 226, 157)&amp;quot; y=&amp;quot;202&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;337&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;246&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;290&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(88, 95, 210)&amp;quot; y=&amp;quot;334&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;78&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;h3&gt;Y Labels&lt;/h3&gt;
&lt;p&gt;Next, using similar concepts as above, we can add the Y Labels:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const yLabels = data.map((d) =&amp;gt; (
  &amp;lt;text key={y(d.name)} y={y(d.name)} x={0} dy=&amp;quot;0.35em&amp;quot;&amp;gt;
    {d.name}
  &amp;lt;/text&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can add this into the SVG, and also wrapping the element in a &lt;code&gt;g&lt;/code&gt; with a some basic text alignment and translation for positioning it correctly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;return (
  &amp;lt;svg viewBox={viewBox}&amp;gt;
    &amp;lt;g
      fill=&amp;quot;steelblue&amp;quot;
      textAnchor=&amp;quot;end&amp;quot;
      transform={`translate(${margin.left - 5}, ${y.bandwidth() / 2})`}
    &amp;gt;
      {yLabels}
    &amp;lt;/g&amp;gt;
    &amp;lt;g&amp;gt;{bars}&amp;lt;/g&amp;gt;
  &amp;lt;/svg&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The state of the SVG at this point is:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg viewBox=&amp;quot;0 20 600 380&amp;quot;&amp;gt;
&amp;lt;g fill=&amp;quot;steelblue&amp;quot; text-anchor=&amp;quot;end&amp;quot; transform=&amp;quot;translate(30, 20)&amp;quot;&amp;gt;
&amp;lt;text y=&amp;quot;26&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍏&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;70&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍌&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;114&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍊&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;158&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍋&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;202&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍇&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;246&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍎&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;290&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍉&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;334&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍐&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(38, 165, 219)&amp;quot; y=&amp;quot;26&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;208&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(68, 121, 223)&amp;quot; y=&amp;quot;70&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;130&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect
fill=&amp;quot;rgb(175, 240, 91)&amp;quot;
y=&amp;quot;114&amp;quot;
x=&amp;quot;35&amp;quot;
width=&amp;quot;545&amp;quot;
height=&amp;quot;40&amp;quot;
&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(97, 83, 199)&amp;quot; y=&amp;quot;158&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;52&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect
fill=&amp;quot;rgb(32, 226, 157)&amp;quot;
y=&amp;quot;202&amp;quot;
x=&amp;quot;35&amp;quot;
width=&amp;quot;337&amp;quot;
height=&amp;quot;40&amp;quot;
&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;246&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;290&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(88, 95, 210)&amp;quot; y=&amp;quot;334&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;78&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;h3&gt;X Labels&lt;/h3&gt;
&lt;p&gt;Next, we can add the X Labels over each &lt;code&gt;rect&lt;/code&gt; using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const xLabels = data.map((d) =&amp;gt; (
  &amp;lt;text key={y(d.name)} y={y(d.name)} x={x(d.count)} dy=&amp;quot;0.35em&amp;quot;&amp;gt;
    {d.count}
  &amp;lt;/text&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the resulting code looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;return (
  &amp;lt;svg viewBox={viewBox}&amp;gt;
    &amp;lt;g
      fill=&amp;quot;steelblue&amp;quot;
      textAnchor=&amp;quot;end&amp;quot;
      transform={`translate(${margin.left - 5}, ${y.bandwidth() / 2})`}
    &amp;gt;
      {yLabels}
    &amp;lt;/g&amp;gt;
    &amp;lt;g&amp;gt;{bars}&amp;lt;/g&amp;gt;
    &amp;lt;g
      fill=&amp;quot;white&amp;quot;
      textAnchor=&amp;quot;end&amp;quot;
      transform={`translate(-6, ${y.bandwidth() / 2})`}
    &amp;gt;
      {xLabels}
    &amp;lt;/g&amp;gt;
  &amp;lt;/svg&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the final SVG:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg viewBox=&amp;quot;0 20 600 380&amp;quot;&amp;gt;
&amp;lt;g fill=&amp;quot;steelblue&amp;quot; text-anchor=&amp;quot;end&amp;quot; transform=&amp;quot;translate(30, 20)&amp;quot;&amp;gt;
&amp;lt;text y=&amp;quot;26&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍏&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;70&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍌&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;114&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍊&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;158&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍋&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;202&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍇&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;246&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍎&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;290&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍉&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;334&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍐&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(38, 165, 219)&amp;quot; y=&amp;quot;26&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;208&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(68, 121, 223)&amp;quot; y=&amp;quot;70&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;130&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect
fill=&amp;quot;rgb(175, 240, 91)&amp;quot;
y=&amp;quot;114&amp;quot;
x=&amp;quot;35&amp;quot;
width=&amp;quot;545&amp;quot;
height=&amp;quot;40&amp;quot;
&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(97, 83, 199)&amp;quot; y=&amp;quot;158&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;52&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect
fill=&amp;quot;rgb(32, 226, 157)&amp;quot;
y=&amp;quot;202&amp;quot;
x=&amp;quot;35&amp;quot;
width=&amp;quot;337&amp;quot;
height=&amp;quot;40&amp;quot;
&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;246&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;290&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(88, 95, 210)&amp;quot; y=&amp;quot;334&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;78&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g fill=&amp;quot;white&amp;quot; text-anchor=&amp;quot;end&amp;quot; transform=&amp;quot;translate(-6, 20)&amp;quot;&amp;gt;
&amp;lt;text y=&amp;quot;26&amp;quot; x=&amp;quot;243&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;8&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;70&amp;quot; x=&amp;quot;165&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;5&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;114&amp;quot; x=&amp;quot;580&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;21&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;158&amp;quot; x=&amp;quot;87&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;2&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;202&amp;quot; x=&amp;quot;372&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;13&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;246&amp;quot; x=&amp;quot;61&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;1&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;290&amp;quot; x=&amp;quot;61&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;1&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;334&amp;quot; x=&amp;quot;113&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;3&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;h3&gt;Final Result&lt;/h3&gt;
&lt;p&gt;The code for the entire file/graph can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Fruit.tsx&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import React from &apos;react&apos;
import * as d3 from &apos;d3&apos;
import { data } from &apos;../data/fruit&apos;

const width = 600
const height = 400

const margin = {
  top: 20,
  right: 20,
  bottom: 20,
  left: 35,
}

const maxX = d3.max(data, (d) =&amp;gt; d.count) as number

const x = d3
  .scaleLinear&amp;lt;number&amp;gt;()
  .domain([0, maxX])
  .range([margin.left, width - margin.right])
  .interpolate(d3.interpolateRound)

const names = data.map((d) =&amp;gt; d.name)

const y = d3
  .scaleBand()
  .domain(names)
  .range([margin.top, height - margin.bottom])
  .padding(0.1)
  .round(true)

const color = d3
  .scaleSequential()
  .domain([0, maxX])
  .interpolator(d3.interpolateCool)

export const Fruit: React.FC = ({}) =&amp;gt; {
  const viewBox = `0 ${margin.top} ${width} ${height - margin.top}`

  const yLabels = data.map((d) =&amp;gt; (
    &amp;lt;text key={y(d.name)} y={y(d.name)} x={0} dy=&amp;quot;0.35em&amp;quot;&amp;gt;
      {d.name}
    &amp;lt;/text&amp;gt;
  ))

  const bars = data.map((d) =&amp;gt; (
    &amp;lt;rect
      key={y(d.name)}
      fill={color(d.count)}
      y={y(d.name)}
      x={x(0)}
      width={x(d.count) - x(0)}
      height={y.bandwidth()}
    /&amp;gt;
  ))

  const xLabels = data.map((d) =&amp;gt; (
    &amp;lt;text key={y(d.name)} y={y(d.name)} x={x(d.count)} dy=&amp;quot;0.35em&amp;quot;&amp;gt;
      {d.count}
    &amp;lt;/text&amp;gt;
  ))

  return (
    &amp;lt;svg viewBox={viewBox}&amp;gt;
      &amp;lt;g
        fill=&amp;quot;steelblue&amp;quot;
        textAnchor=&amp;quot;end&amp;quot;
        transform={`translate(${margin.left - 5}, ${y.bandwidth() / 2})`}
      &amp;gt;
        {yLabels}
      &amp;lt;/g&amp;gt;
      &amp;lt;g&amp;gt;{bars}&amp;lt;/g&amp;gt;
      &amp;lt;g
        fill=&amp;quot;white&amp;quot;
        textAnchor=&amp;quot;end&amp;quot;
        transform={`translate(-6, ${y.bandwidth() / 2})`}
      &amp;gt;
        {xLabels}
      &amp;lt;/g&amp;gt;
    &amp;lt;/svg&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h3&gt;Ticks and Grid Lines&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that D3 includes a &lt;code&gt;d3-axis&lt;/code&gt; package but that doesn&apos;t quite work given that we&apos;re manually creating the SVG using React and not D3&apos;s string-based rendering&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We may want to add Ticks and Grid Lines on the X-Axis, we can do this using the scale&apos;s &lt;code&gt;ticks&lt;/code&gt; method like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const xGrid = x.ticks().map((t) =&amp;gt; (
  &amp;lt;g key={t}&amp;gt;
    &amp;lt;line
      stroke=&amp;quot;lightgrey&amp;quot;
      x1={x(t)}
      y1={margin.top}
      x2={x(t)}
      y2={height - margin.bottom}
    /&amp;gt;
    &amp;lt;text fill=&amp;quot;darkgrey&amp;quot; textAnchor=&amp;quot;middle&amp;quot; x={x(t)} y={height}&amp;gt;
      {t}
    &amp;lt;/text&amp;gt;
  &amp;lt;/g&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then render this in the &lt;code&gt;svg&lt;/code&gt; as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;return (
  &amp;lt;svg viewBox={viewBox}&amp;gt;
    &amp;lt;g&amp;gt;{xGrid}&amp;lt;/g&amp;gt;
    {/* previous graph content */}
  &amp;lt;/svg&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result will look like this:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg viewBox=&amp;quot;0 20 600 380&amp;quot;&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;35&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;35&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;35&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;0&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;87&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;87&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;87&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;2&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;139&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;139&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;139&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;4&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;191&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;191&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;191&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;6&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;243&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;243&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;243&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;8&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;295&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;295&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;295&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;10&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;346&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;346&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;346&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;12&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;398&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;398&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;398&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;14&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;450&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;450&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;450&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;16&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;502&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;502&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;502&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;18&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line stroke=&amp;quot;lightgrey&amp;quot; x1=&amp;quot;554&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;554&amp;quot; y2=&amp;quot;380&amp;quot;&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;554&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;20&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g fill=&amp;quot;steelblue&amp;quot; text-anchor=&amp;quot;end&amp;quot; transform=&amp;quot;translate(30, 20)&amp;quot;&amp;gt;
&amp;lt;text y=&amp;quot;26&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍏&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;70&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍌&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;114&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍊&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;158&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍋&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;202&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍇&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;246&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍎&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;290&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍉&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;334&amp;quot; x=&amp;quot;0&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;🍐&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(38, 165, 219)&amp;quot; y=&amp;quot;26&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;208&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(68, 121, 223)&amp;quot; y=&amp;quot;70&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;130&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect
fill=&amp;quot;rgb(175, 240, 91)&amp;quot;
y=&amp;quot;114&amp;quot;
x=&amp;quot;35&amp;quot;
width=&amp;quot;545&amp;quot;
height=&amp;quot;40&amp;quot;
&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(97, 83, 199)&amp;quot; y=&amp;quot;158&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;52&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect
fill=&amp;quot;rgb(32, 226, 157)&amp;quot;
y=&amp;quot;202&amp;quot;
x=&amp;quot;35&amp;quot;
width=&amp;quot;337&amp;quot;
height=&amp;quot;40&amp;quot;
&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;246&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(104, 73, 185)&amp;quot; y=&amp;quot;290&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;26&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;rect fill=&amp;quot;rgb(88, 95, 210)&amp;quot; y=&amp;quot;334&amp;quot; x=&amp;quot;35&amp;quot; width=&amp;quot;78&amp;quot; height=&amp;quot;40&amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g fill=&amp;quot;white&amp;quot; text-anchor=&amp;quot;end&amp;quot; transform=&amp;quot;translate(-6, 20)&amp;quot;&amp;gt;
&amp;lt;text y=&amp;quot;26&amp;quot; x=&amp;quot;243&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;8&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;70&amp;quot; x=&amp;quot;165&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;5&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;114&amp;quot; x=&amp;quot;580&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;21&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;158&amp;quot; x=&amp;quot;87&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;2&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;202&amp;quot; x=&amp;quot;372&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;13&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;246&amp;quot; x=&amp;quot;61&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;1&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;290&amp;quot; x=&amp;quot;61&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;1&amp;lt;/text&amp;gt;
&amp;lt;text y=&amp;quot;334&amp;quot; x=&amp;quot;113&amp;quot; dy=&amp;quot;0.35em&amp;quot;&amp;gt;3&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;h2&gt;Building a Line Graph&lt;/h2&gt;
&lt;p&gt;We can apply all the same as in the Bar Graph before to draw a Line Graph. The example I&apos;ll be using consists of a &lt;code&gt;Datum&lt;/code&gt; as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export type Datum = {
  date: Date
  temp: number
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given that the X-Axis is a &lt;code&gt;DateTime&lt;/code&gt; we will need to do some additional conversions as well as formatting&lt;/p&gt;
&lt;h3&gt;Working with Domains&lt;/h3&gt;
&lt;p&gt;In the context of this graph it would also be useful to have an automatically calculated domain instead of a hardcoded one as in the previous example&lt;/p&gt;
&lt;p&gt;We can use the &lt;code&gt;d3.extent&lt;/code&gt; function to calculate a domain:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const dateDomain = d3.extent(data, (d) =&amp;gt; d.date) as [Date, Date]
const tempDomain = d3.extent(data, (d) =&amp;gt; d.temp).reverse() as [number, number]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use this domain definitions in a &lt;code&gt;scale&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const tempScale = d3
  .scaleLinear&amp;lt;number&amp;gt;()
  .domain(tempDomain)
  .range([margin.top, height - margin.bottom])
  .interpolate(d3.interpolateRound)

const dateScale = d3
  .scaleTime()
  .domain(dateDomain)
  .range([margin.left, width - margin.right])
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Line&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;d3.line&lt;/code&gt; function is useful for creating a &lt;code&gt;d&lt;/code&gt; attribute for an SVG &lt;code&gt;path&lt;/code&gt; element which defines the line segments&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;line&lt;/code&gt; function requires &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; mappings. The line for the graph path can be seen as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const line = d3
  .line&amp;lt;Datum&amp;gt;()
  .x((d) =&amp;gt; dateScale(d.date))
  .y((d) =&amp;gt; tempScale(d.temp))(data) as string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also include the &lt;code&gt;Datum&lt;/code&gt; type in the above to scope down the type of &lt;code&gt;data&lt;/code&gt; allowed in the resulting function&lt;/p&gt;
&lt;h3&gt;Formatting&lt;/h3&gt;
&lt;p&gt;D3 includes functions for formatting &lt;code&gt;DateTime&lt;/code&gt;s. We can create a formatter for a &lt;code&gt;DateTime&lt;/code&gt; as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const formatter = d3.timeFormat(&apos;%Y-%m&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use the formatter like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;formatter(dateTime)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Grid Lines&lt;/h3&gt;
&lt;p&gt;We can define the X Axis and grid lines similar to how we did it previously:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const xGrid = dateTicks.map((t) =&amp;gt; (
  &amp;lt;g key={t.toString()}&amp;gt;
    &amp;lt;line
      stroke=&amp;quot;lightgrey&amp;quot;
      x1={dateScale(t)}
      y1={margin.top}
      x2={dateScale(t)}
      y2={height - margin.bottom}
      strokeDasharray={4}
    /&amp;gt;
    &amp;lt;text fill=&amp;quot;darkgrey&amp;quot; textAnchor=&amp;quot;middle&amp;quot; x={dateScale(t)} y={height}&amp;gt;
      {formatter(t)}
    &amp;lt;/text&amp;gt;
  &amp;lt;/g&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the Y Axis grid lines:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;const yGrid = tempTicks.map((t) =&amp;gt; (
  &amp;lt;g key={t.toString()}&amp;gt;
    &amp;lt;line
      stroke=&amp;quot;lightgrey&amp;quot;
      y1={tempScale(t)}
      x1={margin.left}
      y2={tempScale(t)}
      x2={width - margin.right}
      strokeDasharray={4}
    /&amp;gt;
    &amp;lt;text fill=&amp;quot;darkgrey&amp;quot; textAnchor=&amp;quot;end&amp;quot; y={tempScale(t)} x={margin.left - 5}&amp;gt;
      {t}
    &amp;lt;/text&amp;gt;
  &amp;lt;/g&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Final result&lt;/h3&gt;
&lt;p&gt;Using all the values that have been defined above, we can create the overall graph and grid lines like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;return (
  &amp;lt;svg viewBox={viewBox}&amp;gt;
    &amp;lt;g&amp;gt;{xGrid}&amp;lt;/g&amp;gt;
    &amp;lt;g&amp;gt;{yGrid}&amp;lt;/g&amp;gt;
    &amp;lt;path d={line} stroke=&amp;quot;steelblue&amp;quot; fill=&amp;quot;none&amp;quot; /&amp;gt;
  &amp;lt;/svg&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final code can be seen below:&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Temperature.tsx&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;import React from &apos;react&apos;
import * as d3 from &apos;d3&apos;
import { data, Datum } from &apos;../data/temperature&apos;

const width = 600
const height = 400

const margin = {
  top: 20,
  right: 50,
  bottom: 20,
  left: 50,
}

const tempDomain = d3.extent(data, (d) =&amp;gt; d.temp).reverse() as [number, number]

const tempScale = d3
  .scaleLinear&amp;lt;number&amp;gt;()
  .domain(tempDomain)
  .range([margin.top, height - margin.bottom])
  .interpolate(d3.interpolateRound)

const tempTicks = tempScale.ticks()

const dateDomain = d3.extent(data, (d) =&amp;gt; d.date) as [Date, Date]

const dateScale = d3
  .scaleTime()
  .domain(dateDomain)
  .range([margin.left, width - margin.right])

const dateTicks = dateScale.ticks(5).concat(dateScale.domain())

const line = d3
  .line&amp;lt;Datum&amp;gt;()
  .x((d) =&amp;gt; dateScale(d.date))
  .y((d) =&amp;gt; tempScale(d.temp))(data) as string

const formatter = d3.timeFormat(&apos;%Y-%m&apos;)

export const Temperature: React.FC = ({}) =&amp;gt; {
  const viewBox = `0 0 ${width} ${height}`

  const xGrid = dateTicks.map((t) =&amp;gt; (
    &amp;lt;g key={t.toString()}&amp;gt;
      &amp;lt;line
        stroke=&amp;quot;lightgrey&amp;quot;
        x1={dateScale(t)}
        y1={margin.top}
        x2={dateScale(t)}
        y2={height - margin.bottom}
        strokeDasharray={4}
      /&amp;gt;
      &amp;lt;text fill=&amp;quot;darkgrey&amp;quot; textAnchor=&amp;quot;middle&amp;quot; x={dateScale(t)} y={height}&amp;gt;
        {formatter(t)}
      &amp;lt;/text&amp;gt;
    &amp;lt;/g&amp;gt;
  ))

  const yGrid = tempTicks.map((t) =&amp;gt; (
    &amp;lt;g key={t.toString()}&amp;gt;
      &amp;lt;line
        stroke=&amp;quot;lightgrey&amp;quot;
        y1={tempScale(t)}
        x1={margin.left}
        y2={tempScale(t)}
        x2={width - margin.right}
        strokeDasharray={4}
      /&amp;gt;
      &amp;lt;text
        fill=&amp;quot;darkgrey&amp;quot;
        textAnchor=&amp;quot;end&amp;quot;
        y={tempScale(t)}
        x={margin.left - 5}
      &amp;gt;
        {t}
      &amp;lt;/text&amp;gt;
    &amp;lt;/g&amp;gt;
  ))

  return (
    &amp;lt;svg viewBox={viewBox}&amp;gt;
      &amp;lt;g&amp;gt;{xGrid}&amp;lt;/g&amp;gt;
      &amp;lt;g&amp;gt;{yGrid}&amp;lt;/g&amp;gt;
      &amp;lt;g&amp;gt;
        &amp;lt;path d={line} stroke=&amp;quot;steelblue&amp;quot; fill=&amp;quot;none&amp;quot; /&amp;gt;
      &amp;lt;/g&amp;gt;
    &amp;lt;/svg&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;And the resulting SVG will then look something like this:&lt;/p&gt;
&lt;p&gt;&amp;lt;svg viewBox=&amp;quot;0 0 600 400&amp;quot;&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;156.48148148148147&amp;quot;
y1=&amp;quot;20&amp;quot;
x2=&amp;quot;156.48148148148147&amp;quot;
y2=&amp;quot;380&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;156.48148148148147&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;
2011-10
&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;267.5925925925926&amp;quot;
y1=&amp;quot;20&amp;quot;
x2=&amp;quot;267.5925925925926&amp;quot;
y2=&amp;quot;380&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;267.5925925925926&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;
2011-10
&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;378.7037037037037&amp;quot;
y1=&amp;quot;20&amp;quot;
x2=&amp;quot;378.7037037037037&amp;quot;
y2=&amp;quot;380&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;378.7037037037037&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;
2011-10
&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;489.81481481481484&amp;quot;
y1=&amp;quot;20&amp;quot;
x2=&amp;quot;489.81481481481484&amp;quot;
y2=&amp;quot;380&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;489.81481481481484&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;
2011-10
&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;50&amp;quot;
y1=&amp;quot;20&amp;quot;
x2=&amp;quot;50&amp;quot;
y2=&amp;quot;380&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;50&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;2011-10&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;550&amp;quot;
y1=&amp;quot;20&amp;quot;
x2=&amp;quot;550&amp;quot;
y2=&amp;quot;380&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;550&amp;quot; y=&amp;quot;400&amp;quot;&amp;gt;2011-10&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;32&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;32&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;32&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;62.5&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;50&amp;quot;
y1=&amp;quot;62&amp;quot;
x2=&amp;quot;550&amp;quot;
y2=&amp;quot;62&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; x=&amp;quot;45&amp;quot; y=&amp;quot;62&amp;quot;&amp;gt;62&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;92&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;92&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;92&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;61.5&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;122&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;122&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;122&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;61&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;152&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;152&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;152&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;60.5&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;50&amp;quot;
y1=&amp;quot;182&amp;quot;
x2=&amp;quot;550&amp;quot;
y2=&amp;quot;182&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; x=&amp;quot;45&amp;quot; y=&amp;quot;182&amp;quot;&amp;gt;60&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;212&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;212&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;212&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;59.5&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;242&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;242&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;242&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;59&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;272&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;272&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;272&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;58.5&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
x1=&amp;quot;50&amp;quot;
y1=&amp;quot;302&amp;quot;
x2=&amp;quot;550&amp;quot;
y2=&amp;quot;302&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; x=&amp;quot;45&amp;quot; y=&amp;quot;302&amp;quot;&amp;gt;58&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;332&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;332&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;332&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;57.5&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g&amp;gt;
&amp;lt;line
stroke=&amp;quot;lightgrey&amp;quot;
y1=&amp;quot;362&amp;quot;
x1=&amp;quot;50&amp;quot;
y2=&amp;quot;362&amp;quot;
x2=&amp;quot;550&amp;quot;
stroke-dasharray=&amp;quot;4&amp;quot;
&amp;gt;&amp;lt;/line&amp;gt;
&amp;lt;text fill=&amp;quot;darkgrey&amp;quot; text-anchor=&amp;quot;end&amp;quot; y=&amp;quot;362&amp;quot; x=&amp;quot;45&amp;quot;&amp;gt;57&amp;lt;/text&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;path
d=&amp;quot;M50,20L105.55555555555554,188L161.11111111111111,236L216.66666666666666,254L272.22222222222223,260L327.77777777777777,362L383.3333333333333,380L438.88888888888886,374L494.4444444444444,380L550,176&amp;quot;
stroke=&amp;quot;steelblue&amp;quot;
fill=&amp;quot;none&amp;quot;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;lt;/path&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Logging Aliases for Javascript</title><link>https://nabeelvalley.co.za/blog/2021/02-11/javascript-quick-logger/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/02-11/javascript-quick-logger/</guid><description>Console and file-based logging alias for Javascript</description><pubDate>Tue, 02 Nov 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I often find myself writing a function to &lt;code&gt;JSON.stringify&lt;/code&gt; some data to log in either a pretty or flat structure&lt;/p&gt;
&lt;p&gt;It&apos;s just more of a convenience method, and it&apos;s pretty much the same as doing &lt;code&gt;console.log(JSON.stringify(data))&lt;/code&gt; and looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const _ = (data: any, pretty: boolean = false) =&amp;gt; {
  return console.log(JSON.stringify(data, null, pretty ? 2 : 0))
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then, when I need to log something:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;_(myData)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, if I want to pretty print the JSON&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;_(myData, true)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Javascript Range Function</title><link>https://nabeelvalley.co.za/blog/2021/29-10/javascript-range/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/29-10/javascript-range/</guid><description>Create ranges in Javascript</description><pubDate>Fri, 29 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Something i often find myself needing is a way to create a range in javascript, similar to what python has&lt;/p&gt;
&lt;p&gt;Here&apos;s a basic implementation of something that works like that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const range = (start, end, count, includeEnd = false) =&amp;gt; {
  const space = (end - start) / (count - includeEnd)
  return new Array(count).fill(0).map((_, i) =&amp;gt; start + i * space)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above will output something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const withoutEnd = range(20, 21, 5)
// withoutEnd === [ 20, 20.2, 20.4, 20.6, 20.8 ]

const withEnd = range(20, 21, 5, true)
// withEnd === [ 20, 20.25, 20.5, 20.75, 21 ]
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Template Literal Types with Typescript</title><link>https://nabeelvalley.co.za/blog/2021/16-08/typescript-template-literal-types/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/16-08/typescript-template-literal-types/</guid><description>Defining type combinations using Template Literal types</description><pubDate>Mon, 16 Aug 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Template literal types provide us a way to combine &lt;code&gt;string types&lt;/code&gt; or &lt;code&gt;enums&lt;/code&gt; in Typescript.&lt;/p&gt;
&lt;p&gt;In the below example, we can make use of a &lt;code&gt;string type&lt;/code&gt; called &lt;code&gt;Action&lt;/code&gt; and an &lt;code&gt;enum&lt;/code&gt; called &lt;code&gt;Resource&lt;/code&gt; to define a type which is a combination of an action combined with a resource&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Action = &apos;UPDATE&apos; | &apos;CREATE&apos; | &apos;DELETE&apos;

enum Resource {
  Person = &apos;Person&apos;,
  Product = &apos;Product&apos;,
  Sale = &apos;Sale&apos;,
}

// the `Lowercase` type concerts all string type options to lowercase
type ResourceAction = `${Resource}.${Action}`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Such that the &lt;code&gt;ResourceAction&lt;/code&gt; type is now defined as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ResourceAction =
  | &apos;Person.UPDATE&apos;
  | &apos;Person.CREATE&apos;
  | &apos;Person.DELETE&apos;
  | &apos;Product.UPDATE&apos;
  | &apos;Product.CREATE&apos;
  | &apos;Product.DELETE&apos;
  | &apos;Sale.UPDATE&apos;
  | &apos;Sale.CREATE&apos;
  | &apos;Sale.DELETE&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, if you&apos;re like me - you probably want your types to be consistent in some way. For this purpose, we can use the &lt;code&gt;Lowercase&lt;/code&gt; type as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ResourceActionLowercase = Lowercase&amp;lt;`${Resource}.${Action}`&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which results in the following types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type ResourceActionLowercase =
  | &apos;person.update&apos;
  | &apos;person.create&apos;
  | &apos;person.delete&apos;
  | &apos;product.update&apos;
  | &apos;product.create&apos;
  | &apos;product.delete&apos;
  | &apos;sale.update&apos;
  | &apos;sale.create&apos;
  | &apos;sale.delete&apos;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Building Serverless Apps using the Serverless Stack Framework</title><link>https://nabeelvalley.co.za/blog/2021/17-06/sst-framework/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/17-06/sst-framework/</guid><description>Build, debug, and deploy serverless applications on AWS using SST and VSCode</description><pubDate>Thu, 17 Jun 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Prior to doing any of the below you will require your &lt;code&gt;~/.aws/credentials&lt;/code&gt; file to be configured with the credentials for your AWS account&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Serverless Stack Framework&lt;/h2&gt;
&lt;p&gt;SST Framework is a framework built on top of CDK for working with Lambdas and other CDK constructs&lt;/p&gt;
&lt;p&gt;It provides easy CDK setups and a streamlined debug and deploy process and even has integration with the VSCode debugger to debug stacks on AWS&lt;/p&gt;
&lt;h3&gt;Init Project&lt;/h3&gt;
&lt;p&gt;To init a new project use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npx create-serverless-stack@latest my-sst-app --language typescript
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will create a Serverless Stack applocation using TypeScript&lt;/p&gt;
&lt;h3&gt;Run the App&lt;/h3&gt;
&lt;p&gt;You can run the created project in using the config defined in the &lt;code&gt;sst.json&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;my-sst-app&amp;quot;,
  &amp;quot;stage&amp;quot;: &amp;quot;dev&amp;quot;,
  &amp;quot;region&amp;quot;: &amp;quot;us-east-1&amp;quot;,
  &amp;quot;lint&amp;quot;: true,
  &amp;quot;typeCheck&amp;quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the following commands command will build then deploy a dev stack and allow you to interact with it via AWS/browser/Postman/etc.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm run start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, running using the above command will also start the application with hot reloading enabled so when you save files the corresponding AWS resources will be redeployed so you can continue testing&lt;/p&gt;
&lt;h3&gt;The Files&lt;/h3&gt;
&lt;p&gt;The application is structured like a relatively normal Lambda/CDK app with &lt;code&gt;lib&lt;/code&gt; which contains the following CDK code:&lt;/p&gt;
&lt;h4&gt;Stack&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;lib/index.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import MyStack from &apos;./MyStack&apos;
import * as sst from &apos;@serverless-stack/resources&apos;

export default function main(app: sst.App): void {
  // Set default runtime for all functions
  app.setDefaultFunctionProps({
    runtime: &apos;nodejs12.x&apos;,
  })

  new MyStack(app, &apos;my-stack&apos;)

  // Add more stacks
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lib/MyStack.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import * as sst from &apos;@serverless-stack/resources&apos;

export default class MyStack extends sst.Stack {
  constructor(scope: sst.App, id: string, props?: sst.StackProps) {
    super(scope, id, props)

    // Create the HTTP API
    const api = new sst.Api(this, &apos;Api&apos;, {
      routes: {
        &apos;GET /&apos;: &apos;src/lambda.handler&apos;,
      },
    })

    // Show API endpoint in output
    this.addOutputs({
      ApiEndpoint: api.httpApi.apiEndpoint,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And &lt;code&gt;src&lt;/code&gt; which contains the lambda code:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/lambda.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from &apos;aws-lambda&apos;

export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  return {
    statusCode: 200,
    headers: { &apos;Content-Type&apos;: &apos;text/plain&apos; },
    body: `Hello, World! Your request was received at ${event.requestContext.time}.`,
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Add a new Endpoint&lt;/h3&gt;
&lt;p&gt;Using the defined constructs it&apos;s really easy for us to add an additional endpoint:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/hello.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from &apos;aws-lambda&apos;

export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  const response = {
    data: &apos;Hello, World! This is another lambda but with JSON&apos;,
  }

  return {
    statusCode: 200,
    headers: { &apos;Content-Type&apos;: &apos;application/json&apos; },
    body: JSON.stringify(response),
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then in the stack we just update the routes:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lib/MyStack.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const api = new sst.Api(this, &apos;Api&apos;, {
  routes: {
    &apos;GET /&apos;: &apos;src/lambda.handler&apos;,
    &apos;GET /hello&apos;: &apos;src/hello.handler&apos;, // new endpoint handler
  },
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So that the full stack looks like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lib/MyStack.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import * as sst from &apos;@serverless-stack/resources&apos;

export default class MyStack extends sst.Stack {
  constructor(scope: sst.App, id: string, props?: sst.StackProps) {
    super(scope, id, props)

    // Create the HTTP API
    const api = new sst.Api(this, &apos;Api&apos;, {
      routes: {
        &apos;GET /&apos;: &apos;src/lambda.handler&apos;,
        &apos;GET /hello&apos;: &apos;src/hello.handler&apos;,
      },
    })

    // Show API endpoint in output
    this.addOutputs({
      ApiEndpoint: api.httpApi.apiEndpoint,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;VSCode Debugging&lt;/h3&gt;
&lt;p&gt;SST supports VSCode Debugging, all that&apos;s required is for you to create a &lt;code&gt;.vscode/launch.json&lt;/code&gt; filw with the following content:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.vscode/launch.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;version&amp;quot;: &amp;quot;0.2.0&amp;quot;,
  &amp;quot;configurations&amp;quot;: [
    {
      &amp;quot;name&amp;quot;: &amp;quot;Debug SST Start&amp;quot;,
      &amp;quot;type&amp;quot;: &amp;quot;node&amp;quot;,
      &amp;quot;request&amp;quot;: &amp;quot;launch&amp;quot;,
      &amp;quot;runtimeExecutable&amp;quot;: &amp;quot;npm&amp;quot;,
      &amp;quot;runtimeArgs&amp;quot;: [&amp;quot;start&amp;quot;],
      &amp;quot;port&amp;quot;: 9229,
      &amp;quot;skipFiles&amp;quot;: [&amp;quot;&amp;lt;node_internals&amp;gt;/**&amp;quot;]
    },
    {
      &amp;quot;name&amp;quot;: &amp;quot;Debug SST Tests&amp;quot;,
      &amp;quot;type&amp;quot;: &amp;quot;node&amp;quot;,
      &amp;quot;request&amp;quot;: &amp;quot;launch&amp;quot;,
      &amp;quot;runtimeExecutable&amp;quot;: &amp;quot;${workspaceRoot}/node_modules/.bin/sst&amp;quot;,
      &amp;quot;args&amp;quot;: [&amp;quot;test&amp;quot;, &amp;quot;--runInBand&amp;quot;, &amp;quot;--no-cache&amp;quot;, &amp;quot;--watchAll=false&amp;quot;],
      &amp;quot;cwd&amp;quot;: &amp;quot;${workspaceRoot}&amp;quot;,
      &amp;quot;protocol&amp;quot;: &amp;quot;inspector&amp;quot;,
      &amp;quot;console&amp;quot;: &amp;quot;integratedTerminal&amp;quot;,
      &amp;quot;internalConsoleOptions&amp;quot;: &amp;quot;neverOpen&amp;quot;,
      &amp;quot;env&amp;quot;: { &amp;quot;CI&amp;quot;: &amp;quot;true&amp;quot; },
      &amp;quot;disableOptimisticBPs&amp;quot;: true
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will then allow you to run &lt;code&gt;Debug SST Start&lt;/code&gt; which will configure the AWS resources using the &lt;code&gt;npm start&lt;/code&gt; command and connect the debugger to the instance so you can debug your functions locally as well as make use of the automated function deployment&lt;/p&gt;
&lt;h3&gt;Add a DB&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;From &lt;a href=&quot;https://serverless-stack.com/examples/how-to-create-a-crud-api-with-serverless-using-dynamodb.html&quot;&gt;these docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can define our table using the &lt;code&gt;sst.Table&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const table = new sst.Table(this, &apos;Notes&apos;, {
  fields: {
    userId: sst.TableFieldType.STRING,
    noteId: sst.TableFieldType.NUMBER,
  },
  primaryIndex: {
    partitionKey: &apos;userId&apos;,
    sortKey: &apos;noteId&apos;,
  },
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we can add some endpoint definitions for the functions we&apos;ll create as well as access to the table name via the environment:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const api = new sst.Api(this, &apos;Api&apos;, {
  defaultFunctionProps: {
    timeout: 60, // increase timeout so we can debug
    environment: {
      tableName: table.dynamodbTable.tableName,
    },
  },
  routes: {
    // .. other routes
    &apos;GET  /notes&apos;: &apos;src/notes/getAll.handler&apos;, // userId in query
    &apos;GET  /notes/{noteId}&apos;: &apos;src/notes/get.handler&apos;, // userId in query
    &apos;POST /notes&apos;: &apos;src/notes/create.handler&apos;,
  },
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And lastly we can grant the permissions to our &lt;code&gt;api&lt;/code&gt; to access the &lt;code&gt;table&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;api.attachPermissions([table])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding the above to the &lt;code&gt;MyStack.ts&lt;/code&gt; file results in the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import * as sst from &apos;@serverless-stack/resources&apos;

export default class MyStack extends sst.Stack {
  constructor(scope: sst.App, id: string, props?: sst.StackProps) {
    super(scope, id, props)

    const table = new sst.Table(this, &apos;Notes&apos;, {
      fields: {
        userId: sst.TableFieldType.STRING,
        noteId: sst.TableFieldType.STRING,
      },
      primaryIndex: {
        partitionKey: &apos;userId&apos;,
        sortKey: &apos;noteId&apos;,
      },
    })

    // Create the HTTP API
    const api = new sst.Api(this, &apos;Api&apos;, {
      defaultFunctionProps: {
        timeout: 60, // increase timeout so we can debug
        environment: {
          tableName: table.dynamodbTable.tableName,
        },
      },
      routes: {
        // .. other routes
        &apos;GET  /notes&apos;: &apos;src/notes/getAll.handler&apos;, // userId in query
        &apos;GET  /notes/{noteId}&apos;: &apos;src/notes/get.handler&apos;, // userId in query
        &apos;POST /notes&apos;: &apos;src/notes/create.handler&apos;,
      },
    })

    api.attachPermissions([table])

    // Show API endpoint in output
    this.addOutputs({
      ApiEndpoint: api.httpApi.apiEndpoint,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before we go any further, we need to install some dependencies in our app, particularly &lt;code&gt;uuid&lt;/code&gt; for generating unique id&apos;s for notes, we can install a dependency with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm install uuid
npm install aws-sdk
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Define Common Structures&lt;/h3&gt;
&lt;p&gt;We&apos;ll also create some general helper functions for returning responses of different types, you can view the details for their files below but these just wrap the response in a status and header as well as stringify the body&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/responses/successResponse.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const successResponse = &amp;lt;T&amp;gt;(item: T) =&amp;gt; {
  return {
    statusCode: 200,
    headers: { &apos;Content-Type&apos;: &apos;application/json&apos; },
    body: JSON.stringify(item),
  }
}

export default successResponse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;src/responses/badResuestsResponse.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const badRequestResponse = (msg: string) =&amp;gt; {
  return {
    statusCode: 400,
    headers: { &apos;Content-Type&apos;: &apos;text/plain&apos; },
    body: msg,
  }
}

export default badRequestResponse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;src/responses/internalErrorResponse.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const internalErrorResponse = (msg: string) =&amp;gt; {
  console.error(msg)
  return {
    statusCode: 500,
    headers: { &apos;Content-Type&apos;: &apos;text/plain&apos; },
    body: &apos;internal error&apos;,
  }
}

export default internalErrorResponse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we&apos;ve also got a &lt;code&gt;Note&lt;/code&gt; type which will be the data that gets stored/retreived:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/notes/Note.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;type Note = {
  userId: string
  noteId: string
  content?: string
  createdAt: number
}

export default Note
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Access DB&lt;/h3&gt;
&lt;p&gt;Once we&apos;ve got a DB table defined as above, we can then access the table to execute different queries&lt;/p&gt;
&lt;p&gt;We would create a DB object instance using:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const db = new DynamoDB.DocumentClient()
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Create&lt;/h4&gt;
&lt;p&gt;A &lt;code&gt;create&lt;/code&gt; is the simplest one of the database functions for us to implement, this uses the &lt;code&gt;db.put&lt;/code&gt; function with the &lt;code&gt;Item&lt;/code&gt; to save which is of type &lt;code&gt;Note&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const create = async (tableName: string, item: Note) =&amp;gt; {
  await db.put({ TableName: tableName, Item: item }).promise()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Get&lt;/h4&gt;
&lt;p&gt;We can implement a &lt;code&gt;getOne&lt;/code&gt; function by using &lt;code&gt;db.get&lt;/code&gt; and providing the full &lt;code&gt;Key&lt;/code&gt; consisting of the &lt;code&gt;userId&lt;/code&gt; and &lt;code&gt;noteId&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getOne = async (tableName: string, noteId: string, userId: string) =&amp;gt; {
  const result = await db
    .get({
      TableName: tableName,
      Key: {
        userId: userId,
        noteId: noteId,
      },
    })
    .promise()

  return result.Item
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;GetAll&lt;/h4&gt;
&lt;p&gt;We can implement a &lt;code&gt;getByUserId&lt;/code&gt; function which will make use of &lt;code&gt;db.query&lt;/code&gt; and use the &lt;code&gt;ExpressionAttributeValues&lt;/code&gt; to populate the &lt;code&gt;KeyConditionExpression&lt;/code&gt; as seen below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const getByUserId = async (tableName: string, userId: string) =&amp;gt; {
  const result = await db
    .query({
      TableName: tableName,
      KeyConditionExpression: &apos;userId = :userId&apos;,
      ExpressionAttributeValues: {
        &apos;:userId&apos;: userId,
      },
    })
    .promise()

  return result.Items
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Define Lambdas&lt;/h3&gt;
&lt;p&gt;Now that we know how to write data to Dynamo, we can implement the following files for the endpoints we defined above:&lt;/p&gt;
&lt;h4&gt;Create&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;src/notes/create.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from &apos;aws-lambda&apos;
import { DynamoDB } from &apos;aws-sdk&apos;
import { v1 } from &apos;uuid&apos;
import internalErrorResponse from &apos;../responses/internalErrorResponse&apos;
import successResponse from &apos;../responses/successResponse&apos;
import badRequestResponse from &apos;../responses/badRequestResponse&apos;
import Note from &apos;./Note&apos;

const db = new DynamoDB.DocumentClient()

const toItem = (data: string, content: string): Note =&amp;gt; {
  return {
    userId: data,
    noteId: v1(),
    content: content,
    createdAt: Date.now(),
  }
}

const parseBody = (event: APIGatewayProxyEventV2) =&amp;gt; {
  const data = JSON.parse(event.body || &apos;{}&apos;)

  return {
    userId: data.userId,
    content: data.content,
  }
}

const isValid = (data: Partial&amp;lt;Note&amp;gt;) =&amp;gt;
  typeof data.userId !== &apos;undefined&apos; &amp;amp;&amp;amp; typeof data.content !== &apos;undefined&apos;

const create = async (tableName: string, item: Note) =&amp;gt; {
  await db.put({ TableName: tableName, Item: item }).promise()
}

export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  if (typeof process.env.tableName === &apos;undefined&apos;)
    return internalErrorResponse(&apos;tableName is undefined&apos;)

  const tableName = process.env.tableName
  const data = parseBody(event)

  if (!isValid(data))
    return badRequestResponse(&apos;userId and content are required&apos;)

  const item = toItem(data.userId, data.content)
  await create(tableName, item)

  return successResponse(item)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Get&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;src/notes/get.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from &apos;aws-lambda&apos;
import { DynamoDB } from &apos;aws-sdk&apos;
import badRequestResponse from &apos;../responses/badRequestResponse&apos;
import internalErrorResponse from &apos;../responses/internalErrorResponse&apos;
import successResponse from &apos;../responses/successResponse&apos;

type RequestParams = {
  noteId?: string
  userId?: string
}

const db = new DynamoDB.DocumentClient()

const parseBody = (event: APIGatewayProxyEventV2): RequestParams =&amp;gt; {
  const pathData = event.pathParameters
  const queryData = event.queryStringParameters

  return {
    noteId: pathData?.noteId,
    userId: queryData?.userId,
  }
}

const isValid = (data: RequestParams) =&amp;gt;
  typeof data.noteId !== &apos;undefined&apos; &amp;amp;&amp;amp; typeof data.userId !== &apos;undefined&apos;

const getOne = async (tableName: string, noteId: string, userId: string) =&amp;gt; {
  const result = await db
    .get({
      TableName: tableName,
      Key: {
        userId: userId,
        noteId: noteId,
      },
    })
    .promise()

  return result.Item
}

export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  const data = parseBody(event)

  if (typeof process.env.tableName === &apos;undefined&apos;)
    return internalErrorResponse(&apos;tableName is undefined&apos;)

  const tableName = process.env.tableName

  if (!isValid(data))
    return badRequestResponse(
      &apos;noteId is required in path, userId is required in query&apos;
    )

  const items = await getOne(
    tableName,
    data.noteId as string,
    data.userId as string
  )

  return successResponse(items)
}
import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from &apos;aws-lambda&apos;
import { DynamoDB } from &apos;aws-sdk&apos;
import badRequestResponse from &apos;../responses/badRequestResponse&apos;
import internalErrorResponse from &apos;../responses/internalErrorResponse&apos;
import successResponse from &apos;../responses/successResponse&apos;

type RequestParams = {
  noteId?: string
  userId?: string
}

const db = new DynamoDB.DocumentClient()

const parseBody = (event: APIGatewayProxyEventV2): RequestParams =&amp;gt; {
  const pathData = event.pathParameters
  const queryData = event.queryStringParameters

  return {
    noteId: pathData?.noteId,
    userId: queryData?.userId,
  }
}

const isValid = (data: RequestParams) =&amp;gt;
  typeof data.noteId !== &apos;undefined&apos; &amp;amp;&amp;amp; typeof data.userId !== &apos;undefined&apos;

const getOne = async (tableName: string, noteId: string, userId: string) =&amp;gt; {
  const result = await db
    .get({
      TableName: tableName,
      Key: {
        userId: userId,
        noteId: noteId,
      },
    })
    .promise()

  return result.Item
}

export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  const data = parseBody(event)

  if (typeof process.env.tableName === &apos;undefined&apos;)
    return internalErrorResponse(&apos;tableName is undefined&apos;)

  const tableName = process.env.tableName

  if (!isValid(data))
    return badRequestResponse(
      &apos;noteId is required in path, userId is required in query&apos;
    )

  const items = await getOne(
    tableName,
    data.noteId as string,
    data.userId as string
  )

  return successResponse(items)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;GetAll&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;src/notes/getAll.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from &apos;aws-lambda&apos;
import { DynamoDB } from &apos;aws-sdk&apos;
import badRequestResponse from &apos;../responses/badRequestResponse&apos;
import internalErrorResponse from &apos;../responses/internalErrorResponse&apos;
import successResponse from &apos;../responses/successResponse&apos;

type PathParams = {
  userId?: string
}

const db = new DynamoDB.DocumentClient()

const parseBody = (event: APIGatewayProxyEventV2): PathParams =&amp;gt; {
  const data = event.queryStringParameters

  return {
    userId: data?.userId,
  }
}

const isValid = (data: PathParams) =&amp;gt; typeof data.userId !== &apos;undefined&apos;

const getByUserId = async (tableName: string, userId: string) =&amp;gt; {
  const result = await db
    .query({
      TableName: tableName,
      KeyConditionExpression: &apos;userId = :userId&apos;,
      ExpressionAttributeValues: {
        &apos;:userId&apos;: userId,
      },
    })
    .promise()

  return result.Items
}

export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  const data = parseBody(event)

  if (typeof process.env.tableName === &apos;undefined&apos;)
    return internalErrorResponse(&apos;tableName is undefined&apos;)

  const tableName = process.env.tableName

  if (!isValid(data)) return badRequestResponse(&apos;userId is required in query&apos;)

  const items = await getByUserId(tableName, data.userId as string)

  return successResponse(items)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Testing&lt;/h4&gt;
&lt;p&gt;Once we&apos;ve got all the above completed, we can actually test our endpoints and create and read back data&lt;/p&gt;
&lt;p&gt;&lt;code&gt;create&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;POST https://AWS_ENDPOINT_HERE/notes

{
  &amp;quot;userId&amp;quot;: &amp;quot;USER_ID&amp;quot;,
  &amp;quot;content&amp;quot;: &amp;quot;Hello world&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which responds with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;200

{
  &amp;quot;content&amp;quot;: &amp;quot;Hello world&amp;quot;,
  &amp;quot;createdAt&amp;quot;: 1619177078298,
  &amp;quot;noteId&amp;quot;: &amp;quot;NOTE_ID_UUID&amp;quot;,
  &amp;quot;userId&amp;quot;: &amp;quot;USER_ID&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;get&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;GET https://AWS_ENDPOINT_HERE/notes/NOTE_ID_UUID?userId=USER_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;200

{
  &amp;quot;content&amp;quot;: &amp;quot;Hello world&amp;quot;,
  &amp;quot;createdAt&amp;quot;: 1619177078298,
  &amp;quot;noteId&amp;quot;: &amp;quot;NOTE_ID_UUID&amp;quot;,
  &amp;quot;userId&amp;quot;: &amp;quot;USER_ID&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getAll&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;GET htttps://AWS_ENDPOINT_HERE/notes?userId=USER_ID
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-http&quot;&gt;200

[
  {
    &amp;quot;content&amp;quot;: &amp;quot;Hello world&amp;quot;,
    &amp;quot;createdAt&amp;quot;: 1619177078298,
    &amp;quot;noteId&amp;quot;: &amp;quot;NOTE_ID_UUID&amp;quot;,
    &amp;quot;userId&amp;quot;: &amp;quot;USER_ID&amp;quot;
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Creating Notes Using a Queue&lt;/h3&gt;
&lt;p&gt;When working with microservices a common pattern is to use a message queue for any operations that can happen in an asynchronous fashion, we can create an SQS queue which we can use to stage messages and then separately save them at a rate that we&apos;re able to process them&lt;/p&gt;
&lt;p&gt;In order to make this kind of logic we&apos;re going to break up our &lt;code&gt;create&lt;/code&gt; data flow - a the moment it&apos;s this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lambda -&amp;gt; dynamo
return &amp;lt;-
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&apos;re going to turn it into this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lambda1 -&amp;gt; sqs
 return &amp;lt;-

          sqs -&amp;gt; lambda2 -&amp;gt; dynamo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This kind of pattern becomes especially useful if we&apos;re doing a lot more stuff with the data other than just the single DB operation and also allows us to retry things like saving to the DB if we have errors, etc.&lt;/p&gt;
&lt;p&gt;A more complex data flow could look something like this (not what we&apos;re implementing):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lambda1 -&amp;gt; sqs
 return &amp;lt;-

           sqs -&amp;gt; lambda2 -&amp;gt; dynamo // save to db
               -&amp;gt; lambda3 -&amp;gt; s3     // generate a report
           sqs &amp;lt;-

           sqs -&amp;gt; lambda4           // send an email
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Create Queue&lt;/h4&gt;
&lt;p&gt;SST provides us with the &lt;code&gt;sst.Queue&lt;/code&gt; class that we can use for this purpose&lt;/p&gt;
&lt;p&gt;To create a Queue you can use the following in stack:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const queue = new sst.Queue(this, &apos;NotesQueue&apos;, {
  consumer: &apos;src/consumers/createNote.handler&apos;,
})

queue.attachPermissions([table])
queue.consumerFunction?.addEnvironment(
  &apos;tableName&apos;,
  table.dynamodbTable.tableName
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;queue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Give the queue permission to access the &lt;code&gt;table&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;tableName&lt;/code&gt; environment variable to the &lt;code&gt;queue&lt;/code&gt;&apos;s &lt;code&gt;consumerFunction&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We will also need to grant permissions to the API to access the &lt;code&gt;queue&lt;/code&gt; so that our &lt;code&gt;create&lt;/code&gt; handler is able to add messages to the &lt;code&gt;queue&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;api.attachPermissions([table, queue])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which means our Stack now looks like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lib/MyStack.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import * as sst from &apos;@serverless-stack/resources&apos;

export default class MyStack extends sst.Stack {
  constructor(scope: sst.App, id: string, props?: sst.StackProps) {
    super(scope, id, props)

    const table = new sst.Table(this, &apos;Notes&apos;, {
      fields: {
        userId: sst.TableFieldType.STRING,
        noteId: sst.TableFieldType.STRING,
      },
      primaryIndex: {
        partitionKey: &apos;userId&apos;,
        sortKey: &apos;noteId&apos;,
      },
    })

    const queue = new sst.Queue(this, &apos;NotesQueue&apos;, {
      consumer: &apos;src/consumers/createNote.handler&apos;,
    })

    queue.attachPermissions([table])
    queue.consumerFunction?.addEnvironment(
      &apos;tableName&apos;,
      table.dynamodbTable.tableName
    )

    // Create the HTTP API
    const api = new sst.Api(this, &apos;Api&apos;, {
      defaultFunctionProps: {
        timeout: 60, // increase timeout so we can debug
        environment: {
          tableName: table.dynamodbTable.tableName,
          queueUrl: queue.sqsQueue.queueUrl,
        },
      },
      routes: {
        &apos;GET  /&apos;: &apos;src/lambda.handler&apos;,
        &apos;GET  /hello&apos;: &apos;src/hello.handler&apos;,
        &apos;GET  /notes&apos;: &apos;src/notes/getAll.handler&apos;,
        &apos;POST /notes&apos;: &apos;src/notes/create.handler&apos;,
        &apos;GET  /notes/{noteId}&apos;: &apos;src/notes/get.handler&apos;,
      },
    })

    api.attachPermissions([table, queue])

    // Show API endpoint in output
    this.addOutputs({
      ApiEndpoint: api.httpApi.apiEndpoint,
    })
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Update the Create Handler&lt;/h4&gt;
&lt;p&gt;Since we plan to create notes via a queue we will update our &lt;code&gt;create&lt;/code&gt; function in the handler to create a new message in the &lt;code&gt;queue&lt;/code&gt;, this is done using the &lt;code&gt;SQS&lt;/code&gt; class from &lt;code&gt;aws-sdk&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/notes/create.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { SQS } from &apos;aws-sdk&apos;

const queue = new SQS()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once we&apos;ve got our instance, the &lt;code&gt;create&lt;/code&gt; function is done by means of the &lt;code&gt;queue.sendMessage&lt;/code&gt; function:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/notes/create.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const create = async (queueUrl: string, item: Note) =&amp;gt; {
  return await queue
    .sendMessage({
      QueueUrl: queueUrl,
      DelaySeconds: 0,
      MessageBody: JSON.stringify(item),
    })
    .promise()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly, our &lt;code&gt;handler&lt;/code&gt; remains mostly the same with the exception of some additional validation to check that we have the &lt;code&gt;queue&lt;/code&gt; connection information in the environment:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/notes/create.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  // pre-save validation
  if (typeof process.env.queueUrl === &apos;undefined&apos;)
    return internalErrorResponse(&apos;queueUrl is undefined&apos;)

  const queueUrl = process.env.queueUrl

  const data = parseBody(event)

  if (!isValid(data))
    return badRequestResponse(&apos;userId and content are required&apos;)

  // save process
  const item = toItem(data.userId, data.content)
  const creatresult = await create(queueUrl, item)

  if (!creatresult.MessageId) internalErrorResponse(&apos;MessageId is undefined&apos;)

  return successResponse(item)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Implementing the above into the &lt;code&gt;create&lt;/code&gt; handler means that our &lt;code&gt;create.ts&lt;/code&gt; file now looks like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/notes/create.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { APIGatewayProxyEventV2, APIGatewayProxyHandlerV2 } from &apos;aws-lambda&apos;
import { v1 } from &apos;uuid&apos;
import internalErrorResponse from &apos;../responses/internalErrorResponse&apos;
import successResponse from &apos;../responses/successResponse&apos;
import badRequestResponse from &apos;../responses/badRequestResponse&apos;
import Note from &apos;./Note&apos;
import { SQS } from &apos;aws-sdk&apos;

const queue = new SQS()

// helper functions start

const toItem = (data: string, content: string): Note =&amp;gt; {
  return {
    userId: data,
    noteId: v1(),
    content: content,
    createdAt: Date.now(),
  }
}

const parseBody = (event: APIGatewayProxyEventV2) =&amp;gt; {
  const data = JSON.parse(event.body || &apos;{}&apos;)

  return {
    userId: data.userId,
    content: data.content,
  }
}

const isValid = (data: Partial&amp;lt;Note&amp;gt;) =&amp;gt;
  typeof data.userId !== &apos;undefined&apos; &amp;amp;&amp;amp; typeof data.content !== &apos;undefined&apos;

// helper functions end

const create = async (queueUrl: string, item: Note) =&amp;gt; {
  return await queue
    .sendMessage({
      QueueUrl: queueUrl,
      DelaySeconds: 0,
      MessageBody: JSON.stringify(item),
    })
    .promise()
}

export const handler: APIGatewayProxyHandlerV2 = async (
  event: APIGatewayProxyEventV2
) =&amp;gt; {
  // pre-save validation
  if (typeof process.env.queueUrl === &apos;undefined&apos;)
    return internalErrorResponse(&apos;queueUrl is undefined&apos;)

  const queueUrl = process.env.queueUrl

  const data = parseBody(event)

  if (!isValid(data))
    return badRequestResponse(&apos;userId and content are required&apos;)

  // save process
  const item = toItem(data.userId, data.content)
  const creatresult = await create(queueUrl, item)

  if (!creatresult.MessageId) internalErrorResponse(&apos;MessageId is undefined&apos;)

  return successResponse(item)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Add Queue-Based Create Handler&lt;/h4&gt;
&lt;p&gt;Now that we&apos;ve updated our logic to save the notes into the &lt;code&gt;queue&lt;/code&gt;, we need to add the logic for the &lt;code&gt;src/consumers/createNote.handler&lt;/code&gt; consumer function as we specified above, this handler will be sent an &lt;code&gt;SQSEvent&lt;/code&gt; and will make use of the DynamoDB Table we gave it permissions to use&lt;/p&gt;
&lt;p&gt;First, we take the &lt;code&gt;create&lt;/code&gt; function that was previously on the &lt;code&gt;create.ts&lt;/code&gt; file for saving to the DB:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/consumers/createNote.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { DynamoDB } from &apos;aws-sdk&apos;

const db = new DynamoDB.DocumentClient()

const create = async (tableName: string, item: Note) =&amp;gt; {
  const createResult = await db
    .put({ TableName: tableName, Item: item })
    .promise()
  if (!createResult) throw new Error(&apos;create failed&apos;)

  return createResult
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&apos;ll also need a function for parsing the &lt;code&gt;SQSRecord&lt;/code&gt; object into a &lt;code&gt;Note&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/consumers/createNote.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const parseBody = (record: SQSRecord): Note =&amp;gt; {
  const { noteId, userId, content, createdAt } = JSON.parse(record.body) as Note

  // do this to ensure we only extract information we need
  return {
    noteId,
    userId,
    content,
    createdAt,
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And finally we consume the above through the &lt;code&gt;handler&lt;/code&gt;, you can see in the below code that we are iterating over the &lt;code&gt;event.Records&lt;/code&gt; object, this is because the &lt;code&gt;SQSEvent&lt;/code&gt; adds each new event into this array, the reason for this is because we can also specify batching into our Queue so that the handler is only triggered after &lt;code&gt;n&lt;/code&gt; events instead of each time, and though this isn&apos;t happening in our case, we still should handle this for our handler:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/consumers/createNote.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export const handler: SQSHandler = async (event) =&amp;gt; {
  // pre-save environment check
  if (typeof process.env.tableName === &apos;undefined&apos;)
    throw new Error(&apos;tableName is undefined&apos;)

  const tableName = process.env.tableName

  for (let i = 0; i &amp;lt; event.Records.length; i++) {
    const r = event.Records[i]
    const item = parseBody(r)
    console.log(item)

    const result = await create(tableName, item)
    console.log(result)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting all the above together our &lt;code&gt;createNote.ts&lt;/code&gt; file now has the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { SQSHandler, SQSRecord } from &apos;aws-lambda&apos;
import Note from &apos;../notes/Note&apos;
import { DynamoDB } from &apos;aws-sdk&apos;

const db = new DynamoDB.DocumentClient()

const create = async (tableName: string, item: Note) =&amp;gt; {
  const createResult = await db
    .put({ TableName: tableName, Item: item })
    .promise()
  if (!createResult) throw new Error(&apos;create failed&apos;)

  return createResult
}

const parseBody = (record: SQSRecord): Note =&amp;gt; {
  const { noteId, userId, content, createdAt } = JSON.parse(record.body) as Note

  // do this to ensure we only extract information we need
  return {
    noteId,
    userId,
    content,
    createdAt,
  }
}

export const handler: SQSHandler = async (event) =&amp;gt; {
  if (typeof process.env.tableName === &apos;undefined&apos;)
    throw new Error(&apos;tableName is undefined&apos;)

  const tableName = process.env.tableName

  for (let i = 0; i &amp;lt; event.Records.length; i++) {
    const r = event.Records[i]
    const item = parseBody(r)
    console.log(item)

    const result = await create(tableName, item)
    console.log(result)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This completes the implementation of the asynchronous saving mechanism for notes. As far as a consumer of our API is concerned, nothing has changed and they will still be able to use the API exactly as we had in the &lt;a href=&quot;#testing&quot;&gt;Testing section above&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Deploy&lt;/h2&gt;
&lt;p&gt;Thus far, we&apos;ve just been running our API in &lt;code&gt;debug&lt;/code&gt; mode via the &lt;code&gt;npm run start&lt;/code&gt; command, while useful for testing this adds a lot of code to make debugging possible, and isn&apos;t something we&apos;d want in our final deployed code&lt;/p&gt;
&lt;p&gt;Deploying using &lt;code&gt;sst&lt;/code&gt; is still very easy, all we need to do is run the &lt;code&gt;npm run deploy&lt;/code&gt; command and this will update our lambda to use a production build of the code instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm run deploy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Teardown&lt;/h2&gt;
&lt;p&gt;Lastly, the &lt;code&gt;sst&lt;/code&gt; CLI also provides us with a function to teardown our &lt;code&gt;start&lt;/code&gt;/&lt;code&gt;deploy&lt;/code&gt; code. So once you&apos;re done playing around you can use this to teardown all your deployed services:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;npm run remove
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that running the &lt;code&gt;remove&lt;/code&gt; command will not delete the DB tables, you will need to do this manually&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Multi-module Python project using an __init__.py file</title><link>https://nabeelvalley.co.za/blog/2021/06-05/multi-module-python-projects/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/06-05/multi-module-python-projects/</guid><description>How to work with modules and handle the &apos;ModuleNotFoundError: No module named ...&apos; error</description><pubDate>Thu, 06 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When creating a multi-module project for Python, especially when coming from another language ecosystem, you may encounter issues importing code from other files, let&apos;s take a look at this&lt;/p&gt;
&lt;h2&gt;The Modules&lt;/h2&gt;
&lt;p&gt;In our project, we&apos;ve got the following files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package1
  |- module1.py
package2
  |- namespace2
       |- module2.py
main.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s say each of our modules export a function, here&apos;s the code for them:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;package1/module1.py&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-py&quot;&gt;def hello_p1_m1():
  return &amp;quot;hello&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;package2/subpackage1/module1.py&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-py&quot;&gt;def hello_p2_s1_m1():
  return &amp;quot;hello&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Main&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve got our files with their functions separated, we try using them from the &lt;code&gt;main.py&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-py&quot;&gt;import package1.module1 as p1m1
import package2.namespace1.module1 as p2s1m1

print(p1m1.hello_p1_m1())
print(p2n1m1.hello_p2_s1_m1())
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Error&lt;/h2&gt;
&lt;p&gt;Now, we try to run this using &lt;code&gt;python&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;python main.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we get the following error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Traceback (most recent call last):
  File &amp;quot;main.py&amp;quot;, line 1, in &amp;lt;module&amp;gt;
    import package1.module1 as p1m1
ImportError: No module named package1.module1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Solution&lt;/h2&gt;
&lt;p&gt;Now, this can be pretty annoying, but the solution is very simple. Python identifies a &lt;code&gt;module&lt;/code&gt; as a single file, and the assumption that leads to the issue above is that we assume a &lt;code&gt;package&lt;/code&gt; has the same convention of just being a directory&lt;/p&gt;
&lt;p&gt;However, a &lt;code&gt;packgage&lt;/code&gt; requires an &lt;code&gt;__init__.py&lt;/code&gt; file to be defined so that they are recognized correctly&lt;/p&gt;
&lt;p&gt;So, we need to add two files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;package1/__init__.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;package2/subpackage1/__init__.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, these files are completely empty, and only serve as information. Note that we don&apos;t need to include a file in &lt;code&gt;package2&lt;/code&gt; directly as this directory does not contain any modules within it so is not really a package in itself and is simply a wrapper &lt;code&gt;subpackage1&lt;/code&gt;&lt;/p&gt;
</content:encoded></item><item><title>XUnit with F#</title><link>https://nabeelvalley.co.za/blog/2021/10-04/xunit-with-fsharp/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/10-04/xunit-with-fsharp/</guid><description>Configuring and Testing F# applications using XUnit and the .NET Core CLI</description><pubDate>Sat, 10 Apr 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;An important part of writing any software is testing. Unit testing is an automated testing method in which we test individual components of our software to verify that their behaviour aligns with our expectations&lt;/p&gt;
&lt;p&gt;This post will take a look at the process of setting up a new F# library and two methods of configuring XUnit to test your project&apos;s code&lt;/p&gt;
&lt;h2&gt;Create a Project&lt;/h2&gt;
&lt;p&gt;Before we can start testing we need a project that we can run tests on&lt;/p&gt;
&lt;p&gt;First, we&apos;re going to create a folder that we can work in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkdir MyProject
cd MyProject
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can use the following command to create a new project in our &lt;code&gt;MyProject&lt;/code&gt; directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet new classlib -lang=f# -o MyProject.Lib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The project that we created will contain the following &lt;code&gt;Library.ts&lt;/code&gt; file, this is the file that we&apos;ll write tests for. First, we want to update the &lt;code&gt;hello&lt;/code&gt; function so that it returns a formatted string:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MyProject.Lib/Library.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;namespace MyProject.Lib

module Say =
    let hello name =
        sprintf &amp;quot;Hello %s&amp;quot; name
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Adding Tests&lt;/h2&gt;
&lt;p&gt;Depending on our preferred project structure we can either:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Add tests in a separate project&lt;/li&gt;
&lt;li&gt;Add test files alongside lib files&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Method 1: Create Tests in Separate Project&lt;/h3&gt;
&lt;p&gt;The standard method of .NET unit testing with XUnit is to make use of separate Project and Test solutions, so a normal test setup would look something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MyProject.Lib
MyProject.Lib.Tests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To add an new XUnit test project you can run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet new xunit -lang=f# -o MyProject.Tests
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, so we&apos;re able to test the code from &lt;code&gt;MyProject.Lib&lt;/code&gt;, we need to add a reference to it from the Test project we just created:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet add MyProject.Tests reference MyProject.Lib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can create a file in our test project called &lt;code&gt;LibraryTests.fs&lt;/code&gt; which will contain our test code which we will cover in the last section, as well as adding a reference to this file in the &lt;code&gt;MyProject.Tests.fsproj&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MyProject.Tests.fsproj&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;...
  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Tests.fs&amp;quot; /&amp;gt;
    &amp;lt;!-- Add the next line --&amp;gt;
    &amp;lt;Compile Include=&amp;quot;LibraryTests.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Program.fs&amp;quot; /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Method 2: Create Tests Alongside Lib Files&lt;/h3&gt;
&lt;p&gt;The second method I&apos;m going to discuss is keeping our &lt;code&gt;test.fs&lt;/code&gt; files alongside the code that the file is testing. The structure of our project is something more like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;MyProject.Lib
|- Library.fs
|- Library.test.fs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Overall I find this more manageable is the way I keep my test code in other languages and frameworks as well&lt;/p&gt;
&lt;p&gt;To implement this method we need to add some dependencies to our project&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd MyProject.Lib
dotnet add package Microsoft.NET.Test.Sdk
dotnet add package xunit
dotnet add package xunit.runner.visualstudio
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can create a file in our project called &lt;code&gt;Library.test.fs&lt;/code&gt; which will contain our test code which we will cover next, as well as a reference to this file in the &lt;code&gt;MyProject.Lib.fsproj&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MyProject.Lib.fsproj&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;...
  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Library.fs&amp;quot; /&amp;gt;
    &amp;lt;!-- Add the next line --&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Library.test.fs&amp;quot; /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&apos;s important to note that this file must be added below the &lt;code&gt;Library.fs&lt;/code&gt; file as it will reference it for tests to run&lt;/p&gt;
&lt;h2&gt;Test Files&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;More detailed information on XUnit can be found in &lt;a href=&quot;/docs/dotnet/unit-testing-intro&quot;&gt;Unit Testing notes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Since we&apos;ve configured XUnit it may be useful to understand how these tests work in the context of F#. XUnit tests are organized into modules. Regardless of which of the two methods above you&apos;re using the test files work the same&lt;/p&gt;
&lt;p&gt;Generally, a test file will contain:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A top-level module definition&lt;/li&gt;
&lt;li&gt;&lt;code&gt;open&lt;/code&gt; statements to import XUnit&lt;/li&gt;
&lt;li&gt;Test functions annotated with &lt;code&gt;Fact&lt;/code&gt; or &lt;code&gt;Theory&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;XUnit tests can be broken into 2 types:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Single-case tests without input parameters inputs are labelled &lt;code&gt;Fact&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Multi-case tests which make use of input parameters are labelled &lt;code&gt;Theory&lt;/code&gt; and use &lt;code&gt;InlineData&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Fact&lt;/h3&gt;
&lt;p&gt;Let&apos;s add the following content into our test file into one that tests the &lt;code&gt;hello&lt;/code&gt; function from our &lt;code&gt;Lib&lt;/code&gt; code with the input &lt;code&gt;&amp;quot;Name&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LibraryTests.fs/Library.test.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;module LibraryTests

open Xunit
open MyProject.Lib.Say

[&amp;lt;Fact&amp;gt;]
let ``Say.hello -&amp;gt; &amp;quot;Hello name&amp;quot; `` () =
    let name = &amp;quot;name&amp;quot;
    let expected = &amp;quot;Hello name&amp;quot;

    let result = hello name

    Assert.Equal(expected, result)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;F# allows us to name our functions using special characters provided they&apos;re enclosed in backticks as seen above. Naming test functions this way allows them to be more discriptive than more traditional variable names&lt;/p&gt;
&lt;p&gt;Additionally, there&apos;s the normal XUnit test setup which includes calling our test function with some input and asserting something about it using &lt;code&gt;Assert.Equal&lt;/code&gt; from &lt;code&gt;XUnit&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Theory&lt;/h3&gt;
&lt;p&gt;We can add a &lt;code&gt;Theory&lt;/code&gt; to test our function with multiple different inputs:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;LibraryTests.fs/Library.test.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;[&amp;lt;Theory&amp;gt;]
[&amp;lt;InlineData(&amp;quot;name&amp;quot;, &amp;quot;Hello name&amp;quot;)&amp;gt;]
[&amp;lt;InlineData(&amp;quot;World&amp;quot;, &amp;quot;Hello World&amp;quot;)&amp;gt;]
let ``Say.hello -&amp;gt; concantenated string`` (name:string, expected: string) =
    let result = hello name

    Assert.Equal(expected, result)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above we add the &lt;code&gt;InlineData&lt;/code&gt; attribute which allows us to provide inputs to our test, as well as specifying a &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;expected&lt;/code&gt; argument for our function. The test framework will then call our test using the arguments as specified in &lt;code&gt;InlineData&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When we&apos;re done our test file should have the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;module LibraryTests

open Xunit
open MyProject.Lib.Say

[&amp;lt;Fact&amp;gt;]
let ``Say.hello -&amp;gt; &amp;quot;Hello name&amp;quot; `` () =
    let name = &amp;quot;name&amp;quot;
    let expected = &amp;quot;Hello name&amp;quot;

    let result = hello name

    Assert.Equal(expected, result)

[&amp;lt;Theory&amp;gt;]
[&amp;lt;InlineData(&amp;quot;name&amp;quot;, &amp;quot;Hello name&amp;quot;)&amp;gt;]
[&amp;lt;InlineData(&amp;quot;World&amp;quot;, &amp;quot;Hello World&amp;quot;)&amp;gt;]
let ``Say.hello -&amp;gt; concantenated string`` (name:string, expected: string) =
    let result = hello name

    Assert.Equal(expected, result)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Running Tests&lt;/h2&gt;
&lt;p&gt;In order to run tests we can use the &lt;code&gt;dotnet-cli&lt;/code&gt;. Depending on the method used you can run your test from the project&apos;s root directory using the following command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Method 1&lt;/strong&gt; - &lt;code&gt;dotnet test MyProject.Tests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Method 2&lt;/strong&gt; - &lt;code&gt;dotnet test MyProject.Lib&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alternatively, tests can also be run from your IDE or Visual Studio Code with the &lt;code&gt;Ionide&lt;/code&gt; and &lt;code&gt;.NET Core Test Explorer&lt;/code&gt; extensions installed&lt;/p&gt;
&lt;h2&gt;Additional Resources&lt;/h2&gt;
&lt;p&gt;If you&apos;d like a deeper look into F# or XUnit here are some of my other posts which cover those:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2019/30-10/fsharp-webapi&quot;&gt;Introduction to F# Web APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dotnet/intro-to-fs&quot;&gt;Introduction to F#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dotnet/fs-entity-framework&quot;&gt;Entity Framework with F#&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dotnet/unit-testing-intro&quot;&gt;Introduction to Unit Testing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/dotnet/test-private-members&quot;&gt;Testing Private Members&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Control a Raspberry Pi GPIO with Python</title><link>https://nabeelvalley.co.za/blog/2021/27-03/flicker-led-with-raspberry-pi/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/27-03/flicker-led-with-raspberry-pi/</guid><description>Flicker and control and LED via a Raspberry Pi&apos;s GPIO Output pins using Python and RPi.GPIO</description><pubDate>Sun, 28 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Circuit Diagram&lt;/h2&gt;
&lt;p&gt;This script will make use of the GPIO Pins to flicker an LED&lt;/p&gt;
&lt;p&gt;The circuit diagram is below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/stdout/2021/27-03/led-circuit.png&quot; alt=&quot;Circuit diagram&quot;&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ve used a $330\Omega$ resistor for the resistor connected in series $R_LED$, however the resistance for a given LED can be calculated with this equation (From &lt;a href=&quot;https://www.circuitspecialists.com/blog/how-to-determine-resistor-value-for-led-lighting/&quot;&gt;Circuit Specialists&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;$$
R_{LED} = \frac{V_{source} - V_{LED}}{I_{LED}}
$$&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It&apos;s important to connect the LED in the correct direction on the circuit&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;Below is a simple python script which will handle turning the GPIO pins on and off using the &lt;a href=&quot;https://pypi.org/project/RPi.GPIO/&quot;&gt;RPi.GPIO&lt;/a&gt; library&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-py&quot;&gt;import RPi.GPIO as GPIO
import time

pin = 21
dur = 1

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(pin, GPIO.OUT)

while True:
  GPIO.output(pin, GPIO.HIGH)
  print &amp;quot;LED ON&amp;quot;
  time.sleep(dur)

  GPIO.output(pin, GPIO.LOW)
  print &amp;quot;LED OFF&amp;quot;
  time.sleep(dur)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Custom Styles in Markdown</title><link>https://nabeelvalley.co.za/blog/2021/23-03/custom-styles-in-markdown/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/23-03/custom-styles-in-markdown/</guid><description>Add styles for specific HTML elements in a markdown document</description><pubDate>Tue, 23 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When working with markdown it can often be useful to be able to style elements using custom CSS&lt;/p&gt;
&lt;p&gt;We can accomplish this by including a &lt;code&gt;style&lt;/code&gt; tag. An example to illustrate this is changing the way a table renders in a specific document by changing the style of table rows to be striped, you would include the following CSS:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;&amp;lt;style&amp;gt;
tr:nth-child(even) {
  background-color: #b2b2b2;
  color: #f4f4f4;
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the platform you&apos;re displaying the HTML in already has the styles included then you may need to add &lt;code&gt;!important&lt;/code&gt; to override in the CSS:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;&amp;lt;style&amp;gt;
tr:nth-child(even) {
  background-color: #b2b2b2!important;
  color: #f4f4f4!important;
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;my-sample-doc.md&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-md&quot;&gt;# Custom CSS in Markdown Example

This is a document where tables are rendered with every second table row with a specific background and foreground colour

&amp;lt;style&amp;gt;
tr:nth-child(even) {
  background-color: #b2b2b2!important;
  color: #f4f4f4!important;
}
&amp;lt;/style&amp;gt;

The above CSS will lead to the following table being rendered with alternating row colours:

| Col 1 | Col 2 | Col 3 |
| ----- | ----- | ----- |
| A     | B     | C     |
| 1     | 2     | 3     |
| A1    | B2    | C3    |
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that depending on your markdown renderer the embeded style tags may be removed, you&apos;ll have to look at your specific renderer/converter/platform to see whether this works for you&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With the converter I&apos;m using, &lt;code&gt;showdown.js&lt;/code&gt;, this is how the table above looks (with &lt;code&gt;!important&lt;/code&gt; included to override my current table styles):&lt;/p&gt;
&lt;p&gt;&amp;lt;style&amp;gt;
tr:nth-child(even) {
background-color: #b2b2b2!important;
color: #f4f4f4!important;
}
&amp;lt;/style&amp;gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Col 1&lt;/th&gt;
&lt;th&gt;Col 2&lt;/th&gt;
&lt;th&gt;Col 3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A1&lt;/td&gt;
&lt;td&gt;B2&lt;/td&gt;
&lt;td&gt;C3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>Render Element by Tag Name in React</title><link>https://nabeelvalley.co.za/blog/2021/19-03/render-component-by-tag-name-react/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/19-03/render-component-by-tag-name-react/</guid><description>Dynamically render a React Element given the name of the corresponding HTML element</description><pubDate>Fri, 19 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When using React it can sometimes be useful to render a standard HTML element given the element name dynamically as a prop&lt;/p&gt;
&lt;p&gt;React allows us to do this provided we store the element name in a variable that starts with a capital letter, as JSX requires this to render a custom element&lt;/p&gt;
&lt;p&gt;We can do something like this by defining a generic element in React which just takes in the name of the tag in addition to it&apos;s usual props and children, something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;const GenericElement = ({ tagName: Tag, children, ...innerProps }) =&amp;gt; (
  &amp;lt;Tag {...innerProps}&amp;gt;{children}&amp;lt;/Tag&amp;gt;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then render this element by calling the &lt;code&gt;GenericElement&lt;/code&gt; with the &lt;code&gt;tagName&lt;/code&gt; prop and then any children we&apos;d like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-jsx&quot;&gt;&amp;lt;GenericElement tagName=&amp;quot;h1&amp;quot;&amp;gt;I am an h1&amp;lt;/GenericElement&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&apos;s a short example using &lt;a href=&quot;https://replit.com/@nabeelvalley/render-by-element-name#src/App.jsx&quot;&gt;Replit&lt;/a&gt; for reference, all the important stuff is in the &lt;code&gt;src/App.jsx&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;700px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://replit.com/@nabeelvalley/render-by-element-name?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Setup HomeAssistant RaspberryPi with WiFi configured</title><link>https://nabeelvalley.co.za/blog/2021/09-03/configure-home-assistant-raspberrypi-wifi/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/09-03/configure-home-assistant-raspberrypi-wifi/</guid><description>Enable a HomeAssistant flashed RaspberryPi to operate over WiFi using config files</description><pubDate>Tue, 09 Mar 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A short lil guide to setting up Home Assistant on a RaspberryPi using WiFi instead of Ethernet&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download Balena Etcher and install from &lt;a href=&quot;https://www.balena.io/etcher/&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Go to the HomeAssistant website and copy the relevant release URL from &lt;a href=&quot;https://github.com/home-assistant/operating-system/releases/download/5.12/hassos_rpi3-64-5.12.img.xz&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Connect your RaspberryPi&apos;s SD card to your computer&lt;/li&gt;
&lt;li&gt;Open Balena Etcher and select &lt;code&gt;Flash from URL&lt;/code&gt; and select the RaspberryPi&apos;s SD to flash to&lt;/li&gt;
&lt;li&gt;Once flashing is complete, open the RaspberryPi&apos;s SD in File Explorer, and create the following file:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;RASPBERRYPIDRIVE/CONFIG/network/my-network&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;!cat .\my-network
[connection]
id=my-network
uuid=72111c67-4a5d-4d5c-925e-f8ee26efb3c3
type=802-11-wireless
[802-11-wireless]
ssid=YOUR_WIFI_NETWORK_NAME
#hidden=true

[802-11-wireless-security]
auth-alg=open
key-mgmt=wpa-psk
psk=YOUR_WIFI_PASSWORD

[ipv4]
method=auto

[ipv6]
addr-gen-mode=stable-privacy
method=auto
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Be sure to use &lt;code&gt;LF&lt;/code&gt; line endings, additional information on this setup can be found &lt;a href=&quot;https://github.com/home-assistant/operating-system/blob/dev/Documentation/network.md&quot;&gt;on GitHub&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Serialize a JsonValue Array using F# and FSharp.Data&apos;s JsonProvider</title><link>https://nabeelvalley.co.za/blog/2021/01-03/serialize-jsonvalue-array-fsharp/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/01-03/serialize-jsonvalue-array-fsharp/</guid><description>Making use of the FSharp.Data JsonProvider and the serialization of JsonProvider arrays into JSON</description><pubDate>Wed, 03 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When working with the &lt;code&gt;FSharp.Data.JsonProvider&lt;/code&gt; type provider you may encounter a need to serialize a &lt;code&gt;JsonValue array&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s take a look at an example where this may be necessary:&lt;/p&gt;
&lt;p&gt;First, we&apos;ll define the type of our data using a type provider, in this case it&apos;s connected to the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;data/api-response.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;data&amp;quot;: [
    {
      &amp;quot;id&amp;quot;: &amp;quot;id&amp;quot;,
      &amp;quot;caption&amp;quot;: &amp;quot;caption&amp;quot;,
      &amp;quot;media_type&amp;quot;: &amp;quot;IMAGE&amp;quot;,
      &amp;quot;media_url&amp;quot;: &amp;quot;url_to_image&amp;quot;
    }
  ],
  &amp;quot;paging&amp;quot;: {
    &amp;quot;cursors&amp;quot;: {
      &amp;quot;before&amp;quot;: &amp;quot;hash&amp;quot;,
      &amp;quot;after&amp;quot;: &amp;quot;hash&amp;quot;
    },
    &amp;quot;next&amp;quot;: &amp;quot;full_request_url&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the F# file that&apos;s using this as the basis for the type definition is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;open FSharp.Data

type ApiResponse = JsonProvider&amp;lt;&amp;quot;./data/api-response.json&amp;quot;, SampleIsList=true&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can also create some sample data using the &lt;code&gt;ApiResponse.Parse&lt;/code&gt; method that&apos;s now defined on our type thanks to the JsonProvider&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;// get some sample data
let sampleData = ApiResponse.Parse(&amp;quot;&amp;quot;&amp;quot;{
  &amp;quot;data&amp;quot;: [
      {
          &amp;quot;id&amp;quot;: &amp;quot;id&amp;quot;,
          &amp;quot;caption&amp;quot;: &amp;quot;caption&amp;quot;,
          &amp;quot;media_type&amp;quot;: &amp;quot;IMAGE&amp;quot;,
          &amp;quot;media_url&amp;quot;: &amp;quot;url_to_image&amp;quot;
      }
  ],
  &amp;quot;paging&amp;quot;: {
      &amp;quot;cursors&amp;quot;: {
          &amp;quot;before&amp;quot;: &amp;quot;hash&amp;quot;,
          &amp;quot;after&amp;quot;: &amp;quot;hash&amp;quot;
      },
      &amp;quot;next&amp;quot;: &amp;quot;full_request_url&amp;quot;
  }
}&amp;quot;&amp;quot;&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you were to use the &lt;code&gt;sampleData&lt;/code&gt; object and try to parse it to JSON you could directly call the &lt;code&gt;sampleData.JsonValue.ToString()&lt;/code&gt; method. As designed, this immediately returns the JSON representation of the object&lt;/p&gt;
&lt;p&gt;However, when we take a look at the &lt;code&gt;sampleData.Data&lt;/code&gt; property, we will notice this is a &lt;code&gt;Datum array&lt;/code&gt;, the problem here is that the &lt;code&gt;array&lt;/code&gt; type doesn&apos;t have &lt;code&gt;JsonValue&lt;/code&gt; property&lt;/p&gt;
&lt;p&gt;However, if we look at how &lt;code&gt;JsonValue&lt;/code&gt; is defined we will see the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;union JsonValue =
  | String of string
  | Number of decimal
  | Float of float
  | Record of properties : (string * JsonValue) array
  | Array of elements : JsonValue array
  | Boolean of bool
  | Null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Based on this, we can see that an &lt;code&gt;Array of elements&lt;/code&gt; can be seen as a &lt;code&gt;JsonValue array&lt;/code&gt;, using this information, we can make use of the &lt;code&gt;JsonValue.Array&lt;/code&gt; constructor and the &lt;code&gt;JsonValue&lt;/code&gt; property of each of the elements of the &lt;code&gt;Data&lt;/code&gt; property to convert the &lt;code&gt;JsonValue array&lt;/code&gt; to a &lt;code&gt;JsonValue&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;let jsonValue =
    // get the property we want
    sampleData.Data
    // extract the JsonValue property from each element
    |&amp;gt; Array.map (fun p -&amp;gt; p.JsonValue)
    // pass into the JsonValue.Array constructor
    |&amp;gt; JsonValue.Array

let json = jsonValue.ToString()
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Jenkins: A Git process may have crashed in the repository</title><link>https://nabeelvalley.co.za/blog/2021/03-02/jenkins-git-process-crashed/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2021/03-02/jenkins-git-process-crashed/</guid><description>Repair an issue preventing Jenkins from running Git processes</description><pubDate>Wed, 03 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Taken from &lt;a href=&quot;https://stackoverflow.com/questions/38004148/another-git-process-seems-to-be-running-in-this-repository&quot;&gt;this StackOverflow answer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;Another git process seems to be running in this repository, e.g.
an edirot opened by &apos;git commit&apos;. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes when using Jenkins a Git process may crash or timeout resulting in an error message like the above one. This can result in issues when running later Git steps or running other Git steps in the repository in the Jenkins workspace&lt;/p&gt;
&lt;p&gt;The simplest way I&apos;ve found to fix this is to simply delete the &lt;code&gt;.git/index.lock&lt;/code&gt; or &lt;code&gt;.git/shallow.lock&lt;/code&gt; file from the workspace that&apos;s giving the issue and run again&lt;/p&gt;
</content:encoded></item><item><title>Custom Attributes in C# Web Controllers</title><link>https://nabeelvalley.co.za/blog/2020/17-12/csharp-webapi-custom-attributes/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/17-12/csharp-webapi-custom-attributes/</guid><description>Modify controller behaviour using Attributes</description><pubDate>Thu, 17 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Implementing an attribute for a WebAPI or class in C# can help to reduce duplication and centralize parts of the application logic. This could be used for a variety of tasks such as logging information when methods are called as well as managinng authorization&lt;/p&gt;
&lt;p&gt;In this post I&apos;m going to cover the following:&lt;/p&gt;
&lt;h2&gt;Attribute Types and Execution Order&lt;/h2&gt;
&lt;p&gt;There are a few different attribute types that we can handle on a WebAPI that provide us with the ability to wrap some functionality around our endpoints, below are some of the common attributes that we can implement and the order in which they execute (&lt;a href=&quot;https://stackoverflow.com/questions/19249511/difference-between-iactionfilter-and-iauthorizationfilter&quot;&gt;StackOverflow&lt;/a&gt;)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Authorization - &lt;code&gt;IAuthorizationFilter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Action - &lt;code&gt;IActionFilter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Result - &lt;code&gt;IResultFilter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Exception - &lt;code&gt;IExceptionFilter&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;IActionFilter&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;IActionFilter&lt;/code&gt; executes before and after a method is executed and contains two different methods for doing this, namely the &lt;code&gt;OnActionExecuting&lt;/code&gt; and &lt;code&gt;OnActionExecuted&lt;/code&gt; methods respectively. A basic implemtation of &lt;code&gt;IActionFilter&lt;/code&gt; would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;namespace CSharpAttributes.Attributes
{
  public class LogStatusAttribute : Attribute, IActionFilter
  {
    public LogStatusAttribute()
    {
      Console.WriteLine(&amp;quot;Attribute Initialized&amp;quot;);
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
      Console.WriteLine(&amp;quot;OnActionExecuting&amp;quot;);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
      Console.WriteLine(&amp;quot;OnActionExecuted&amp;quot;);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can then be implemented on a controller method with a &lt;code&gt;[LogStatus]&lt;/code&gt; attribute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;[LogStatus]
[HttpGet]
public IEnumerable&amp;lt;WeatherForecast&amp;gt; Get()
{
  Console.WriteLine(&amp;quot;Executing Get&amp;quot;);
  return data;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The order of logging which we see will be as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Attribute Initialized&lt;/code&gt; when the controller is instantiated&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OnActionExecuting&lt;/code&gt; when the controller is called&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Executing Get&lt;/code&gt; when the controller is executed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OnActionExecuted&lt;/code&gt; when the controller is done executing&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;IAuthorizationFilter&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;IAuthorizationFilter&lt;/code&gt; executes as the first filter on a controller&apos;s method call&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;namespace CSharpAttributes.Attributes
{
  public class CustomAuthorizeAttribute : Attribute, IAuthorizationFilter
  {
    public CustomAuthorizeAttribute()
    {
      Console.WriteLine(&amp;quot;Attribute Initialized&amp;quot;);
    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
      Console.WriteLine(&amp;quot;OnAuthorization&amp;quot;);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can then be implemented on a controller method with a &lt;code&gt;[CustomAuthorize]&lt;/code&gt; attribute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;[CustomAuthorize]
[HttpGet]
public IEnumerable&amp;lt;WeatherForecast&amp;gt; Get()
{
  Console.WriteLine(&amp;quot;Executing Get&amp;quot;);
  return data;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The order of logging which we see will be as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Attribute Initialized&lt;/code&gt; when the controller is instantiated&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OnAuthorization&lt;/code&gt; when the controller is called&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Executing Get&lt;/code&gt; when the controller is executed&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Modify Response Data&lt;/h2&gt;
&lt;p&gt;An attribute&apos;s &lt;code&gt;context&lt;/code&gt; parameter gives us ways by which we can access the &lt;code&gt;HttpContext&lt;/code&gt; as well as set the result of a method call so that it can be handled down the line. For example, we can implement our CustomAuthorize attribute with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;public void OnAuthorization(AuthorizationFilterContext context)
{
  if (!context.HttpContext.Request.Headers.ContainsKey(&amp;quot;X-Custom-Auth&amp;quot;))
  {
    context.Result = new UnauthorizedResult();
  }

  Console.WriteLine(&amp;quot;Attribute Called&amp;quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will mean that if we set the &lt;code&gt;context.Result&lt;/code&gt; in our method then the controller will not be executed and the endpoint will return the &lt;code&gt;UnauthorizedResult&lt;/code&gt; early. You can also see that we&apos;re able to access things like the &lt;code&gt;HttpContext&lt;/code&gt; which makes it easy for us to view the request/response data and do things based on that&lt;/p&gt;
&lt;h2&gt;Attribute on a Class&lt;/h2&gt;
&lt;p&gt;Note that it&apos;s also possible to apply the above to each method in a class by adding the attribute at the top of the class declaration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;[ApiController]
[LogStatus]
[Route(&amp;quot;[controller]&amp;quot;)]
public class WeatherForecastController : ControllerBase
{
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Attributes with Input Parameters&lt;/h2&gt;
&lt;p&gt;We are also able to create attributes that enable the consumer to modify their behaviour by taking input parameters to the constructor, we can update our &lt;code&gt;LogStatus&lt;/code&gt; attribute to do something like add a prefix before all logs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;namespace CSharpAttributes.Attributes
{
  public class LogStatusAttribute : Attribute, IActionFilter
  {
    private readonly string _prefix;

    public LogStatusAttribute(string prefix = &amp;quot;&amp;quot;)
    {
      _prefix = prefix;
      Console.WriteLine(&amp;quot;Attribute Initialized&amp;quot;);
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
      Console.WriteLine(_prefix + &amp;quot;OnActionExecuted&amp;quot;);
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
      Console.WriteLine(_prefix + &amp;quot;OnActionExecuting&amp;quot;);
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, applying to our controller method like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;[LogStatus(&amp;quot;WeatherController-Get:&amp;quot;)]
[HttpGet]
public IEnumerable&amp;lt;WeatherForecast&amp;gt; Get()
{
  Console.WriteLine(&amp;quot;Executing Get&amp;quot;);
  return data;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the new output will look like so:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Attribute Initialized&lt;/code&gt; when the controller is instantiated&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WeatherForecast-Get:OnActionExecuting&lt;/code&gt; when the controller is called&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Executing Get&lt;/code&gt; when the controller is executed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WeatherForecast-Get:OnActionExecuted&lt;/code&gt; when the controller is done executing&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Attribute Setting at Class and Method Level&lt;/h2&gt;
&lt;p&gt;Since an attribute can be implemented at a class and method level it&apos;s useful for us to be able to implement it at a class and the override the behaviour or add behaviour for a specific method&lt;/p&gt;
&lt;p&gt;We can do this by setting the attribute inheritence to &lt;code&gt;false&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Updating out &lt;code&gt;LogStatusAttribute&lt;/code&gt; we can add the &lt;code&gt;AttributeUsage&lt;/code&gt; Attribute as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;namespace CSharpAttributes.Attributes
{
  [AttributeUsage(AttributeTargets.All, Inherited = false)]
  public class LogStatusAttribute : Attribute, IActionFilter
  {
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means that we can independently apply the attribute at class and method levels, so now our controller can look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cs&quot;&gt;namespace CSharpAttributes.Controllers
{
  [ApiController]
  [Route(&amp;quot;[controller]&amp;quot;)]
  [LogStatus(&amp;quot;WeatherForecast:&amp;quot;)]
  public class WeatherForecastController : ControllerBase
  {
    [LogStatus(&amp;quot;Get:&amp;quot;)]
    [HttpGet]
    public IEnumerable&amp;lt;WeatherForecast&amp;gt; Get()
    {
      Console.WriteLine(&amp;quot;Executing Get&amp;quot;);
      return data;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will output the logs as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Attribute Initialized&lt;/code&gt; when the controller is instantiated&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WeatherForecast:OnActionExecuting&lt;/code&gt; when the class is called&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Get:OnActionExecuting&lt;/code&gt; when the controller is called&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Executing Get&lt;/code&gt; when the controller is executed&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Get:OnActionExecuted&lt;/code&gt; when the controller is done executing&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WeatherForecast:OnActionExecuted&lt;/code&gt; when the class is done executing&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Debug POSTs using an Express App</title><link>https://nabeelvalley.co.za/blog/2020/04-12/post-endpoint-logger-express/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/04-12/post-endpoint-logger-express/</guid><description>Create an express.js app with an endpoint that logs and returns a request&apos;s JSON body</description><pubDate>Fri, 04 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sometimes it&apos;s useful to have an endpoint that you can use to debug data that&apos;s being &lt;code&gt;POST&lt;/code&gt;ed to an application&lt;/p&gt;
&lt;p&gt;You can make use of the following &lt;code&gt;express.js&lt;/code&gt; app to log your application&apos;s POST requests:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/Express-POST-Logger?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const express = require(&apos;express&apos;)
const app = express()

// parse json
app.use(express.json())

// GET endpoint to check uptime
app.get(&apos;/&apos;, (req, res) =&amp;gt; {
  res.json({ data: &apos;hello&apos; })
})

// POST endpointthat logs request body
app.post(&apos;/&apos;, (req, res) =&amp;gt; {
  console.log(req.body)
  res.json(req.body)
})

// listen for requests
const listener = app.listen(process.env.PORT, () =&amp;gt; {
  console.log(&apos;listening on port &apos; + listener.address().port)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;detail&amp;gt;&lt;/p&gt;
</content:encoded></item><item><title>Backup SQL Server Database as Script</title><link>https://nabeelvalley.co.za/blog/2020/26-11/backup-database-as-script/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/26-11/backup-database-as-script/</guid><description>Create a DB Backup/Restore Script using SQL Server</description><pubDate>Thu, 26 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To create a scripted backup of a database on SQL Server do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Right click on the database name &amp;gt; &lt;code&gt;Tasks&lt;/code&gt; &amp;gt; &lt;code&gt;Generate Scripts...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;code&gt;Choose Objects&lt;/code&gt; screen select &lt;code&gt;Scriot entire database and all database objects&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;code&gt;Set Scripting Options&lt;/code&gt; screen click on &lt;code&gt;Advanced&lt;/code&gt; and select:
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Script DROP and CREATE = Script CREATE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Types of data to script = Schema and data&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Set the location to save the script&lt;/li&gt;
&lt;li&gt;On the &lt;code&gt;Summary&lt;/code&gt; page you can click &lt;code&gt;Next&lt;/code&gt; which will start the generation&lt;/li&gt;
&lt;li&gt;Thereafter you can view the generated database script from the location it was generated to&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Generate data for a Postman request</title><link>https://nabeelvalley.co.za/blog/2020/24-11/generate-postman-data/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/24-11/generate-postman-data/</guid><description>Using Pre-Request Scripts and Environment variables to generate data in Postman</description><pubDate>Tue, 24 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When making requests with Postman to test an API it is often useful to have generated data, for example when creating users in a backend system you may want the ability to get custom user data&lt;/p&gt;
&lt;p&gt;The method we will use to do this is by setting Postman environment variables in the Pre-request Script of a Postman request&lt;/p&gt;
&lt;p&gt;Firstly, we can write some basic logging in the Pre-request script section on Postman and view the result in the Postman console:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const name = &apos;Nabeel&apos;

console.log(`Hello ${name}`)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally, postman gives us some functions to set and get environment variables, so we can set the name as an environment variable like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const name = &apos;Nabeel&apos;

pm.environment.set(&apos;name&apos;, name)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And log it like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;console.log(pm.environment.get(&apos;name&apos;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aditionally, we can make HTTP Requests using &lt;code&gt;pm.sendRequest&lt;/code&gt; which then takes a callback for what we want to do after the request, we can use the &lt;code&gt;randomuser&lt;/code&gt; api to get a user:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;pm.sendRequest(&apos;https://randomuser.me/api/&apos;, (err, res) =&amp;gt; {
  const apiResponse = res.json()

  // do more stuff
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using this method, we can get some random user data and set it in the environment variables as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;pm.sendRequest(&apos;https://randomuser.me/api/&apos;, (err, res) =&amp;gt; {
  const apiResponse = res.json()

  const user = apiResponse.results[0]

  const email = user.email
  const firstName = user.name.first
  const lastName = user.name.last

  pm.environment.set(&apos;email&apos;, email)
  pm.environment.set(&apos;firstName&apos;, firstName)
  pm.environment.set(&apos;lastName&apos;, lastName)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then use this in our request body using Postman&apos;s &lt;code&gt;{\{}\}&lt;/code&gt; syntax. If we were making a JSON request, our body would look something like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POST: https://my-api.com/users&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;email&amp;quot;: &amp;quot;{{email}}&amp;quot;,
  &amp;quot;firstName&amp;quot;: &amp;quot;{{firstName}}&amp;quot;,
  &amp;quot;lastName&amp;quot;: &amp;quot;{{lastName}}&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Postman will then populate the slots from the environment variables that we set automatically when making the request&lt;/p&gt;
</content:encoded></item><item><title>Capture Fetch with Cypress</title><link>https://nabeelvalley.co.za/blog/2020/10-11/capture-fetch-response-cypress/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/10-11/capture-fetch-response-cypress/</guid><description>Capture and Use Fetch Requests and Responses in Cypress</description><pubDate>Tue, 10 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;To capture the result of a &lt;code&gt;fetch&lt;/code&gt; request with Cypress you will need to make use of &lt;code&gt;cy.route2&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;cy.route2&lt;/code&gt; command needs to be enabled in your &lt;code&gt;cypress.json&lt;/code&gt; file before usage, to do so add the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cypress.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;experimentalNetworkStubbing&amp;quot;: true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;Next, using the command to capture requests to a route looks a bit like this in a test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;cy.route2(&apos;POST&apos;, &apos;/do-stuff&apos;).as(&apos;data&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above you need to use the &lt;code&gt;cy.route2&lt;/code&gt; function. In the above we&apos;re capturing &lt;code&gt;POST&lt;/code&gt; requests to the &lt;code&gt;/do-stuff&lt;/code&gt; endpoint. The object which contains the request and response data is stored in the &lt;code&gt;@data&lt;/code&gt; which can be retreived and worked with like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;cy.wait(&apos;@data&apos;).then((data) =&amp;gt; {
  // do stuff using the data object
  console.log(data)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;cy.wait&lt;/code&gt; function retreives the &lt;code&gt;data&lt;/code&gt; object, we use the &lt;code&gt;.then&lt;/code&gt; function with a callback function to do stuff with the fully resolved &lt;code&gt;data&lt;/code&gt; object&lt;/p&gt;
&lt;p&gt;Furthermore, the HTTP response from the &lt;code&gt;data&lt;/code&gt; object can be parsed using &lt;code&gt;JSON.parse&lt;/code&gt;, you can then also add assertions based on the response object. Adding this in, the above code would look more like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;cy.wait(&apos;@data&apos;).then((data) =&amp;gt; {
  console.log(data)

  // parse the response body
  const res = JSON.parse(data.response.body)

  // assertions on the response
  assert.isTrue(res.success)
  assert.isNotNull(res.message)
})
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Scripting with FSharp</title><link>https://nabeelvalley.co.za/blog/2020/13-10/launch-fsi-from-terminal/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/13-10/launch-fsi-from-terminal/</guid><description>Using the .NET CLI to use the F# Interactive console and run F# Scripts</description><pubDate>Tue, 13 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;Before you can use the following, you will need the &lt;a href=&quot;https://dotnet.microsoft.com/download&quot;&gt;.NET Core SDK installed&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Open the F# Interactive Console&lt;/h2&gt;
&lt;p&gt;To open an F# interactive console using the &lt;code&gt;dotnet&lt;/code&gt; CLI. You can run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet fsi
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that to end statements/execute in the F# Interactive console use &lt;code&gt;;;&lt;/code&gt; at the end of a line or section of code&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once in the console, running &lt;code&gt;#help;;&lt;/code&gt; from the &lt;code&gt;fsi&lt;/code&gt; console to view the help menu, and &lt;code&gt;#quit;;&lt;/code&gt; to quit the interactive session&lt;/p&gt;
&lt;p&gt;Additionally, you can write multi-line &lt;code&gt;F#&lt;/code&gt; code as well as just single line expressions. Each expression should be terminated with &lt;code&gt;;;&lt;/code&gt;. For example, you can write a function that will print some data into the console:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;let printer s =
    printfn s
;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you can call the function with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;printer &amp;quot;Hello World&amp;quot;;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will execute the above code and output &lt;code&gt;Hello World&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Run an F# Script&lt;/h2&gt;
&lt;p&gt;F# scripts can be run using the &lt;code&gt;dotnet fsi&lt;/code&gt; command as well, followed by the path to an F# script file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet fsi ./myscript.fsx
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Package Management with Poetry</title><link>https://nabeelvalley.co.za/blog/2020/07-10/python-packages-with-poetry/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/07-10/python-packages-with-poetry/</guid><description>Manage python packages using poetry</description><pubDate>Wed, 07 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://python-poetry.org/docs/&quot;&gt;Poetry Docs&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Python package management is typically quite a mess. Managing packages with &lt;code&gt;pip&lt;/code&gt; often requires additional management of things like virtual environments and python version management&lt;/p&gt;
&lt;p&gt;Poetry is a package manager that abstracts a lot of the typical Python dependency and environment management away from the user&lt;/p&gt;
&lt;h2&gt;Install Poetry&lt;/h2&gt;
&lt;p&gt;Before you can install &lt;code&gt;poetry&lt;/code&gt; you need to have Python installed&lt;/p&gt;
&lt;p&gt;To install &lt;code&gt;poetry&lt;/code&gt; you can do one of the following depending on your OS:&lt;/p&gt;
&lt;h3&gt;Windows Powershell&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-ps1&quot;&gt;(Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python -
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Bash&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Initialize Poetry&lt;/h2&gt;
&lt;h3&gt;Create a New Project&lt;/h3&gt;
&lt;p&gt;If you&apos;re starting a new project, you can run the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;poetry new my-project
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above will generate a &lt;code&gt;pyproject.toml&lt;/code&gt; file with the project settings. Alternatively you can use the following to add &lt;code&gt;poetry&lt;/code&gt; to an existing project&lt;/p&gt;
&lt;h3&gt;Add to Existing Project&lt;/h3&gt;
&lt;p&gt;To add &lt;code&gt;poetry&lt;/code&gt; to an existing project, run the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;poetry init
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Using Poetry&lt;/h2&gt;
&lt;h3&gt;Add Dependency&lt;/h3&gt;
&lt;p&gt;To manage dependencies you can use the &lt;code&gt;poetry add&lt;/code&gt; command. For example, if we would like to install &lt;code&gt;flask&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;poetry add flask
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Run Application&lt;/h3&gt;
&lt;p&gt;To run an application using the virtual environment created by &lt;code&gt;poetry&lt;/code&gt; you can use the &lt;code&gt;poetry run&lt;/code&gt; command, followed by the command you want to run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;poetry run python app.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running a &lt;code&gt;flask&lt;/code&gt; app would look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;poetry run flask run
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create a Shell&lt;/h2&gt;
&lt;p&gt;To create a shell in the &lt;code&gt;poetry&lt;/code&gt; virtual environment run:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;poetry shell
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above will open a &lt;code&gt;poetry&lt;/code&gt; shell with the virtual environment. You can then do something like run the &lt;code&gt;python&lt;/code&gt; command to open a &lt;code&gt;python&lt;/code&gt; shell in the environment&lt;/p&gt;
</content:encoded></item><item><title>Trust .NET Core Dev Certificates</title><link>https://nabeelvalley.co.za/blog/2020/07-10/trust-dotnet-dev-certs/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/07-10/trust-dotnet-dev-certs/</guid><description>Adding .NET Core Certificates to the Cert store from the CLI</description><pubDate>Wed, 07 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When developing .NET Core web applications with HTTPS, to simplifiy your experience and avoid browser warnings you can trust the .NET Core dev certs on your local device with the followning commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;dotnet dev-certs https --clean
dotnet dev-certs https --trust
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Highlight Specific Elements</title><link>https://nabeelvalley.co.za/blog/2020/29-09/highlight-specific-elements/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/29-09/highlight-specific-elements/</guid><description>Add a border around all HTML Elements that match a CSS Selector to aid in debugging</description><pubDate>Tue, 29 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You can highlight all HTML elements which respond to a specific CSS selector with the following. This can be useful for debugging purposes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;document
  .querySelectorAll(selector)
  .forEach((el) =&amp;gt; (el.style.border = &apos;solid 2px red&apos;))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, the following &lt;code&gt;[id]&lt;/code&gt; selector will find all elements with an &lt;code&gt;id&lt;/code&gt; attribute:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;document
  .querySelectorAll(&apos;[id]&apos;)
  .forEach((el) =&amp;gt; (el.style.border = &apos;solid 2px red&apos;))
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>URL Text Fragments</title><link>https://nabeelvalley.co.za/blog/2020/29-09/text-fragments/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/29-09/text-fragments/</guid><description>Link to, and highlight, content on any part of a Web page with the Text Fragment directive</description><pubDate>Tue, 29 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When linking to a webpage it can be useful to link to a specific part of a page. Using a hash in the URl you can link to the &lt;code&gt;id&lt;/code&gt; attribute in the HTML of a page&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;https://my.website.com#overview&lt;/code&gt; would link to the element with &lt;code&gt;id=&amp;quot;overview&amp;quot;&lt;/code&gt; in the HTML&lt;/p&gt;
&lt;p&gt;However, it may be useful for us to link to a general piece of text on a page, we can use &lt;em&gt;text fragments&lt;/em&gt; to do so. These work similar to the way a hash does, but we can link to any text on a page even if it does not have an &lt;code&gt;id&lt;/code&gt;. Additionally, the user&apos;s browser will highlight the text set to draw the user&apos;s attention to it&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that at the moment only Chromium based browsers support this&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To do this, we need to identifiy the text on the page we want to link to. Say we&apos;d like to link to the first paragraph of this page, we can use the &lt;strong&gt;text directive&lt;/strong&gt; (&lt;code&gt;#:~:text=&lt;/code&gt;) param in the URL to link to specific text instead of just the &lt;code&gt;#&lt;/code&gt; like we use for an ID&lt;/p&gt;
&lt;p&gt;We would need to take the part of the text we want to focus, URL encode it, then add it to the &lt;strong&gt;text directive&lt;/strong&gt; the final URL may look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://my.website.com/#:~:text=When%20linking%20to%20a%20webpage
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you need to highlight a larger piece of text, you can use the start and end of your text segment, separated by a comma, for example selecting the entire first paragraph of this post:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://my.website.com/#:~:text=when%20linking,HTML%20of%20a%20page
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The link below should link to the first paragraph of this page if opened in a new tab (provided your browser supports text fragments):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;#:~:text=when%20linking,HTML%20of%20a%20page&quot;&gt;ctrl + click me&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can read more about text fragments in URLs on &lt;a href=&quot;https://web.dev/text-fragments/&quot;&gt;web.dev&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>Node.js Dirname vs Resolve</title><link>https://nabeelvalley.co.za/blog/2020/25-09/dirname-vs-resolve/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/25-09/dirname-vs-resolve/</guid><description>Working with paths using resolve and __dirname in Node.js</description><pubDate>Fri, 25 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Node.js has a few methods by which we can get the directory in which we are currently executing, and get paths relative to it&lt;/p&gt;
&lt;h2&gt;Get the Current Directory&lt;/h2&gt;
&lt;h3&gt;Process Directory&lt;/h3&gt;
&lt;p&gt;We can get the working directory from where we started the &lt;code&gt;node&lt;/code&gt; script with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const processDir = process.cwd()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;File/Module Directory&lt;/h3&gt;
&lt;p&gt;And we can get the directory in which the currently executing file is in with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const fileDir = __dirname
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Get Path to a Target Location&lt;/h2&gt;
&lt;p&gt;To get an absolute path to a specific target file/directory we have a few methods&lt;/p&gt;
&lt;h3&gt;Joining Paths&lt;/h3&gt;
&lt;p&gt;We can use the &lt;code&gt;path&lt;/code&gt; module&apos;s &lt;code&gt;join&lt;/code&gt; method to get a path given any path pieces you can go up or down a directory using the &lt;code&gt;../&lt;/code&gt; notation&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { join } = require(&apos;path&apos;)

const path1 = join(basePath, &apos;./downdir/myfile.txt&apos;)
const path2 = join(basePath, &apos;../updir&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Absolute Path from Process Directory&lt;/h3&gt;
&lt;p&gt;To get an absolute path from the process directory, you can use the &lt;code&gt;path&lt;/code&gt; module&apos;s &lt;code&gt;resolve&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { resolve } = require(&apos;path&apos;)

const absPath = resolve(&apos;./downdir/myfile.txt&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Like the &lt;code&gt;join&lt;/code&gt; method you can also use the &lt;code&gt;../&lt;/code&gt; notation to move up a directory&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using &lt;code&gt;resolve&lt;/code&gt; is basically shorthand for using &lt;code&gt;join&lt;/code&gt; with &lt;code&gt;process.cwd()&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const absPath = join(process.cwd(), &apos;./downdir/myfile.txt&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Absolute Path from File/Module Directory&lt;/h3&gt;
&lt;p&gt;If it makes more sense to get the path relative to the executing file, you can use a combination of &lt;code&gt;__dirname&lt;/code&gt; and &lt;code&gt;join&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const { join } = require(&apos;path&apos;)

const absPath = join(__dirname, &apos;./downdir/myfile.txt&apos;)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Split an Array into Segments</title><link>https://nabeelvalley.co.za/blog/2020/23-09/split-an-array-into-segments/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/23-09/split-an-array-into-segments/</guid><description>Distribute elements of an array over a fixed number of segments</description><pubDate>Wed, 23 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It can sometimes be useful to split an array into a separated set of rows or columns, such as when trying to separate elements into buckets while maintaing order.&lt;/p&gt;
&lt;p&gt;For example, given the following &lt;code&gt;input&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the desired &lt;code&gt;output&lt;/code&gt; array as follows, in which we split elements into different rows, while maintaing a top-down/left-right ordering:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const output = [
  [1, 4, 7, 10],
  [2, 5, 8],
  [3, 6, 9],
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can accomplish this using a function like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const transform = (arr, segments) =&amp;gt;
  [...new Array(segments)].map((_, outerPos) =&amp;gt;
    input.filter((el, innerPos) =&amp;gt; innerPos % segments === outerPos)
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which can then be used with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const rows = 3
const transformedData = transform(input, rows)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Mongo DB in Docker</title><link>https://nabeelvalley.co.za/blog/2020/22-09/mongo-db-in-docker/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/22-09/mongo-db-in-docker/</guid><description>Run a MongoDB Instance with Docker or Docker Compose</description><pubDate>Tue, 22 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Considerations&lt;/h2&gt;
&lt;p&gt;To run MongDB in a Docker Container there are a few things to take note of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may need to configure auth&lt;/li&gt;
&lt;li&gt;Volume storage to be set up&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;From Terminal&lt;/h2&gt;
&lt;p&gt;To run a Docker container using a single command in the terminal you can run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker run -d -p 27017:27017
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also specify additional information like the volumes you would like to use using flags when running:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;docker run -d -p 27017:27017
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;From Compose&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;More info can be found &lt;a href=&quot;https://medium.com/faun/managing-mongodb-on-docker-with-docker-compose-26bf8a0bbae3&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You can also run a MongoDB Container with Compose which may be a bit easier:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;version: &apos;3.3&apos;

services:
  # mongonode0:27017
  mongo0:
    image: mongo
    hostname: mongo0
    container_name: mongo0
    restart: always
    ports:
      - &apos;37000:27017&apos;
    volumes:
      - ./mongo0-data:/data/db
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Web APIs with AdonisJS and PostgreSQL</title><link>https://nabeelvalley.co.za/blog/2020/06-09/first-look-at-adonisjs/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/06-09/first-look-at-adonisjs/</guid><description>A look at developing Web APIs using the AdonisJS Framework and MongoDB</description><pubDate>Sun, 06 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this post, we&apos;ll take a look at building an API using the AdonisJS framework. We&apos;ll specifically be looking at the &lt;a href=&quot;https://preview.adonisjs.com/&quot;&gt;AdonisJS v5 Release Preview&lt;/a&gt; and how we can create a simple REST API that handles some CRUD operations on a Database&lt;/p&gt;
&lt;p&gt;Because we&apos;re going to be creating a REST API, you should have some experience making HTTP Requests, for our purposes we can use a website called &lt;a href=&quot;https://postwoman.io/&quot;&gt;Postwoman&lt;/a&gt; to interact with our API, but you can also use any other tool you prefer&lt;/p&gt;
&lt;h2&gt;About AdonisJS&lt;/h2&gt;
&lt;p&gt;AdonisJS is an opinionated, Typescript-first web framework that provides a lot more &amp;quot;out of the box&amp;quot; functionality than the traditional framework or library in the Node.js ecosystem and is more comparable to something like .NET&apos;s WebAPI or MVC Framework than things like Express or Next in Node.js&lt;/p&gt;
&lt;p&gt;Some of the built-in features and decisions that stand out for me are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First-class Typescript support&lt;/li&gt;
&lt;li&gt;Class-based controllers&lt;/li&gt;
&lt;li&gt;Class-Based SQL ORM&lt;/li&gt;
&lt;li&gt;Dependency Injection&lt;/li&gt;
&lt;li&gt;Request Body Validation&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Server-side View Rendering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are a lot more features, and it would be impractical for me to talk about all of them in a single post. Overall, the framework seems to be very complete at this point&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;We&apos;ll be using a Node.js and a SQL Database for this post, so if you&apos;re going to follow along with this post you will need to have a couple of things installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js and NPM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Any Supported SQL Database:
&lt;ul&gt;
&lt;li&gt;MySQL&lt;/li&gt;
&lt;li&gt;SQLite&lt;/li&gt;
&lt;li&gt;Microsoft SQL Server&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;MariaDB&lt;/li&gt;
&lt;li&gt;OracleDB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Alternatively, you can run a Docker image for the database which may be easier, I&apos;ll be using Postgres via Docker with VSCode&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To learn more about VSCode Dev Containers you can look at &lt;a href=&quot;/blog/2020/25-07/developing-in-a-container-vscode/&quot;&gt;my previous post&lt;/a&gt; on how to use Dev Containers&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Initialize an Application&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve got all our necessary dependencies installed, we can initialize an application using the &lt;code&gt;npm init&lt;/code&gt; command:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;During the initialization the CLI will ask you what type of project to initialize, be sure to select &lt;code&gt;API Server&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm init adonis-ts-app my-api
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command is made up of the following parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;npm init&lt;/code&gt; which is the npm command that will run an initialization script from the provided package&lt;/li&gt;
&lt;li&gt;&lt;code&gt;adonis-ts-app&lt;/code&gt; which is the package to be used for initialization&lt;/li&gt;
&lt;li&gt;&lt;code&gt;my-api&lt;/code&gt; is the name of the folder/project we want to create&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once the project has been configured, navigate into the project directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd my-api
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And start the app:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm start
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The Ace CLI&lt;/h2&gt;
&lt;p&gt;AdonisJS makes use of a command-line application called &lt;code&gt;ace&lt;/code&gt;, &lt;code&gt;ace&lt;/code&gt; can be used to do common tasks as well as custom tasks that we define. By default, it can scaffold controllers, commands, and a bunch of other things as well as run and build an AdonisJS application&lt;/p&gt;
&lt;h2&gt;Environment Variables&lt;/h2&gt;
&lt;p&gt;AdonisJS Makes use of Environment Variables do set the application configuration, in your generated files you should see a file named &lt;code&gt;.env&lt;/code&gt;, this file contains the environment variables used by the application. Looking at this file will give us an idea of our current configuration:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;PORT=3333
HOST=0.0.0.0
NODE_ENV=development
APP_KEY=mE8zN8V_7PzazKfv9_ds-8CGjVRLA2wo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the moment, we can see that our application will be listening on host &lt;code&gt;0.0.0.0&lt;/code&gt; and port &lt;code&gt;3333&lt;/code&gt;, this means that we can access our application from our browser at &lt;code&gt;http://localhost:3333&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we open this page on our browser we will see the adonis logs kicked off in our command line, something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ℹ  info      cleaning up build directory build
ℹ  info      copy .env,ace build
☐  pending   compiling typescript source files
✔  success   built successfully
ℹ  info      copy .adonisrc.json build
…  watch     watching file system for changes
ℹ  info      starting http server
✔  create    ace-manifest.json
[1595755199986] INFO  (my-app/1531 on 47f057d8722c): started server on 0.0.0.0:3333
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first request may take some time, this is because the server is still starting itself up. In the meantime, however, let&apos;s discuss how we&apos;ll be accessing our API&lt;/p&gt;
&lt;h2&gt;Making Requests&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;You will need to use &lt;a href=&quot;https://postwoman.io/&quot;&gt;Postwoman&lt;/a&gt; or something similar when making requests&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that our application is running, we can start making requests to our API. By default, AdonisJS sets up a &lt;code&gt;hello-world&lt;/code&gt; route at the base of our application (the &lt;code&gt;/&lt;/code&gt; route`)&lt;/p&gt;
&lt;p&gt;We can reach this endpoint by simply making a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;http://localhost:3333&lt;/code&gt; which will return the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;hello&amp;quot;: &amp;quot;world&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;AdonisJS can define routes using a method similar to libraries like Express.js, the &amp;quot;Hello World&amp;quot; route is defined in the &lt;code&gt;start/routes.ts&lt;/code&gt; file and has the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;routes.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import Route from &apos;@ioc:Adonis/Core/Route&apos;

Route.get(&apos;/&apos;, async () =&amp;gt; {
  return { hello: &apos;world&apos; }
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Route.get&lt;/code&gt; portion states that this is a &lt;code&gt;GET&lt;/code&gt; route on the &lt;code&gt;/&lt;/code&gt; path with an &lt;code&gt;async&lt;/code&gt; handler function that returns an object&lt;/p&gt;
&lt;p&gt;However, for this post, we won&apos;t be defining our route&apos;s handler functions like this. We&apos;re going to make use of &lt;code&gt;controllers&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;Controllers&lt;/h2&gt;
&lt;p&gt;AdonisJS uses &lt;code&gt;controllers&lt;/code&gt; to structure our API. This makes use of a &lt;code&gt;class&lt;/code&gt; which contains functions intended to work as an interface between the HTTP request and the work we want to do via a &lt;code&gt;provider&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We will simply state which &lt;code&gt;controller&lt;/code&gt; and &lt;code&gt;method&lt;/code&gt; we want to use in our &lt;code&gt;routes.ts&lt;/code&gt; file instead of containing all the handler logic in that file&lt;/p&gt;
&lt;p&gt;To generate a controller we can use &lt;code&gt;ace&lt;/code&gt;. We will use &lt;code&gt;ace&lt;/code&gt; to create a &lt;code&gt;UsersContoller&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First, stop your running application with &lt;code&gt;ctrl + c&lt;/code&gt; in the terminal, then use the following &lt;code&gt;ace&lt;/code&gt; command to generate a &lt;code&gt;User&lt;/code&gt; &lt;code&gt;controller&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node ace make:controller User
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate an &lt;code&gt;app/Controllers/Http/UsersController.ts&lt;/code&gt; file with the following contents:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UsersController.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export default class UsersController {}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which exports a class called &lt;code&gt;UsersController&lt;/code&gt; with no default functionality&lt;/p&gt;
&lt;p&gt;We can create any functions inside of here that we want to, and then map these functions to routes. For now, let&apos;s add a &lt;code&gt;get&lt;/code&gt; function that will put some placeholder data into. We&apos;ll update this later to use our database&lt;/p&gt;
&lt;p&gt;A few things to note about the function we&apos;re going to create:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The function is asynchronous, so if there are any long-running operations it won&apos;t block other things from running&lt;/li&gt;
&lt;li&gt;The name of the function is &lt;code&gt;get&lt;/code&gt; and it has no parameters&lt;/li&gt;
&lt;li&gt;The function returns an array of objects that represents a &lt;code&gt;User&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;UsersController.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export default class UsersController {
  public async get() {
    return [
      {
        id: 1,
        name: &apos;Bob Smith&apos;,
        email: &apos;bob@smithmail.com&apos;,
      },
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have defined our function, we can add a &lt;code&gt;route&lt;/code&gt; that will cause this function to be called. We do this by adding the following in the &lt;code&gt;routes.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;Route.get(&apos;users&apos;, &apos;UsersController.get&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can then run &lt;code&gt;npm start&lt;/code&gt; from the command line and make a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;http://localhost:3333/users&lt;/code&gt; which should return our user:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;[
  {
    &amp;quot;id&amp;quot;: 1,
    &amp;quot;name&amp;quot;: &amp;quot;Bob Smith&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;bob@smithmail.com&amp;quot;
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Database&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve got some basic understanding of how AdonisJS maps routes to functionality, we can connect our application to a Database&lt;/p&gt;
&lt;p&gt;To add database functionality, we first want to install the &lt;code&gt;adonisjs/lucid&lt;/code&gt; package to our application. Behind the scenes, AdonisJS makes use of &lt;code&gt;Lucid&lt;/code&gt; for connecting to and working with databases&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm i @adonisjs/lucid@alpha
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then run the following command to initialize it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node ace invoke @adonisjs/lucid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which should give the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;   create    config/database.ts
   update    .env
   update    tsconfig.json { types += @adonisjs/lucid }
   update    .adonisrc.json { commands += @adonisjs/lucid/build/commands }
   update    .adonisrc.json { providers += @adonisjs/lucid }
✔  create    ace-manifest.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you open your &lt;code&gt;.env&lt;/code&gt; file you will see the configuration for a &lt;code&gt;sqlite&lt;/code&gt; database&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;## ... other config
DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_USER=lucid
DB_PASSWORD=lucid
DB_NAME=lucid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can follow the general database setup information on the &lt;a href=&quot;https://preview.adonisjs.com/guides/database/setup&quot;&gt;AdonisJS Docs&lt;/a&gt; to set yours up, but I&apos;ll be using Postgres as I&apos;ve mentioned before&lt;/p&gt;
&lt;p&gt;To use Postgress, you need to install the &lt;code&gt;pg&lt;/code&gt; package from npm:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm i pg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then configure your application to use Postgres. We will first update our &lt;code&gt;.env&lt;/code&gt; file to have our database credentials:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;DB_CONNECTION=pg
DB_HOST=db
DB_USER=user
DB_PASSWORD=pass
DB_NAME=data
DB_PORT=5432
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you&apos;ve configured your database connection information in the &lt;code&gt;.env&lt;/code&gt; file, our database connection information will be taken care of by AdonisJS&lt;/p&gt;
&lt;p&gt;These environment variables are used in the &lt;code&gt;config/database.ts&lt;/code&gt; file, we can see them in the &lt;code&gt;pg&lt;/code&gt; part of the file&lt;/p&gt;
&lt;p&gt;&lt;code&gt;database.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;  ...
    pg: {
      client: &apos;pg&apos;,
      connection: {
        host: Env.get(&apos;DB_HOST&apos;, &apos;127.0.0.1&apos;) as string,
        port: Number(Env.get(&apos;DB_PORT&apos;, 5432)),
        user: Env.get(&apos;DB_USER&apos;, &apos;lucid&apos;) as string,
        password: Env.get(&apos;DB_PASSWORD&apos;, &apos;lucid&apos;) as string,
        database: Env.get(&apos;DB_NAME&apos;, &apos;lucid&apos;) as string,
      },
      healthCheck: true,
    },
  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;database.ts&lt;/code&gt; file above, look for the section for your relevant database, and set the &lt;code&gt;healthCheck&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve set things up, we can create a health-check route that will enable us to view the current status of our database connection. We will add a handler for this in the &lt;code&gt;routes.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import HealthCheck from &apos;@ioc:Adonis/Core/HealthCheck&apos;
// ... existing file content

Route.get(&apos;health&apos;, async ({ response }) =&amp;gt; {
  const report = await HealthCheck.getReport()
  return report.healthy ? response.ok(report) : response.badRequest(report)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you&apos;ve done all the above, start the development server again with &lt;code&gt;npm start&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then make a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;http://localhost:3333/health&lt;/code&gt; to view your health-check information&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;healthy&amp;quot;: true,
  &amp;quot;report&amp;quot;: {
    &amp;quot;env&amp;quot;: {
      &amp;quot;displayName&amp;quot;: &amp;quot;Node Env Check&amp;quot;,
      &amp;quot;health&amp;quot;: {
        &amp;quot;healthy&amp;quot;: true
      }
    },
    &amp;quot;appKey&amp;quot;: {
      &amp;quot;displayName&amp;quot;: &amp;quot;App Key Check&amp;quot;,
      &amp;quot;health&amp;quot;: {
        &amp;quot;healthy&amp;quot;: true
      }
    },
    &amp;quot;lucid&amp;quot;: {
      &amp;quot;displayName&amp;quot;: &amp;quot;Database&amp;quot;,
      &amp;quot;health&amp;quot;: {
        &amp;quot;healthy&amp;quot;: true,
        &amp;quot;message&amp;quot;: &amp;quot;All connections are healthy&amp;quot;
      },
      &amp;quot;meta&amp;quot;: [
        {
          &amp;quot;connection&amp;quot;: &amp;quot;pg&amp;quot;,
          &amp;quot;message&amp;quot;: &amp;quot;Connection is healthy&amp;quot;,
          &amp;quot;error&amp;quot;: null
        }
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the &lt;code&gt;lucid&lt;/code&gt; section we will see if our database connection is working or any applicable error information.&lt;/p&gt;
&lt;h2&gt;Defining Models&lt;/h2&gt;
&lt;p&gt;Once we&apos;ve configured our database, we will want to interact with the data in it. Lucid makes use of &lt;code&gt;models&lt;/code&gt; essentially as proxies for database tables. We can generate a &lt;code&gt;model&lt;/code&gt; for our &lt;code&gt;User&lt;/code&gt; with &lt;code&gt;ace&lt;/code&gt; as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Stop your development server with &lt;code&gt;ctrl + c&lt;/code&gt; before running this:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node ace make:model User
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above script will have generated a &lt;code&gt;User&lt;/code&gt; model class in the &lt;code&gt;app/Models/User.ts&lt;/code&gt; file that extends &lt;code&gt;BaseModel&lt;/code&gt;. All models must do this. The generated &lt;code&gt;User.ts&lt;/code&gt; file looks like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;User.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { DateTime } from &apos;luxon&apos;
import { BaseModel, column } from &apos;@ioc:Adonis/Lucid/Orm&apos;

export default class User extends BaseModel {
  @column({ isPrimary: true })
  public id: number

  @column.dateTime({ autoCreate: true })
  public createdAt: DateTime

  @column.dateTime({ autoCreate: true, autoUpdate: true })
  public updatedAt: DateTime
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;When viewing the above file your code editor may give you a warning saying that decorators are not supported, if you see this then set the &lt;code&gt;experimentalDecorators&lt;/code&gt; property to &lt;code&gt;true&lt;/code&gt; in your &lt;code&gt;tsconfig.json&lt;/code&gt; file:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;...
  &amp;quot;compilerOptions&amp;quot;: {
    &amp;quot;experimentalDecorators&amp;quot;: true,
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;code&gt;@column&lt;/code&gt; decorators, these are used to map columns in our database to our model fields. We&apos;ll add a field for our user&apos;s &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt; as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;User.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export default class User extends BaseModel {
  // ... other stuff in class
  @column()
  public name: String

  @column()
  public email: String
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Any properties or methods defined in a class without the &lt;code&gt;@column&lt;/code&gt; decorator will not be mapped to the database, we can just use these as normal functions in the class and implement utilities from them&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Migrating the Database&lt;/h2&gt;
&lt;p&gt;At this point, our database does not contain a &lt;code&gt;user&lt;/code&gt; table, which will be used to store our data for the &lt;code&gt;User&lt;/code&gt; model. We need to create a Database Migration which will add the required table and fields.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ace&lt;/code&gt; provides us with a method to scaffold a migration file. To create this file we will run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node ace make:migration users
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will have created a &lt;code&gt;database/migrations/SOME_ID_users.ts&lt;/code&gt; file with the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;*_users.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import BaseSchema from &apos;@ioc:Adonis/Lucid/Schema&apos;

export default class Users extends BaseSchema {
  protected tableName = &apos;users&apos;

  public async up() {
    this.schema.createTable(this.tableName, (table) =&amp;gt; {
      table.increments(&apos;id&apos;)
      table.timestamps(true)
    })
  }

  public async down() {
    this.schema.dropTable(this.tableName)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The generated file (above) contains an &lt;code&gt;up&lt;/code&gt; function which will create a &lt;code&gt;users&lt;/code&gt; table with an &lt;code&gt;id&lt;/code&gt; as well as &lt;code&gt;createdAt&lt;/code&gt; and &lt;code&gt;updatedAt&lt;/code&gt; fields. We will need to modify the &lt;code&gt;up&lt;/code&gt; function to add our new fields as well:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;export default class Users extends BaseSchema {
  ...

  public async up () {
    this.schema.createTable(this.tableName, (table) =&amp;gt; {
      table.increments(&apos;id&apos;)
      table.timestamps(true)

      // our added fields
      table.string(&apos;name&apos;).notNullable()
      table.string(&apos;email&apos;).unique().notNullable()
    })
  }

  ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once we&apos;ve defined our migration script we need to build the application with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node ace build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then we can run the migration using &lt;code&gt;ace&lt;/code&gt; as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node ace migration:run
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;If there is an error in a migration script, we can rollback the migration with &lt;code&gt;node ace migration:rollback&lt;/code&gt; which will run the &lt;code&gt;down&lt;/code&gt; function in your migration&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Interact with the Database&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve got our database, we can interact with it using the &lt;code&gt;User&lt;/code&gt; model we defined earlier&lt;/p&gt;
&lt;p&gt;The first change we&apos;ll make is to modify the &lt;code&gt;get&lt;/code&gt; function to return all users. To do this we need to import &lt;code&gt;App/Models/User&lt;/code&gt; and use the &lt;code&gt;User.all&lt;/code&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import User from &apos;App/Models/User&apos;

export default class UsersController {
  public async get() {
    // get all users
    return await User.all()
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;We use &lt;code&gt;await&lt;/code&gt; because the &lt;code&gt;User.all&lt;/code&gt; function is asynchronous&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next, we&apos;ll add a function to create a &lt;code&gt;User&lt;/code&gt;. We will call it &lt;code&gt;post&lt;/code&gt;. To make this function work we need to do a couple of things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Import &lt;code&gt;HttpContextContract&lt;/code&gt; from &lt;code&gt;@ioc:Adonis/Core/HttpContext&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Retrieve the &lt;code&gt;request&lt;/code&gt; from the &lt;code&gt;HttpContextContract&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;User&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Return the created user&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { HttpContextContract } from &apos;@ioc:Adonis/Core/HttpContext&apos;
// ... other imports

export default class UsersController {
  // ... get user code above
  public async post({ request }: HttpContextContract) {
    // get the user from the request body
    const newUser = request.all() as Partial&amp;lt;User&amp;gt;

    // create a user using the object we received
    const user = await User.create(newUser)

    // return the created user object
    return user
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;request.all&lt;/code&gt; function combines the data from the request body and query string into a single object&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When we&apos;ve added that, our completed &lt;code&gt;UsersController.ts&lt;/code&gt; file should look like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UsersController.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { HttpContextContract } from &apos;@ioc:Adonis/Core/HttpContext&apos;
import User from &apos;App/Models/User&apos;

export default class UsersController {
  public async get() {
    return await User.all()
  }

  public async post({ request }: HttpContextContract) {
    const newUser = request.all() as Partial&amp;lt;User&amp;gt;
    const user = await User.create(newUser)
    return user
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we&apos;ve added a new function to our controller, we need to expose a route to it in the &lt;code&gt;routes.ts&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;routes.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;...
Route.post(&apos;users&apos;, &apos;UsersController.post&apos;)
...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Consume the API&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve created API endpoints for listing all users and creating a user we can restart our development server with &lt;code&gt;npm start&lt;/code&gt; and consume our API from wherever we want to make some HTTP requests&lt;/p&gt;
&lt;h3&gt;Create a User&lt;/h3&gt;
&lt;p&gt;To create a &lt;code&gt;User we need to make a&lt;/code&gt;POST&lt;code&gt;request to&lt;/code&gt;http://localhost:3333/users&lt;code&gt;and a Content-Type of&lt;/code&gt;application/json&lt;code&gt;with the following as the&lt;/code&gt;body` for our request:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;Bob Smith&amp;quot;,
  &amp;quot;email&amp;quot;: &amp;quot;bob@smithmail.com&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which should return a created user like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;Bob Smith&amp;quot;,
  &amp;quot;email&amp;quot;: &amp;quot;bob@smithmail.com&amp;quot;,
  &amp;quot;created_at&amp;quot;: &amp;quot;2020-07-26T14:35:25.987-00:00&amp;quot;,
  &amp;quot;updated_at&amp;quot;: &amp;quot;2020-07-26T14:35:25.988-00:00&amp;quot;,
  &amp;quot;id&amp;quot;: 4
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;We can also try to create a &lt;code&gt;User&lt;/code&gt; with the same information but we will see that this fails due to the database constraints we added in our migration script&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Next, we can get a list of all Users by making a &lt;code&gt;GET&lt;/code&gt; request to &lt;code&gt;http://localhost:333/users&lt;/code&gt; which should give us back our created users:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;[
  {
    &amp;quot;id&amp;quot;: 4,
    &amp;quot;created_at&amp;quot;: &amp;quot;2020-07-26T14:35:25.987-00:00&amp;quot;,
    &amp;quot;updated_at&amp;quot;: &amp;quot;2020-07-26T14:35:25.988-00:00&amp;quot;,
    &amp;quot;name&amp;quot;: &amp;quot;Bob Smith&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;bob@smithmail.com&amp;quot;
  }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;My overall impression of AdonisJS is pretty good. The framework feels very stable and I had much fewer issues in the process of learning it and writing this post than I have had using other more popular frameworks.&lt;/p&gt;
&lt;p&gt;AdonisJS is very well documented with code samples for most traditional tasks and is backed by some solid libraries for things like database integration&lt;/p&gt;
&lt;p&gt;Working with SQL using the framework has been fairly straightforward, and the ability to write database migrations using functionality provided by the framework instead of just tossing some wild SQL together makes it more approachable&lt;/p&gt;
&lt;p&gt;Personally, however, I prefer no-SQL databases like MongoDB and tend to use them more often when using JavaScript or TypeScript, but I feel like if the need arises for a SQL database then AdonisJS is a really good option, especially if you&apos;re a JavaScript developer and don&apos;t want to have to learn Java or C# for this type of functionality&lt;/p&gt;
&lt;p&gt;There is also a &lt;strong&gt;lot&lt;/strong&gt; more functionality than what I&apos;ve gone through in this post, so I&apos;d recommend browsing &lt;a href=&quot;https://preview.adonisjs.com/&quot;&gt;the AdonisJS docs&lt;/a&gt; to get a broader sense of what the framework entails&lt;/p&gt;
&lt;p&gt;If you feel like playing around with the code I&apos;ve gone through in this post without having to write it all then I&apos;ve got it all &lt;a href=&quot;https://github.com/nabeelvalley/blog-code/tree/post/adonisjs-first-look&quot;&gt;on GitHub&lt;/a&gt; and it should just be plug-and-play using Visual Studio Code Remote Containers. If you want to learn more about that, then you can check out &lt;a href=&quot;/blog/2020/25-07/developing-in-a-container-vscode/&quot;&gt;my previous blog post&lt;/a&gt; on developing within a container&lt;/p&gt;
</content:encoded></item><item><title>Automate Anything with GitHub Actions</title><link>https://nabeelvalley.co.za/blog/2020/11-08/automate-anything-with-actions/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/11-08/automate-anything-with-actions/</guid><description>Build a GitHub action that updates your Twitter Profile</description><pubDate>Tue, 11 Aug 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://github.com/nabeelvalley/twitter-bio-update/workflows/Build%20Action%20Dist/badge.svg&quot; alt=&quot;Build Action Dist&quot;&gt;
&lt;img src=&quot;https://github.com/nabeelvalley/twitter-bio-update/workflows/Run%20Twitter%20Bio%20Action/badge.svg&quot; alt=&quot;Run Twitter Bio Action&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can take a look at the Action we build in this post &lt;a href=&quot;https://github.com/nabeelvalley/twitter-bio-update/actions&quot;&gt;here on GitHub&lt;/a&gt;. I&apos;ve also included an action that&apos;s responsible for building and updating the action &lt;code&gt;dist&lt;/code&gt; which may also be of interest. It&apos;s all in &lt;a href=&quot;https://github.com/nabeelvalley/twitter-bio-update&quot;&gt;this Repository&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A few weeks ago I was playing around with GitHub actions and the recently introduced GitHub Account README functionality and wanted a way to make this &amp;quot;static&amp;quot; file a bit more dynamic&lt;/p&gt;
&lt;p&gt;Enter GitHub Actions. GitHub actions are a way for you to define and run programmatic tasks. If you can put it in code, then you can run it as an action&lt;/p&gt;
&lt;p&gt;Usually, you&apos;ll be using actions that have been defined by GitHub or another developer for common tasks, such as running your application CI or deployment processes. However, since actions are &lt;strong&gt;extremely&lt;/strong&gt; generic, we&apos;re going to do something a little different - update our Twitter bio?&lt;/p&gt;
&lt;p&gt;In this post, we&apos;re going create a GitHub action that uses the Twitter API to update our bio, as well as make the action we created run automatically on GitHub&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a GitHub Repository for us to work in&lt;/li&gt;
&lt;li&gt;Set up Twitter Developer Credentials&lt;/li&gt;
&lt;li&gt;Write a Node.js script that uses the Twitter API&lt;/li&gt;
&lt;li&gt;Configure our GitHub Action Metadata&lt;/li&gt;
&lt;li&gt;Add our Twitter Secrets in GitHub&lt;/li&gt;
&lt;li&gt;Configure a GitHub Action that will run our script (an action, within an action)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/downloads&quot;&gt;Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt; or any other Code Editor&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Create a GitHub Repo&lt;/h2&gt;
&lt;p&gt;For us to run our action we&apos;ll need a GitHub Repository to use, to create a Repo go to &lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt; and sign in, thereafter go the &lt;a href=&quot;https://github.com/new&quot;&gt;&apos;Create a new repository page&apos;&lt;/a&gt; and fill in the details, be sure to select &lt;code&gt;Initialize this repository with a README&lt;/code&gt;, pick &lt;code&gt;Node&lt;/code&gt; as the &lt;code&gt;.gitignore&lt;/code&gt; file, and select a license if you&apos;d like to&lt;/p&gt;
&lt;p&gt;Once you&apos;ve done that, click &lt;code&gt;Create repository&lt;/code&gt; and you should see the initial files we added to the Repo. Next, click on the &lt;code&gt;Code&lt;/code&gt; button and copy the URL in the text box&lt;/p&gt;
&lt;p&gt;Now, from a terminal, you will need to clone the repository. Run the following command and make sure to paste the link you just copied in place of &lt;code&gt;&amp;lt;YOUR URL&amp;gt;&lt;/code&gt; below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git clone &amp;lt;YOUR URL&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, open the folder you just cloned in your code editor and create a new file called &lt;code&gt;.env&lt;/code&gt; in the folder root directory. We&apos;ll keep our Twitter credentials in this file for testing. For now, just add the following to the file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;TWITTER_CONSUMER_KEY=
TWITTER_CONSUMER_SECRET=
TWITTER_ACCESS_KEY=
TWITTER_ACCESS_SECRET=
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the next step, we&apos;re going to get the credentials from Twitter, we&apos;ll add them into the file above when we&apos;re done&lt;/p&gt;
&lt;h2&gt;Get Some Twitter Cred.&lt;/h2&gt;
&lt;p&gt;Twitter exposes the Twitter Developer API that allows us to do all kinds of useful and pointless things by interacting with Twitter&apos;s data&lt;/p&gt;
&lt;p&gt;For us to consume the Twitter API we require credentials for the API. To set these up we&apos;ll need to do a few things&lt;/p&gt;
&lt;p&gt;First, open your browser on &lt;a href=&quot;https://developer.twitter.com/&quot;&gt;the Twitter Developer Portal&lt;/a&gt; and click the sign-in button. Then, once you&apos;ve signed in, you should see your name on the top right of the page, click on the dropdown arrow and select &lt;code&gt;Apps&lt;/code&gt; to go to the App Dashboard&lt;/p&gt;
&lt;p&gt;On the App Dashboard, click &lt;code&gt;Create an app&lt;/code&gt; and fill in the &lt;strong&gt;required&lt;/strong&gt; information. For the &lt;code&gt;Website URL&lt;/code&gt; you can put the URL of your GitHub repository that you copied previously into this field. Once you&apos;ve filled in all the details click &lt;code&gt;Create&lt;/code&gt; at the bottom of the page&lt;/p&gt;
&lt;p&gt;You should now see the Details Page for the app we just created. Next, click on the &lt;code&gt;Keys and Tokens&lt;/code&gt; tab and click &lt;code&gt;Generate&lt;/code&gt; then copy and paste each token after the &lt;code&gt;=&lt;/code&gt; in the &lt;code&gt;.env&lt;/code&gt; file we created without any spaces before or after the key&lt;/p&gt;
&lt;p&gt;When you&apos;ve pasted your tokens into their places, your &lt;code&gt;.env&lt;/code&gt; file should look something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that using the template for &lt;code&gt;.gitignore&lt;/code&gt; that we chose, the &lt;code&gt;.env&lt;/code&gt; file will be automatically ignored. Don&apos;t publically upload this data just anywhere as it can potentially give someone access to your Twitter account&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;.env&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;TWITTER_CONSUMER_KEY=xxxxxxxxxxxxxxxxxxxxxx
TWITTER_CONSUMER_SECRET=xxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_SECRET=xxxxxxxxxxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(With the actual keys, and not just &lt;code&gt;xxxx&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve got our credentials set up, we can start to work on the application&lt;/p&gt;
&lt;h2&gt;Using the Twitter API&lt;/h2&gt;
&lt;p&gt;We&apos;re going to be writing a script that runs on Node.js (JavaScript) and makes use of the Twitter API using the &lt;code&gt;twit&lt;/code&gt; library for Node.js and the GitHub libraries for working with GitHub actions&lt;/p&gt;
&lt;p&gt;To get started, run the following command from a terminal within your repository&apos;s directory to initialize a new Node.js project and select the defaults for all the questions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm init -y
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we&apos;ll add the dependencies that our application is going to need to run:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@actions/core&lt;/code&gt; allows us to interact with the data provided to our action by GitHub&lt;/li&gt;
&lt;li&gt;&lt;code&gt;twit&lt;/code&gt; is used to interact with the Twitter API&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dotenv&lt;/code&gt; enables us to load in our &lt;code&gt;.env&lt;/code&gt; file so our application can use it&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;npm install @actions/core twit dotenv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the application is done installing we&apos;ll create an &lt;code&gt;index.js&lt;/code&gt; file inside of our repo folder and we can get started on our code&lt;/p&gt;
&lt;p&gt;Inside of the &lt;code&gt;index.js&lt;/code&gt; the first thing we&apos;ll want to do is import our environment variables from the &lt;code&gt;.env&lt;/code&gt; file we configured, we&apos;ll do that using the &lt;code&gt;dotenv&lt;/code&gt; NPM Package we installed previously:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;require(&apos;dotenv&apos;).config()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we&apos;ll configure a new &lt;code&gt;Twitter&lt;/code&gt; API Client using our environment variables. The &lt;code&gt;twitter&lt;/code&gt; Package exports a &lt;code&gt;Twitter&lt;/code&gt; class that we can create an instance of, do to this we will use the &lt;code&gt;Twitter&lt;/code&gt; constructor and get our environment variables that are all stored in the &lt;code&gt;process.env&lt;/code&gt; variable:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const Twitter = require(&apos;twitter&apos;)

const client = new Twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_KEY,
  access_token_secret: process.env.TWITTER_ACCESS_SECRET,
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we&apos;ve got an instance of a &lt;code&gt;Twitter&lt;/code&gt; client that we can use to interact with the API we&apos;ll want to use it&lt;/p&gt;
&lt;p&gt;The Twitter API Client runs asynchronously, for us to work with it correctly we have two options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using the &lt;code&gt;callback&lt;/code&gt; method, which means that we give the &lt;code&gt;client&lt;/code&gt; a function to run when it&apos;s done sending the data to Twitter. While this is easier in our specific circumstance it can become difficult to keep track of when we have many different callback functions&lt;/li&gt;
&lt;li&gt;The second option is to use &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; syntax, which allows us to write our code more sequentially and makes it easier for us to control our sequence and flow&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To use the &lt;code&gt;async/await&lt;/code&gt; functionality, we need the code that we need to &lt;code&gt;await&lt;/code&gt; to be inside of an &lt;code&gt;async&lt;/code&gt; function. In this one function, we can &lt;code&gt;await&lt;/code&gt; as many tasks as we want sequentially without worrying about callbacks&lt;/p&gt;
&lt;p&gt;We&apos;ll create a &lt;code&gt;main&lt;/code&gt; function that is &lt;code&gt;async&lt;/code&gt; in which we will do any asynchronous interactions, in our case - interact with Twitter&lt;/p&gt;
&lt;p&gt;After the code we&apos;ve already got in our &lt;code&gt;index.js&lt;/code&gt; file, define the &lt;code&gt;main&lt;/code&gt; function as follows:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const main = async () =&amp;gt; {
  // this is where we&apos;ll work with the twitter client
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, we&apos;ll add the code to interact with the Twitter API inside of this function. To update our Profile Bio (or &lt;code&gt;description&lt;/code&gt; as it&apos;s called in the Twitter API) we&apos;ll make use of the &lt;code&gt;account/update_profile&lt;/code&gt; endpoint&lt;/p&gt;
&lt;p&gt;The data we send the Twitter API will need to be an object with a &lt;code&gt;description&lt;/code&gt; property for what we want to set our Twitter Bio as. We&apos;ll &lt;code&gt;await&lt;/code&gt; this function call by adding it within our &lt;code&gt;main&lt;/code&gt; function:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const main = async () =&amp;gt; {
  const response = await client.post(&apos;account/update_profile&apos;, {
    description: &apos;Hello, World!&apos;,
  })

  console.log(response)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code will set our Twitter &lt;code&gt;description&lt;/code&gt; to &lt;code&gt;Hello, World!&lt;/code&gt; and then print our the &lt;code&gt;response&lt;/code&gt; we get back from Twitter&lt;/p&gt;
&lt;p&gt;The way we&apos;ve written the above code is a little bit dangerous as we aren&apos;t handling any potential errors/failures that may happen when interacting with the Twitter API&lt;/p&gt;
&lt;p&gt;When working with an API via an HTTP Request there&apos;s always the chance that there could be an error. Errors can be caused by anything ranging from poor network connections, incorrect credentials, or a system outage on the API host itself&lt;/p&gt;
&lt;p&gt;For our application to give us a bit more information about what happened, we may want to handle the error before passing it on to the process that kicked off our script. We&apos;ll make use of a &lt;code&gt;try/catch&lt;/code&gt; to handle this error:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const main = async () =&amp;gt; {
  try {
    const response = await client.post(&apos;account/update_profile&apos;, {
      description: &apos;Hello, World!&apos;,
    })

    console.log(response)
  } catch (error) {
    console.error(error)
    throw new Error(
      `The Twitter API Responded with an Error: ${error[0].code}, ${error[0].message}`
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see above that we&apos;re just doing some cleanup of the error message before throwing the exception to the process&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve fully defined our &lt;code&gt;client&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; functions we can call the function as the last line of the script:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should make a request to the Twitter API and print our the &lt;code&gt;response&lt;/code&gt; or &lt;code&gt;error&lt;/code&gt; if there is one&lt;/p&gt;
&lt;p&gt;So, the above function will always set our Twitter Bio to the same value, this isn&apos;t interesting. Next, we&apos;d like to get some data from the workflow that&apos;s going to be running our action. The way we would do this is with an &lt;code&gt;input&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Our action is going to take an &lt;code&gt;input&lt;/code&gt; called &lt;code&gt;bio&lt;/code&gt;. We can use the &lt;code&gt;@actions/core&lt;/code&gt; library to get the value of the &lt;code&gt;input&lt;/code&gt;. We can do this with the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const core = require(&apos;@actions/core&apos;)

const bio = core.getInput(&apos;bio&apos;) || &apos;Hello, World!&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above code also sets a default value of &lt;code&gt;Hello, World!&lt;/code&gt; to the description, this will allow us to also run the action without throwing an exception on our local machine as well as if the &lt;code&gt;bio&lt;/code&gt; is not provided to the action&lt;/p&gt;
&lt;p&gt;Furthermore, instead of just throwing errors, we can rather set the error-status using the &lt;code&gt;core.setFailed&lt;/code&gt; function. Updating our &lt;code&gt;main&lt;/code&gt; function to do this we now have:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const main = async () =&amp;gt; {
  try {
    const response = await client.post(&apos;account/update_profile&apos;, {
      description: bio,
    })

    console.log(response)
  } catch (error) {
    console.error(error)
    core.setFailed(
      `The Twitter API Responded with an Error: ${error[0].code}, ${error[0].message}`
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, our full &lt;code&gt;index.js&lt;/code&gt; file should look like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;re(&apos;dotenv&apos;).config()

const Twitter = require(&apos;twitter&apos;)
const core = require(&apos;@actions/core&apos;)

const bio = core.getInput(&apos;bio&apos;) || &apos;Hello, World!&apos;

const client = new Twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_KEY,
  access_token_secret: process.env.TWITTER_ACCESS_SECRET,
})

const main = async () =&amp;gt; {
  try {
    const response = await client.post(&apos;account/update_profile&apos;, {
      description: bio,
    })

    console.log(response)
  } catch (error) {
    console.error(error)
    core.setFailed(
      `The Twitter API Responded with an Error: ${error[0].code}, ${error[0].message}`
    )
  }
}

main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we&apos;ve written the functionality for our action we&apos;ll want to turn it into an action&lt;/p&gt;
&lt;h2&gt;Configure the Action Metadata&lt;/h2&gt;
&lt;p&gt;For GitHub to recognise our code as an action, we need to create an &lt;code&gt;action.yml&lt;/code&gt; file that contains a description of our action. Our &lt;code&gt;action.yml&lt;/code&gt; file needs to have the following information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; for our action&lt;/li&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt; of the action itself&lt;/li&gt;
&lt;li&gt;an &lt;code&gt;input&lt;/code&gt; parameter of &lt;code&gt;bio&lt;/code&gt; that will be used by our application&lt;/li&gt;
&lt;li&gt;&lt;code&gt;runs&lt;/code&gt; which states the script to run&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;action.yml&lt;/code&gt; file for our action looks like the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;action.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: &apos;Twitter Bio Update&apos;
description: &apos;Update your Twitter Account Bio&apos;
inputs:
  bio:
    description: &apos;Text that you would like to set as your Twitter Bio&apos;
    required: true
    default: &apos;Hello, World!&apos;
runs:
  using: &apos;node12&apos;
  main: &apos;index.js&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fields we&apos;ve got above are all pretty much required. The above fields are the simplest configuration for a Node.js action. The &lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Docs&lt;/a&gt; have a lot more information on more complex configurations and actions&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve defined our action, we will want to configure it to run. But before we can do that, we&apos;ll want to set up our secrets&lt;/p&gt;
&lt;h2&gt;Setting Up Secrets in GitHub&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve got our action defined, we&apos;re almost ready to write a Workflow that will use this action. However, our action requires environment variables (that we&apos;ve got saved in our &lt;code&gt;.env&lt;/code&gt; file) but we don&apos;t want these to be pushed to GitHub as part of our source code. The way to set up these environment variables in GitHub is called a &lt;code&gt;secret&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To add our environment variables in GitHub you&apos;ll need to open your Repo on GitHub and navigate to &lt;code&gt;Settings &amp;gt; Secrets&lt;/code&gt; then click &lt;code&gt;New secret&lt;/code&gt; and add your first secret. If we use our &lt;code&gt;.env&lt;/code&gt; file as a reference we&apos;ll want to create a secret for each line in the file. To do this look at the name of the environment variable (everything before the &lt;code&gt;=&lt;/code&gt;) and set this as the &lt;code&gt;Name&lt;/code&gt; for the secret, then look at the value (everything after the &lt;code&gt;=&lt;/code&gt;) and set this as the &lt;code&gt;Value&lt;/code&gt; for the secret then click &lt;code&gt;Add secret&lt;/code&gt;. Do this for every line in your &lt;code&gt;.env&lt;/code&gt; file (every environment variable`&lt;/p&gt;
&lt;h2&gt;Create a Workflow&lt;/h2&gt;
&lt;p&gt;Workflows are GitHub&apos;s way of tying together a bunch of actions to run. Often, we will want to run multiple actions. We place these into what&apos;s called a &lt;code&gt;step&lt;/code&gt; in a &lt;code&gt;job&lt;/code&gt;. Each Workflow can have multiple &lt;code&gt;steps&lt;/code&gt; and &lt;code&gt;jobs&lt;/code&gt; and a repository can have multiple workflows&lt;/p&gt;
&lt;p&gt;The structure of a workflow is something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;workflow
|-- Job 1
|   |-- Step 1
|   |-- Step 2
|-- Job 2
    |-- Step 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A Workflow can have any number of jobs and steps&lt;/p&gt;
&lt;p&gt;We&apos;re going to create a Workflow with a single job with the goal of running our script. For us to do this, the job will need to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Checkout our code&lt;/li&gt;
&lt;li&gt;Configure Node.js and NPM&lt;/li&gt;
&lt;li&gt;Install Dependencies&lt;/li&gt;
&lt;li&gt;Run our Action&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To do Steps 1 and 2 we&apos;re going to use actions that are defined by GitHub. We&apos;re going to go through our Workflow file working from the top-down as this is the order in which everything will be run&lt;/p&gt;
&lt;p&gt;Firstly, we&apos;ll need to create a new directory in our Repository named &lt;code&gt;.github&lt;/code&gt; and inside of this another called &lt;code&gt;workflows&lt;/code&gt;. Inside of the &lt;code&gt;.github/workflows&lt;/code&gt; directory create a file named &lt;code&gt;main.yml&lt;/code&gt; (this can be any name so long as it&apos;s a &lt;code&gt;yml&lt;/code&gt; file)&lt;/p&gt;
&lt;p&gt;Next, on the first line of this file we will define a name for our workflow like so:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Run Twitter Bio Action
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the name that will be displayed when the workflow runs. Actions are run when a specific GitHub event happens (more about that &lt;a href=&quot;https://docs.github.com/en/actions/reference/events-that-trigger-workflows&quot;&gt;in the Docs&lt;/a&gt;). We&apos;re going to configure our action to run manually only, so we will use the &lt;code&gt;workflow_dispatch&lt;/code&gt; event. After the &lt;code&gt;name&lt;/code&gt; in the &lt;code&gt;main.yml&lt;/code&gt; file, add the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;on:
  workflow_dispatch:
    inputs:
      bio:
        description: &apos;Twitter Bio&apos;
        required: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above, we set an &lt;code&gt;on&lt;/code&gt; event for &lt;code&gt;workflow_dispatch&lt;/code&gt; with an &lt;code&gt;input&lt;/code&gt; for &lt;code&gt;bio&lt;/code&gt; that we&apos;re going to pass on to our action&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve got the workflow metadata defined, we&apos;re going to add a &lt;code&gt;job&lt;/code&gt;. To do this, we&apos;ll add a &lt;code&gt;jobs&lt;/code&gt; object with a name of &lt;code&gt;update-bio&lt;/code&gt;, a specification on what OS it needs to run on, and the &lt;code&gt;steps&lt;/code&gt; that will be a part of it:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;jobs:
  update-bio:
    runs-on: ubuntu-latest
    name: Update Twitter Bio
    steps:
      # we&apos;ll add the steps here in a moment
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see above that we&apos;re running on the &lt;code&gt;ubuntu-latest&lt;/code&gt; OS. Next, we&apos;ll add the first step for checking out our code in the action. This will use &lt;code&gt;actions/checkout&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;steps:
  - name: Checkout
    uses: actions/checkout@v2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above, we give our step a &lt;code&gt;name&lt;/code&gt; which is for display purposes, and a &lt;code&gt;uses&lt;/code&gt; which says what action this step should use. In our case, we&apos;re checking out our code using the &lt;code&gt;actions/checkout@v2&lt;/code&gt; action&lt;/p&gt;
&lt;p&gt;Next, we&apos;ll want to configure Node.js and NPM because our action needs these to run. We can use the &lt;code&gt;actions/setup-node@v1&lt;/code&gt; for this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;- name: Setup Node.js
  uses: actions/setup-node@v1
  with:
    node-version: 12.x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this action, we use the &lt;code&gt;with&lt;/code&gt; to state an &lt;code&gt;input&lt;/code&gt; that the action needs. In this case, we specify that we want to use a &lt;code&gt;node-version&lt;/code&gt; of &lt;code&gt;12.x&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now we&apos;ve got Node.js and NPM, we need to install the dependencies for our action to run. We do this with the &lt;code&gt;npm install&lt;/code&gt; command like so:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;- name: Install Dependencies
  run: npm install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And lastly, we will configure our action to run with the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;- name: Run Action
  uses: ./
  env:
    TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }}
    TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }}
    TWITTER_ACCESS_KEY: ${{ secrets.TWITTER_ACCESS_KEY }}
    TWITTER_ACCESS_SECRET: ${{ secrets.TWITTER_ACCESS_SECRET }}
  with:
    bio: ${{ github.event.inputs.bio }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this last step we&apos;re doing quite a few things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We&apos;re setting a &lt;code&gt;name&lt;/code&gt; for our action&lt;/li&gt;
&lt;li&gt;We set a &lt;code&gt;uses&lt;/code&gt; to be &lt;code&gt;./&lt;/code&gt; which means we want to run the action at the root of our Repo (our &lt;code&gt;action.yml&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;We set the &lt;code&gt;env&lt;/code&gt;, these are the different environment variables we want to pass to the application. We use &lt;code&gt;${\{ ... }\}&lt;/code&gt; to mean that it&apos;s a variable, and we use &lt;code&gt;secrets.variable&lt;/code&gt; to access the variable from the secrets we configured in the repository&lt;/li&gt;
&lt;li&gt;We use the &lt;code&gt;with&lt;/code&gt; to set the &lt;code&gt;bio&lt;/code&gt; from the input we give to the workflow on our &lt;code&gt;workflow_dispatch&lt;/code&gt; event. GitHub exposes this in the &lt;code&gt;github.event.inputs.bio&lt;/code&gt; variable&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;With the &lt;code&gt;Run Action&lt;/code&gt; step added, we&apos;ve got a full workflow. The overall &lt;code&gt;main.yml&lt;/code&gt; file should have the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;main.yml&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;name: Run Twitter Bio Action
on:
  workflow_dispatch:
    inputs:
      bio:
        description: &apos;Twitter Bio&apos;
        required: true

jobs:
  update-bio:
    runs-on: ubuntu-latest
    name: Update Twitter Bio
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup Node.js
        uses: actions/setup-node@v1
        with:
          node-version: 12.x
      - name: Install Dependencies
        run: npm install
      - name: Run Action
        uses: ./
        env:
          TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }}
          TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }}
          TWITTER_ACCESS_KEY: ${{ secrets.TWITTER_ACCESS_KEY }}
          TWITTER_ACCESS_SECRET: ${{ secrets.TWITTER_ACCESS_SECRET }}
        with:
          bio: ${{ github.event.inputs.bio }}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Run the Action&lt;/h2&gt;
&lt;p&gt;To run the action, we first need to get everything to GitHub. From Repo directory, in the terminal, run the following commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;git add .
git commit -m &amp;quot;I made a GitHub Action!&amp;quot;
git push
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, go to your repository on GitHub and click on the &lt;code&gt;Actions&lt;/code&gt; tab. You should then see your Workflow listed. Click on your workflow name, and then the &lt;code&gt;Run workflow&lt;/code&gt; dropdown. Fill in your &lt;code&gt;Twitter Bio&lt;/code&gt;, wait for the workflow to complete and look at your Twitter profile!&lt;/p&gt;
&lt;p&gt;From GitHub, you are also able to inspect and view any logs or errors from a Workflow run. If the workflow fails you can also take a look at the output that was thrown by the step that resulted in the failure&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;And that&apos;s about it. We&apos;ve taken a look at how you can use GitHub actions to automate a pretty silly task, but there&apos;s a lot more to using GitHub Actions, and the sky&apos;s the limit in terms of what you can use them for&lt;/p&gt;
&lt;p&gt;Overall, GitHub actions aren&apos;t too different from similar options like Azure Pipelines, Jenkins, or any other CI service. What makes them so useful is how easily they hook into the source control system and how well they work and are supported within the GitHub ecosystem&lt;/p&gt;
&lt;p&gt;That all being said, they&apos;re not the easiest things to configure and it can take a while to get them right if you&apos;re doing something especially complex. Overall they&apos;re pretty cool and are a pretty good place to get started with automating tasks and working with things like continuous integration and deployments and I&apos;d definitely recommend giving them a shot&lt;/p&gt;
</content:encoded></item><item><title>Code in a Container</title><link>https://nabeelvalley.co.za/blog/2020/25-07/developing-in-a-container-vscode/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/25-07/developing-in-a-container-vscode/</guid><description>Using a Docker Container as a development container using the Visual Studio Code Remote-Containers Extension</description><pubDate>Sat, 25 Jul 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I&apos;d started using Visual Studio Code&apos;s &lt;em&gt;Remote Containers&lt;/em&gt; functionality for development and it&apos;s been really useful&lt;/p&gt;
&lt;p&gt;The Remote Containers extension allows us to write code and develop applications within a virtualized environment that makes it easier for us to manage our development environment as well as more closely resemble our target deployment environment (if we&apos;re deploying to Docker or Kubernetes)&lt;/p&gt;
&lt;p&gt;In this post, I&apos;ll take a look at what a Docker container is, why we would want to use one as a development environment, and how we can go about setting one up for VSCode&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;If you intend to follow along with this post you&apos;ll need to have the following installed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Windows or Mac OS version capable of running Docker Desktop&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/desktop/#download-and-install&quot;&gt;Docker Desktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers&quot;&gt;Visual Studio Code&apos;s Remote Containers Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker&quot;&gt;Visual Studio Code&apos;s Docker Extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Some familiarity with using the command line&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Docker Containers&lt;/h2&gt;
&lt;p&gt;A Container, in this context, is a simple virtual machine that contains the code required to run an application with all its dependencies&lt;/p&gt;
&lt;p&gt;A Docker container is built from a &lt;code&gt;docker image&lt;/code&gt; and run by the &lt;code&gt;docker&lt;/code&gt; command. I&apos;ll explain these as we go along&lt;/p&gt;
&lt;p&gt;To check that Docker is installed correctly on your machine run the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If your install is working correctly you should see something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Unable to find image &apos;hello-world:latest&apos; locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete

Digest: sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202
Status: Downloaded newer image for hello-world:latest

Hello from Docker

...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Docker Images&lt;/h2&gt;
&lt;p&gt;Docker images are typically used to run applications in a production-type environment, every Docker container we run needs to be based on an image, every running container is like an instance of an image - similar to how objects are an instance of a class&lt;/p&gt;
&lt;p&gt;An image states what our container will need to be made of, what it depends on, and how it runs. We define how docker should build our image in a &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We&apos;re going to go through some of the basics of Docker Images and Docker as would typically be done when creating a container to be run in production before we get into development containers so you&apos;ve got an understanding of how this all works&lt;/p&gt;
&lt;p&gt;To get started create a new folder and open it from Visual Studio Code and do the following:&lt;/p&gt;
&lt;h3&gt;Create an Application&lt;/h3&gt;
&lt;p&gt;We&apos;ll need a simple &amp;quot;hello-world&amp;quot; web server using Node.js, for the sake of example. You can, however, use any language (or Languages) you want when creating an application to run within Docker. You do not need to have any dependencies for the specific application or language installed on your computer, we will handle this using Docker&lt;/p&gt;
&lt;p&gt;For our purpose, create a file called &lt;code&gt;index.js&lt;/code&gt; with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const http = require(&apos;http&apos;)

const requestListener = function (req, res) {
  res.writeHead(200)
  res.end(&apos;Hello, World!&apos;)
}

const serverListeningCallback = function () {
  console.log(&apos;Server started&apos;)
}

const server = http.createServer(requestListener)
server.listen(8080, serverListeningCallback)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see in the above on the last line that the application will listen on port 8080, just keep this in mind&lt;/p&gt;
&lt;p&gt;We don&apos;t need to run this file as yet, but if we want, we can run this with the following command from our working directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;node app.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point our working directory should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;working-directory
|__ index.js
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create a Dockerfile&lt;/h3&gt;
&lt;p&gt;There are a few steps that are the same for most &lt;code&gt;Dockerfile&lt;/code&gt;s you&apos;ll be building:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A Base Image that your container/image should use, in our case &lt;code&gt;node:12&lt;/code&gt;, which has &lt;code&gt;node&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; preinstalled&lt;/li&gt;
&lt;li&gt;Copy all the code in the current (&lt;code&gt;.&lt;/code&gt;) directory&lt;/li&gt;
&lt;li&gt;Define your runtime port/ports (in the case of a web application)&lt;/li&gt;
&lt;li&gt;The command that will be run to start the application&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Any line starting with a &lt;code&gt;#&lt;/code&gt; is a comment, Docker will ignore these&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;## step 1 - FROM baseImage
FROM node:12

## step 2 - COPY source destination
COPY . .

## step 3 - EXPOSE port
EXPOSE 8080

## step 4 - CMD stratupCommandArray
CMD [&amp;quot;node&amp;quot;, &amp;quot;app.js&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point our working directory should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;working-directory
|__ index.js
|__ Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can build our image, based on the &lt;code&gt;Dockerfile&lt;/code&gt; using the following &lt;code&gt;docker&lt;/code&gt; command:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note the &lt;code&gt;.&lt;/code&gt; at the end of the command&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;docker build -t my-docker-app .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above command can be broken down as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;docker build&lt;/code&gt; the command from the Docker CLI to build an image&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-t my-docker-app&lt;/code&gt; says what we want our image to be called, in the above &lt;code&gt;my-docker-app&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.&lt;/code&gt; which is the directory in which the &lt;code&gt;Dockerfile&lt;/code&gt; is located, in our case our current directory&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can then run the image we just built like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -p 8080:8080 my-docker-app
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;docker run&lt;/code&gt; is the command from the &lt;code&gt;Docker CLI&lt;/code&gt; to run a container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p 8080:8080&lt;/code&gt; is our port mapping, it is ordered as &lt;code&gt;HOST_PORT:CONTAINER_PORT&lt;/code&gt; and allows us to say which port on our host we want to map to our container, the container port is the same port that our app listens on and is &lt;code&gt;EXPOSE&lt;/code&gt;d in the &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;my-docker-app&lt;/code&gt; is the image tag we would like to run&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Each time we change the app files for a container like above we need to rebuild the container before running, and that normally making changes to files during the image build or container run will not modify the original files on our computer&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that the application is running on port &lt;code&gt;8080&lt;/code&gt; you can open &lt;code&gt;http://localhost:8080&lt;/code&gt; in your browser and you should see your &lt;code&gt;Hello World&lt;/code&gt; app running&lt;/p&gt;
&lt;p&gt;When you&apos;re done with that you can go back to the terminal where the container was started and use &lt;code&gt;ctrl + c&lt;/code&gt; to stop the container&lt;/p&gt;
&lt;p&gt;If you&apos;ve never used Docker before and have got everything running this far, congratulations! If you&apos;ve got any questions you can comment below or hit me up on &lt;a href=&quot;https://twitter.com/not_nabeel&quot;&gt;Twitter @not_nabeel&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Moving swiftly along&lt;/p&gt;
&lt;h2&gt;Development Containers&lt;/h2&gt;
&lt;p&gt;So now that we understand a bit about containers and how we can go about using them in production, we&apos;ll look at why we may want to use them as a development environment&lt;/p&gt;
&lt;h3&gt;Why Develop in a Container&lt;/h3&gt;
&lt;p&gt;As developers, we are far too familiar with the &amp;quot;it runs on my machine&amp;quot; dilemma. Development environments can be wildly inconsistent between different developers or different operating systems, and ensuring that our development code runs easily on everyone&apos;s computer can be challenging&lt;/p&gt;
&lt;p&gt;Containers can help us to explicitly define our development environment, our application dependencies, what networking relationships, and (potentially) what other sibling applications need to be running in development, like databases, or other application tiers&lt;/p&gt;
&lt;p&gt;Visual Studio Code can help transport us into a container so that we work on our application in a well-defined environment, not just run our application within one while reducing the overall number of things we need to have installed on our computer&lt;/p&gt;
&lt;h3&gt;How to Develop in a Container&lt;/h3&gt;
&lt;p&gt;To develop in a Container using Visual Studio Code we will need to have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/desktop/#download-and-install&quot;&gt;Docker Desktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers&quot;&gt;Visual Studio Code&apos;s Remote Containers Extension&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;What&apos;s important to note is that we don&apos;t need any of our application&apos;s runtime or development dependencies installed, like Node.js, these will all be handled by VSCode within our container&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To configure our project for running in a container we need to first open the project folder (the folder we used previously) in Visual Studio Code&lt;/p&gt;
&lt;h4&gt;Use an Existing Dockerfile&lt;/h4&gt;
&lt;p&gt;Once open use the keyboard shortcut &lt;code&gt;ctrl + shift + p&lt;/code&gt; to open the Command Palette and search for &lt;code&gt;Remote-Containers: Add Development Container Configuration Files&lt;/code&gt; and click &lt;code&gt;enter&lt;/code&gt;, you will then have an option to use the existing Dockerfile &lt;code&gt;from Dockerfile&lt;/code&gt; which will generate a &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; file&lt;/p&gt;
&lt;p&gt;At this point our working directory should look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;working-directory
|__ .devcontainer
|   |__ devcontainer.json
|
|__ index.js
|__ Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; file that was created will contain the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;devcontainer.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file&apos;s README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.128.0/containers/docker-existing-dockerfile
{
    &amp;quot;name&amp;quot;: &amp;quot;Existing Dockerfile&amp;quot;,

    // Sets the run context to one level up instead of the .devcontainer folder.
    &amp;quot;context&amp;quot;: &amp;quot;..&amp;quot;,

    // Update the &apos;dockerFile&apos; property if you aren&apos;t using the standard &apos;Dockerfile&apos; filename.
    &amp;quot;dockerFile&amp;quot;: &amp;quot;..\\Dockerfile&amp;quot;,

    // Set *default* container specific settings.json values on container create.
    &amp;quot;settings&amp;quot;: {
        &amp;quot;terminal.integrated.shell.linux&amp;quot;: null
    },

    // Add the IDs of extensions you want installed when the container is created.
    &amp;quot;extensions&amp;quot;: []

    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above file is the configuration for our development container, we can also allow VSCode to generate a Dockerfile which we&apos;ll look at later in the post&lt;/p&gt;
&lt;p&gt;We&apos;ll stick to our simple &lt;code&gt;Dockerfile&lt;/code&gt; for this post, but if you&apos;ve got a different &lt;code&gt;Dockerfile&lt;/code&gt; when running your application in Production and Development then you may need a different file in the &lt;code&gt;dockerFile&lt;/code&gt; property below&lt;/p&gt;
&lt;p&gt;Now that we&apos;ve got a starting point we can add a little to our configuration so that everything is just right:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Change the &lt;code&gt;name&lt;/code&gt; property to name our workspace (purely aesthetic)&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;forwardPorts&lt;/code&gt; property to expose our application port to our localhost network, be sure to add the &lt;code&gt;,&lt;/code&gt; after &lt;code&gt;&amp;quot;extensions&amp;quot;:[]&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once we make the above changes we should have this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;devcontainer.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
    &amp;quot;name&amp;quot;: &amp;quot;My Workspace&amp;quot;,

    // Sets the run context to one level up instead of the .devcontainer folder.
    &amp;quot;context&amp;quot;: &amp;quot;..&amp;quot;,

    // Update the &apos;dockerFile&apos; property if you aren&apos;t using the standard &apos;Dockerfile&apos; filename.
    &amp;quot;dockerFile&amp;quot;: &amp;quot;..\\Dockerfile&amp;quot;,

    // Set *default* container specific settings.json values on container create.
    &amp;quot;settings&amp;quot;: {
        &amp;quot;terminal.integrated.shell.linux&amp;quot;: null
    },

    // Add the IDs of extensions you want installed when the container is created.
    &amp;quot;extensions&amp;quot;: [],

    // Use &apos;forwardPorts&apos; to make a list of ports inside the container available locally.
    &amp;quot;forwardPorts&amp;quot;: [
        8080
    ],
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we&apos;ve configured our build container, use &lt;code&gt;ctrl + shift + p&lt;/code&gt; to open the Command Palette again and search for &lt;code&gt;Remote-Containers: Reopen in Container&lt;/code&gt; and click &lt;code&gt;enter&lt;/code&gt; which will build the container and set up an image with the following setup for us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linked ports as defined in the &lt;code&gt;forwardPorts&lt;/code&gt; property&lt;/li&gt;
&lt;li&gt;Configure a VSCode development server inside the container so our editor can link to it&lt;/li&gt;
&lt;li&gt;Mount our system&apos;s file directory into the container so we can edit our files&lt;/li&gt;
&lt;li&gt;Does not run the &lt;code&gt;CMD&lt;/code&gt; command from our &lt;code&gt;Dockerfile&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Open a VSCode window linked to the container so we can start working with our code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you&apos;re in the container you can edit your files and run it by doing the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;ctrl + shift + p&lt;/code&gt; and then search for &lt;code&gt;Terminal: Create new Integrated Terminal&lt;/code&gt; and click &lt;code&gt;enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;node app.js&lt;/code&gt; into the new Terminal window and click &lt;code&gt;enter&lt;/code&gt; to run our app.js file&lt;/li&gt;
&lt;li&gt;Navigate to &lt;code&gt;http://localhost:8080&lt;/code&gt; in your browser to view your running app&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point we&apos;ve created a container to use as a development file and run our application, you can stop the application with &lt;code&gt;ctrl + c&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can switch from developing in a container back to your local environment with &lt;code&gt;ctrl + shift + p&lt;/code&gt; and searching for &lt;code&gt;Remote-Containers: Reopen locally&lt;/code&gt; and clicking &lt;code&gt;enter&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now that we&apos;re back on our local environment (and not docker) we can look at the other way we can set up our project for VSCode&lt;/p&gt;
&lt;h4&gt;Using a Preconfigured Dockerfile&lt;/h4&gt;
&lt;p&gt;Visual Studio Code&apos;s Remote Containers Extension provides some pre-configured &lt;code&gt;Dockerfile&lt;/code&gt;s for common application or application framework types. One of the available preconfigured &lt;code&gt;Dockerfile&lt;/code&gt;s is for working on Node.js applications&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The preconfigured files usually just provide a starting point for applications and often you will need to modify these to suit your application, we don&apos;t need this for the application we&apos;re working on however&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To redefine our Docker development config, let&apos;s delete the &lt;code&gt;.devcontainer&lt;/code&gt; directory in our application and regenerate this&lt;/p&gt;
&lt;p&gt;We can regenerate the files needed with &lt;code&gt;ctrl + shift + p&lt;/code&gt;, and searching for &lt;code&gt;Remote-Containers: Add Development Container Configuration Files&lt;/code&gt; again, clicking &lt;code&gt;enter&lt;/code&gt; and then selecting the &lt;code&gt;From a predefined configuration definition&lt;/code&gt; option, and then selecting &lt;code&gt;Node.js 12&lt;/code&gt;, this should now create a &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; file as well as a new &lt;code&gt;.devcontainer/Dockerfile&lt;/code&gt; that we did not have previously, our working directory will now look like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;working-directory
|__ .devcontainer
|   |__ devcontainer.json
|   |__ Dockerfile         # predefined dev container Dockerfile
|
|__ index.js
|__ Dockerfile             # our self-defined Dockerfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we look at the &lt;code&gt;devcontainer.json&lt;/code&gt; file we will see something similar to what we had before:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;devcontainer.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
    &amp;quot;name&amp;quot;: &amp;quot;Node.js 12&amp;quot;,
    &amp;quot;dockerFile&amp;quot;: &amp;quot;Dockerfile&amp;quot;,

    // Set *default* container specific settings.json values on container create.
    &amp;quot;settings&amp;quot;: {
        &amp;quot;terminal.integrated.shell.linux&amp;quot;: &amp;quot;/bin/bash&amp;quot;
    },

    // Add the IDs of extensions you want installed when the container is created.
    &amp;quot;extensions&amp;quot;: [
        &amp;quot;dbaeumer.vscode-eslint&amp;quot;
    ]

    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may, however, note that the &lt;code&gt;dockerFile&lt;/code&gt; property is missing, this just means that VSCode will use the default &lt;code&gt;Dockerfile&lt;/code&gt; which has been created in the &lt;code&gt;.devcontainer&lt;/code&gt; directory&lt;/p&gt;
&lt;p&gt;We can go ahead and change the name if we want, we should also add the &lt;code&gt;forwardPorts&lt;/code&gt; option as we did previously:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;devcontainer.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
    ...

    &amp;quot;forwardPorts&amp;quot;: [
        8080
    ],

    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now looking at the &lt;code&gt;Dockerfile&lt;/code&gt; which defines the base development container:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dockerfile&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a bit different to ours because Visual Studio Code will handle the file copying and port exposing on its own for the development container. Note that this configuration can only be used for development and can&apos;t really be deployed as a production container. This type of setup is necessary if our development image and production image will be different (which they usually are)&lt;/p&gt;
&lt;p&gt;Now that the development container has been set-up, we can use &lt;code&gt;ctrl + shift + p&lt;/code&gt; and &lt;code&gt;Remote-Containers: Reopen in Container&lt;/code&gt; to open our development container, from here we can work on our application and run the application the same as we did before&lt;/p&gt;
&lt;h3&gt;Which Method to Use&lt;/h3&gt;
&lt;p&gt;We&apos;ve looked at two different methods for configuring our development container, either of which can be used in any project. Below are my recommendations:&lt;/p&gt;
&lt;p&gt;If you&apos;ve got an existing &lt;code&gt;Dockerfile&lt;/code&gt; and your development container can be the same as your production container, for things like simple &lt;code&gt;node.js&lt;/code&gt; or &lt;code&gt;python&lt;/code&gt; apps, and you don&apos;t want to maintain another &lt;code&gt;Dockerfile&lt;/code&gt; then this may be a quick solution to opt for&lt;/p&gt;
&lt;p&gt;Otherwise, if your development container needs to be different from your production one then it&apos;s probably easier to start with a predefined VSCode Container as a base and add in any development configuration you need to the &lt;code&gt;.devcontainer/Dockerfile&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Lastly, if you don&apos;t have an existing &lt;code&gt;Dockerfile&lt;/code&gt; at all then I&apos;d suggest using a predefined one so that even if it&apos;s not fully configured you&apos;ve got a relatively good starting point, especially when working with more complex languages and frameworks as a custom &lt;code&gt;Dockerfile&lt;/code&gt; for these can be some work to configure&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;In this post, we&apos;ve covered the basics of using Docker to run your applications in a container as well as how to define and build your images. We also looked at why we may want to use a container for development and how we can do this using Visual Studio Code&lt;/p&gt;
&lt;h3&gt;Further Reading&lt;/h3&gt;
&lt;p&gt;For some more in-depth information on Docker and VSCode Development Containers you can look at the following resources:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;/docs/containers-and-microservices/docker&quot;&gt;My General Docker Notes&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/docs/containers-and-microservices/docker&quot;&gt;Docker Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/containers-and-microservices/build-an-express-app-with-mongo&quot;&gt;Express Application with MongoDB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/docs/containers-and-microservices/docker-multi-stage&quot;&gt;Multi-stage Builds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker&apos;s Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/remote/containers&quot;&gt;VSCode&apos;s Remote Containers Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Code for Noobs</title><link>https://nabeelvalley.co.za/blog/2020/17-05/code-for-noobs/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/17-05/code-for-noobs/</guid><description>An introduction to programming and general programming concepts using JavaScript</description><pubDate>Sun, 17 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So I&apos;ve been meaning to write an introductory post about the basics of JavaScript for quite some time. A few weeks ago I managed to finally get something going on &lt;a href=&quot;https://twitter.com/not_nabeel/status/1255743195557888000&quot;&gt;this Twitter thread (@not_nabeel)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let&apos;s get into it&lt;/p&gt;
&lt;h2&gt;0. What is Programming&lt;/h2&gt;
&lt;p&gt;Programming is our way of telling a computer to do things. This can be anything from checking our spelling to making trippy digital art&lt;/p&gt;
&lt;p&gt;The basics of programming are the same in most languages and doesn&apos;t involve much math or binary (&lt;code&gt;0010101&lt;/code&gt;) like a lot of people seem to think. Programming languages &lt;em&gt;usually&lt;/em&gt; make use of a very small subset of words and concepts of a normal human language like English&lt;/p&gt;
&lt;p&gt;The language I&apos;m going to be using is called &lt;code&gt;JavaScript&lt;/code&gt; but many of these concepts are the same in most other programming languages&lt;/p&gt;
&lt;h2&gt;1. What is JavaScript?&lt;/h2&gt;
&lt;p&gt;JavaScript is the language used to add interactivity to a website but it can also be used to do pretty much anything you like. JavaScript runs in all modern web browsers and can be accessed through your browser&apos;s developer tools, but it can also be used on other devices using something like &lt;a href=&quot;https://twitter.com/nodejs&quot;&gt;@nodejs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For our purposes though, we don&apos;t need to worry too much about how that all works right now. To get started we&apos;ll be using tools like &lt;a href=&quot;https://twitter.com/CodePen&quot;&gt;@CodePen&lt;/a&gt;, &lt;a href=&quot;https://twitter.com/replit&quot;&gt;@replit&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/glitch&quot;&gt;@glitch&lt;/a&gt; which give you text editor and a place to run your code&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You&apos;ll see some code samples embeded in the&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&apos;ll be posting links to the code on these sites as I go along&lt;/p&gt;
&lt;h2&gt;2. Text Data&lt;/h2&gt;
&lt;p&gt;In a program, we can store different types of data (known as &amp;quot;data types&amp;quot;)&lt;/p&gt;
&lt;p&gt;When we store text we use a data type called &lt;code&gt;string&lt;/code&gt;. In JavaScript a string is just text surrounded in either double quotes, single quotes, or &lt;code&gt;`these things`&lt;/code&gt; (which are known as backticks):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&apos;i am text&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;&apos;i am also text&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;;`me too.`
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;;`unlike the others,
  i can b
multiple lines
lllooonnnggg
    and have random spaces`
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. Variables&lt;/h2&gt;
&lt;p&gt;If we want to keep our data for use at a later stage we need to give it a name, otherwise how do we know what data we&apos;re trying to use right? To give a piece of data (or text, in our case) a name we create a &lt;code&gt;variable&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We create a variable using &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt; along with a variable name and the data that we want to give the name to :&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt3?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// this code shouldn&apos;t do anything if you run it
// we are just creating some variables

let myText = &apos;Hello World&apos;

const myOtherText = &apos;Bye World&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;let&lt;/code&gt; for data whose data may change and &lt;code&gt;const&lt;/code&gt; for data whose data won&apos;t you can remember this like: &lt;code&gt;const = constant&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that it is also possible to use the keyword &lt;code&gt;var&lt;/code&gt; to create a variable. This is something that is left over from older versions of JavaScript and can have some effects that are better to just avoid (if you&apos;re interested you can read &lt;a href=&quot;https://medium.com/@josephcardillo/the-difference-between-function-and-block-scope-in-JavaScript-4296b2322abe&quot;&gt;this article about how it impacts variable scope&lt;/a&gt; but it is a bit of a more challenging concept to understand)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When creating a variable, there are a few rules we need to follow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Variable names &lt;strong&gt;must not&lt;/strong&gt; contain spaces or stuff like &lt;code&gt;!@#%%^&amp;amp;\*()&lt;/code&gt;, underscores and dollar signs are okay though&lt;/li&gt;
&lt;li&gt;Variable names &lt;strong&gt;must not&lt;/strong&gt; be a word the language has set aside for something else. e.g &lt;code&gt;const&lt;/code&gt; or &lt;code&gt;let&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Variable names &lt;strong&gt;must not&lt;/strong&gt; start with a number&lt;/li&gt;
&lt;li&gt;Variable names &lt;strong&gt;should be&lt;/strong&gt; descriptive. while names like &amp;quot;x&amp;quot; and &amp;quot;blah&amp;quot; are allowed, if they have no meaning in the context it&apos;s better to opt for something people will understand&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;4. Printing Data&lt;/h2&gt;
&lt;p&gt;Languages have ways we can show data to a user (or programmer). In JavaScript this is the &amp;quot;console.log&amp;quot; function. We&apos;ll discuss functions later on but for now know that when we give them data, and they do stuff&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt4?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// print the data
console.log(&apos;Bob Smith&apos;) //prints -&amp;gt; Bob Smith

// print a variable
const jenny = &apos;Jenny Smith&apos;
console.log(jenny) // prints -&amp;gt; Jenny Smith
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;5. Numbers&lt;/h2&gt;
&lt;p&gt;Numbers are another type of data in JavaScript, to store a number we can just write the number. using numbers we can also do things like getting fat or running from the po-lice&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt; is plus&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt; is minus&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; is multiply&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt; is divide&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt5?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const myWeight = 100
const food = 100 + 50

const myNewWeight = myWeight + food

console.log(myNewWeight) // print -&amp;gt; 250

const myWeightAfterRunnin = myWeight - myWeight * 0.2

console.log(myWeightAfterRunnin) // print -&amp;gt; 80
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;But, JavaScript lets us add do maths with anything. so maybe like - don&apos;t do this:&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt5-1?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const dontDoThis = &apos;apple&apos; * &apos;pineapple&apos;

console.log(dontDoThis) // print -&amp;gt; NaN (Not a Number)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;6. Arrays&lt;/h2&gt;
&lt;p&gt;Arrays are how we store a set of data. an array can have different data types in it, but usually, we want to be storing the same stuff in an array. we make an array by wrapping our items in &lt;code&gt;[ ]&lt;/code&gt; and separating each item with a comma (&lt;code&gt;,&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt6?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const myFriends = [&amp;quot;i&amp;quot;, &amp;quot;don&apos;t&amp;quot;, &amp;quot;have&amp;quot;, &amp;quot;any&amp;quot;]

const thingsToRemember = [&amp;quot;uhmm&amp;quot;, 42, 12, &amp;quot;idk, i guess i forgot&amp;quot;]

const multipleLines = [
&amp;quot;arrays don&apos;t have to be&amp;quot;,
&amp;quot;on a single&amp;quot;,
&amp;quot;line&amp;quot;
]

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;If we want to get a specific element in an array we can use the variable name with the index (position) of the element. the index starts at 0. we will get &lt;code&gt;undefined&lt;/code&gt; (I&apos;ll explain this in a bit) if we try to get a value at an index that does not exist&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt6-1?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;  const myData = [
  &amp;quot;zeroeth index&amp;quot;,
  &amp;quot;first index&amp;quot;,
  &amp;quot;second index&amp;quot;,
  &amp;quot;third index&amp;quot;
]

console.log(myData[0]) // print -&amp;gt; zeroeth index
console.log(myData[1]) // print -&amp;gt; first index
console.log(myData[2]) // print -&amp;gt; second index
console.log(myData[3]) // print -&amp;gt; third index

// indexes that do not exist in our array
console.log(myData[-1]) // print -&amp;gt; undefined
console.log(myData[100]) // print -&amp;gt; undefined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;7. Booleans&lt;/h2&gt;
&lt;p&gt;So far we&apos;ve looked at strings and numbers, we have an even more basic data type called a boolean. a boolean is a value that can either be true or false. when creating a variable for a boolean we do not wrap the value in quotes&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt7?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;var myTrueBool = true

var myFalseBool = false

console.log(myTrueBool)
console.log(myFalseBool)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;8. Complex Data&lt;/h2&gt;
&lt;p&gt;If we want to store data that are more complex than the ones we&apos;ve seen above, we can make use of &amp;quot;objects&amp;quot;. use &lt;code&gt;{ }&lt;/code&gt; around our data to group more basic data. these use &lt;code&gt;keys&lt;/code&gt; as names for values in the object&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt8?lite=true&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const jenny = {
  id: 123,
  name: &apos;Jenny&apos;,
  surname: &apos;Smith&apos;,
  age: &amp;quot;idk, can&apos;t ask a woman that&amp;quot;,
  favouriteBooks: [
    &apos;To not kill a Mockingbird&apos;,
    &apos;Why are books so voilent, yoh&apos;,
  ],
}

// we can get specific values using their keys
const jennyName = jenny.name
const jennyBooks = jenny.favouriteBooks
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;9. Undefined and Null&lt;/h2&gt;
&lt;p&gt;the values &lt;code&gt;undefined&lt;/code&gt; and &lt;code&gt;null&lt;/code&gt; have a special meaning.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;undefined&lt;/code&gt; is a representation for a variable that does not have a value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;null&lt;/code&gt; is a value of &amp;quot;nothing&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What&apos;s wrong with chocolate? &lt;code&gt;null&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;What&apos;s a flobuir? &lt;code&gt;undefined&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;10. Functions&lt;/h2&gt;
&lt;p&gt;Functions are a way we can group code for a specific set of instructions, usually with some end purpose. In JavaScript we define a function in one of two ways: using the word &lt;code&gt;function&lt;/code&gt; or with the &lt;code&gt;fat arrow syntax&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-pt10?lite=false&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// using the &amp;quot;function&amp;quot; keyword
// this creates a variable called &amp;quot;myFunc1&amp;quot;
function myFunc() {
  const stuff = &apos;I am Function&apos;
  console.log(stuff)
}

// we can also create the variable using
// &amp;quot;let&amp;quot; or &amp;quot;const&amp;quot; like we do for other variables
const myLetFunc = function () {
  const stuff = &apos;I am another Function&apos;
  console.log(stuff)
}

// fat arrow function
const myFatFunc = () =&amp;gt; {
  console.log(&apos;Phat Funk&apos;)
}

// single line fat-arrow functions don&apos;t need the {}
const mySingleLineFunct = () =&amp;gt; console.log(&apos;single line&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;To use a function we simply write the name of the function and then add &lt;code&gt;()&lt;/code&gt; at the end, provided the function doesn&apos;t take any data (also known as &lt;code&gt;parameters&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-10-1?lite=false&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const sayHello = function () {
  console.log(&apos;Hello&apos;)
}

// &amp;quot;call&amp;quot; the function
sayHello() // prints -&amp;gt; Hello

const sayBye = () =&amp;gt; console.log(&apos;BYEE&apos;)

// &amp;quot;call&amp;quot; the function
sayBye() // prints -&amp;gt; BYEE
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;Remember earlier I said that functions take data and do stuff? For us to give a function data we need to tell it what variables to store that data as when we call it. We do this by having the data in the &lt;code&gt;()&lt;/code&gt; when we create (or &apos;declare&apos;) our function&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-10-2?lite=false&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function sayHello(name) {
  console.log(&apos;Hello &apos; + name)
}

// use the function
sayHello(&apos;Bob&apos;) // print -&amp;gt; Hello Bob

const sayBye = (name) =&amp;gt; console.log(&apos;Bye &apos; + name)

//use the function
const name = &apos;Jenny&apos;
sayBye(name) // print -&amp;gt; Bye Jenny
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;When computers are following our code they do so from the top down, so the first line is handled by the computer before the second. the second before the third, etc. functions are a way for us to reuse code that was written on a line higher up in our code. You may notice that we use the variable &lt;code&gt;name&lt;/code&gt; in a lot of different places above. this uses &lt;code&gt;scope&lt;/code&gt; and broadly means any variable name created in a function (or pretty much anywhere between &lt;code&gt;{ }&lt;/code&gt;) is only available within that section&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Scope complicated, you can read more about it &lt;a href=&quot;https://scotch.io/tutorials/understanding-scope-in-JavaScript&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Functions can also take multiple parameters, this is done by listing the parameters between the () and separating them by commas. the order that we list them when we create our function is the same as the order we need to put them when using the function&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-10-3?lite=false&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const sayBye = (firstName, lastName) =&amp;gt; {
  console.log(&apos;Bye &apos; + firstName + &apos; &apos; + lastName)
}

// use the function
const jennyName = &apos;Jenny&apos;
const jennySurname = &apos;Smith&apos;
sayBye(jennyName, jennySurname) // print -&amp;gt; Bye Jenny Smith
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;Functions are also able to give us back a value after doing some stuff. They do this by using the &lt;code&gt;return&lt;/code&gt; keyword which tells it what to give back. A function stops processing when it sees the keyword &lt;code&gt;return&lt;/code&gt; - anything after it in a function is ignored&lt;/p&gt;
&lt;p&gt;&amp;lt;iframe height=&amp;quot;400px&amp;quot; width=&amp;quot;100%&amp;quot; src=&amp;quot;https://repl.it/@nabeelvalley/twitter-10-4?lite=false&amp;quot; scrolling=&amp;quot;no&amp;quot; frameborder=&amp;quot;no&amp;quot; allowtransparency=&amp;quot;true&amp;quot; allowfullscreen=&amp;quot;true&amp;quot; sandbox=&amp;quot;allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals&amp;quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;View Code&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const addNumbers = (num1, num2) =&amp;gt; {
  const result = num1 + num2
  return result
}

const mySum = addNumbers(1, 2)

console.log(mySum) // print -&amp;gt; 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;That&apos;s it for now, I&apos;ll definitely be updating this post/series as things are added&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Colour in Black and White Photography</title><link>https://nabeelvalley.co.za/blog/2020/07-04/filtering-in-bw/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/07-04/filtering-in-bw/</guid><description>Introduction to Black and White Colour Filtering and Processing for Photography</description><pubDate>Tue, 07 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Let&apos;s talk about black and white shall we?. As a first-time monochromer there are a couple of aspects of shooting and editing a black and white picture that isn&apos;t immediately apparent&lt;/p&gt;
&lt;p&gt;When shooting in Black and White (henceforth B&amp;amp;W) there are some things we need to be aware especially aware of, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Brightness&lt;/li&gt;
&lt;li&gt;Texture&lt;/li&gt;
&lt;li&gt;Colour&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, of course, other considerations can be made but most of these boil down to how you use these three elements. For the most part, I&apos;ll be discussing how &lt;em&gt;colour&lt;/em&gt; comes into play from an editing perspective, but this should give you an awareness of how this applies when shooting too&lt;/p&gt;
&lt;h2&gt;Brightness&lt;/h2&gt;
&lt;p&gt;When I refer to brightness in this context I am not referring to the exposure of the image but rather the distribution of brightness across the image itself, where are your shadows and highlights, how bright is your subject in relation to your background, etc.&lt;/p&gt;
&lt;p&gt;Typically when we are working with a B&amp;amp;W image we try to have our subject be a little brighter (or much brighter) than everything else, this helps us to draw the viewer&apos;s attention more easily, of course, this is only one of the factors&lt;/p&gt;
&lt;h2&gt;Texture&lt;/h2&gt;
&lt;p&gt;When shooting B&amp;amp;W we also look for texture, I would argue that texture is to a black and white picture what colour is to a colour one. Texture helps us to differentiate between different elements in a photo and is very evident when used a lot of strong contrast. Sometimes you want a lot of texture, sometimes you don&apos;t - it is, however, important that you acknowledge how it contributes to an image&lt;/p&gt;
&lt;h2&gt;Colour&lt;/h2&gt;
&lt;p&gt;My focus in this post is primarily colour because I think it&apos;s the easiest to play around with and can make the biggest impact to a picture when editing (how else does anyone get B&amp;amp;W these days?)&lt;/p&gt;
&lt;p&gt;At a simplified level, the way we work with colour in a B&amp;amp;W picture is by manipulating the brightness with which different colours are interpreted which in turn allows us to emphasize (or de-emphasize) specific elements in an image&lt;/p&gt;
&lt;p&gt;Over the remainder of this post I&apos;ll be discussing a lot of this in the context of the following image:&lt;/p&gt;
&lt;p&gt;&amp;lt;center&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2020/07-04/images/colour.jpg&quot; alt=&quot;Colour Version of Discussion Image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;For our discussion there are a few important aspects of this image to note:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The image is darkest in the background (top left) and transitions to being brighter in the foreground (bottom right)&lt;/li&gt;
&lt;li&gt;We primarily have the subject in &lt;strong&gt;red&lt;/strong&gt; and the background element (leaves) in &lt;strong&gt;green&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The brightness of our red and green elements in their respective sections of the image are approximately the same&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If we were to simply convert this image to a B&amp;amp;W one we get the following:&lt;/p&gt;
&lt;p&gt;&amp;lt;center&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2020/07-04/images/neutral.jpg&quot; alt=&quot;Neutral Version of Discussion Image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;From the above we see that the distinction between our red and green elements isn&apos;t really visible anymore, this is because of the impact that colour mixing has on our image. Mixing allows us to control the way the different colours are seen in the image and most photo editing tools have some version of a Black and White Mixer that allows us to apply a colour filter to a Black and White image&lt;/p&gt;
&lt;h3&gt;Neutral Filtering&lt;/h3&gt;
&lt;p&gt;This is the &amp;quot;natural&amp;quot; way that a B&amp;amp;W conversion works, using this method for any two colours at approximately the same brightness we should see the same brightness in the B&amp;amp;W version&lt;/p&gt;
&lt;p&gt;If we look at the neutral version of our image we can observe that the brightness across our image is fairly consistent with that of the colour version with a darker background and brighter foreground. We can also see that there is very little differentiation between the red and green elements in our image&lt;/p&gt;
&lt;p&gt;&amp;lt;center&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2020/07-04/images/neutral.svg&quot; alt=&quot;Neutral Version of Discussion Image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;In photography, there are few well-known colour filters which can be placed in front of your lens to achieve what we are doing here digitally. Commonly we have red, green, blue, and yellow filters. We&apos;ll just be looking at the red and green filters that were used to edit this image&lt;/p&gt;
&lt;h3&gt;Red Filter&lt;/h3&gt;
&lt;p&gt;In a picture like this where our subject is red, we can use a red filter to increase the brightness of the red portions of our image. To do this we would bump up the red and orange sections of our colours while trying to maintain a smooth change from one colour to the next to prevent any sharp changes in the brightness of our image&lt;/p&gt;
&lt;p&gt;Additionally, I&apos;ve also made the green slightly darker to add some additional contrast. We can see the result of doing so along with the changes made to the brightness of the respective colours below:&lt;/p&gt;
&lt;p&gt;&amp;lt;center&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2020/07-04/images/red.svg&quot; alt=&quot;Red Filtered Version of Discussion Image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;Using a method like this we can draw our focus back to the red elements a little more than if we had left the brightnesses as they were in the Neutral image while pushing down the brightness of our green elements so we don&apos;t have the two competing for focus&lt;/p&gt;
&lt;h3&gt;Green Filter&lt;/h3&gt;
&lt;p&gt;We can also do something like the above using a filter that brightens the green and darkens the red&lt;/p&gt;
&lt;p&gt;&amp;lt;center&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2020/07-04/images/green.svg&quot; alt=&quot;Green Filtered Version of Discussion Image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;In the resulting image above we can see that the greens are now much brighter and the reds are almost black - however we still maintain a good level of contrast between our too resulting elements. We can see a comparison of the impact the different colour filters have on our image below. These are ordered from left to right as red, neutral and green&lt;/p&gt;
&lt;p&gt;&amp;lt;center&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2020/07-04/images/comparison.jpg&quot; alt=&quot;Comparison of Filtered Versions of Discussion Image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/center&amp;gt;&lt;/p&gt;
&lt;p&gt;Using what we&apos;ve looked at in the above we can see that the way we choose to filter a black and white image has a huge impact on how we direct the viewer&apos;s attention in our image as well as how clearly we can differentiate between different elements&lt;/p&gt;
&lt;p&gt;Note that while we do have different common colour filters, when editing a B&amp;amp;W image it usually makes sense to play around with your Black and White Mixer Tool to see what works best for your image&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>The Gatsby Migration, pt.3 - Smart Pages</title><link>https://nabeelvalley.co.za/blog/2020/15-03/gatsby-migration-3/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/15-03/gatsby-migration-3/</guid><description>Adding dynamic pages to a Gatsby site</description><pubDate>Sun, 15 Mar 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;So far we&apos;ve created the initial react application as with a few routes for our &lt;code&gt;Home&lt;/code&gt;, &lt;code&gt;Blog&lt;/code&gt;, and &lt;code&gt;404&lt;/code&gt; pages. In this post we&apos;ll look at how we can set up our &lt;code&gt;Post&lt;/code&gt; component to render our pages dynamically based on the JSON data we have. We&apos;ll also extend this so that we can have some more content in a markdown file that we&apos;ll parse and add to our Gatsby data&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2020/21-01/gatsby-migration-1&quot;&gt;Creating the initial React App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2020/01-02/gatsby-migration-2&quot;&gt;Rendering the &amp;quot;Dumb&amp;quot; pages with Gatsby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rendering the &amp;quot;Smart&amp;quot; page with Gatsby&lt;/strong&gt; (This post)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Setting Up&lt;/h2&gt;
&lt;p&gt;We&apos;re going to make our data a little more complex by creating two additional markdown files in our &lt;code&gt;static/posts&lt;/code&gt; directory to enable us to have more content with each post&lt;/p&gt;
&lt;p&gt;Create the following markdown files in the application and align the names with our &lt;code&gt;post-1.json&lt;/code&gt; and &lt;code&gt;post-2.json&lt;/code&gt; files:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;static/posts/post-1.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static/posts/post-2.md&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Gatsby Plugins&lt;/h2&gt;
&lt;p&gt;To read the data from our files we&apos;re going to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use the &lt;code&gt;gatsby-source-filesystem&lt;/code&gt; to read our files into the Gatsby Data Layer&lt;/li&gt;
&lt;li&gt;Define our own plugin that can read the file content, parse the markdown, and add it into the data layer&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Reading the File Metadata&lt;/h3&gt;
&lt;p&gt;To read our file data we will need to first install the &lt;code&gt;gatsby-source-filesystem&lt;/code&gt; plugin. Plugins in Gatsby enable us to ingest or transform data in our application. We then make use of GraphQL to query the data from the relevant component&lt;/p&gt;
&lt;p&gt;Install the &lt;code&gt;gatsby-source-filesystem&lt;/code&gt; plugin with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn add gatsby-source-filesystem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then add the plugin configuration to the &lt;code&gt;gatsby-node.js&lt;/code&gt; file into the &lt;code&gt;plugins&lt;/code&gt; array:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gatsby-node.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;{
    resolve: `gatsby-source-filesystem`,
    options: {
        name: `content`,
        path: `${__dirname}/static/posts`,
    },
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will read all the data from our &lt;code&gt;posts&lt;/code&gt; directory into the filesystem. We can now start the application back up with &lt;code&gt;yarn start&lt;/code&gt; and navigate to &lt;code&gt;http://localhost:8000/__graphql&lt;/code&gt; in our browser to view the GraphQL data. We should be able to see the GraphiQL interface&lt;/p&gt;
&lt;p&gt;From the GraphiQL interface run the following query to see the data from the files in our directory:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;query PostData {
  allFile {
    nodes {
      name
      extension
      absolutePath
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should yield the following JSON with our file meta data in it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;data&amp;quot;: {
    &amp;quot;allFile&amp;quot;: {
      &amp;quot;nodes&amp;quot;: [
        {
          &amp;quot;name&amp;quot;: &amp;quot;post-1&amp;quot;,
          &amp;quot;extension&amp;quot;: &amp;quot;json&amp;quot;,
          &amp;quot;absolutePath&amp;quot;: &amp;quot;C:/repos/cra-to-gatsby/static/posts/post-1.json&amp;quot;
        },
        {
          &amp;quot;name&amp;quot;: &amp;quot;1&amp;quot;,
          &amp;quot;extension&amp;quot;: &amp;quot;jpg&amp;quot;,
          &amp;quot;absolutePath&amp;quot;: &amp;quot;C:/repos/cra-to-gatsby/static/posts/1.jpg&amp;quot;
        },
        {
          &amp;quot;name&amp;quot;: &amp;quot;post-1&amp;quot;,
          &amp;quot;extension&amp;quot;: &amp;quot;md&amp;quot;,
          &amp;quot;absolutePath&amp;quot;: &amp;quot;C:/repos/cra-to-gatsby/static/posts/post-1.md&amp;quot;
        }
        // file 2 data
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Processing the Files&lt;/h3&gt;
&lt;p&gt;Now that we have our metadata for each file in the file system, we&apos;re going to create a plugin that will allow us to read the file data and add it the GraphQL data layer&lt;/p&gt;
&lt;p&gt;In order to do this, create a &lt;code&gt;plugins&lt;/code&gt; directory in the root folder. Inside of the plugins directory create a folder and folder for our plugin.&lt;/p&gt;
&lt;p&gt;Create a new folder in the &lt;code&gt;plugins&lt;/code&gt; directory with another folder called &lt;code&gt;gatsby-transformer-postdata&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;From this directory run the following commands to initialize and link the yarn package:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;plugins/gatsby-transformer-postdata&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn init -y
yarn link
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&apos;ll also add the &lt;code&gt;showdown&lt;/code&gt; package which will allow us to convert the markdown into the HTML so we can render it with our &lt;code&gt;Post&lt;/code&gt; component&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn add showdown
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then create an &lt;code&gt;gatsby-node.js&lt;/code&gt; file in this directory with the following content:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/plugins/gatsby-transformer-postdata/gatsby-node.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const fs = require(&apos;fs&apos;)
const crypto = require(&apos;crypto&apos;)
const showdown = require(&apos;showdown&apos;)

exports.onCreateNode = async ({ node, getNode, actions }) =&amp;gt; {
  const { createNodeField, createNode } = actions

  // we&apos;ll process the node data here
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This exposes the &lt;code&gt;onCreateNode&lt;/code&gt; Gatsby API for our plugin. This is what Gatsby calls when creating nodes and we will be able to hook into this to create new nodes with all the data for each respective post based on the created file nodes&lt;/p&gt;
&lt;p&gt;From the &lt;code&gt;onCreateNode&lt;/code&gt; function we&apos;ll do the following to create the new nodes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check if it is a markdown node&lt;/li&gt;
&lt;li&gt;Check if the JSON file exists&lt;/li&gt;
&lt;li&gt;Read file content&lt;/li&gt;
&lt;li&gt;Parse the metadata into an object&lt;/li&gt;
&lt;li&gt;Convert the markdown to HTML&lt;/li&gt;
&lt;li&gt;Get the name of the node&lt;/li&gt;
&lt;li&gt;Define the data for our node&lt;/li&gt;
&lt;li&gt;Create the new node using the &lt;code&gt;createNode&lt;/code&gt; function&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;gatsby-transformer-postdata/gatsby-node.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const fs = require(&apos;fs&apos;)
const crypto = require(&apos;crypto&apos;)
const showdown = require(&apos;showdown&apos;)

exports.onCreateNode = async ({ node, actions, loadNodeContent }) =&amp;gt; {
  const { createNodeField, createNode } = actions

  // 1. Check if it is a markdown node
  if (node.internal.mediaType == &apos;text/markdown&apos;) {
    const jsonFilePath = `${node.absolutePath.slice(0, -3)}.json`

    console.log(jsonFilePath)

    // 2. Check if the JSON file exists
    if (fs.existsSync(jsonFilePath)) {
      // 3. Read file content
      const markdownFilePath = node.absolutePath
      const markdownContent = fs.readFileSync(markdownFilePath, &apos;utf8&apos;)
      const jsonContent = fs.readFileSync(jsonFilePath, &apos;utf8&apos;)

      // 4. Parse the metadata into an object
      const metaData = JSON.parse(jsonContent)

      // 5. Convert the markdown to HTML
      const converter = new showdown.Converter()
      const html = converter.makeHtml(markdownContent)

      // 6. Get the name of the node
      const name = node.name

      // 7. Define the data for our node
      const nodeData = {
        name,
        html,
        metaData,
        slug: `/blog/${name}`,
      }

      // 8. Create the new node using the `createNode` function
      const newNode = {
        // Node data
        ...nodeData,

        // Required fields.
        id: `RenderedMarkdownPost-${name}`,
        children: [],
        internal: {
          type: `RenderedMarkdownPost`,
          contentDigest: crypto
            .createHash(`md5`)
            .update(JSON.stringify(nodeData))
            .digest(`hex`),
        },
      }

      createNode(newNode)
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the root directory you can clean and rerun the application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn clean
yarn start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, reload the GraphiQL at &lt;code&gt;http://localhost:8000/__graphql&lt;/code&gt; and run the following query to extract the data we just pushed into the node:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-graphql&quot;&gt;query AllPostData {
  allRenderedMarkdownPost {
    nodes {
      html
      name
      slug
      metaData {
        body
        image
        title
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should give us the relevant post data:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;data&amp;quot;: {
    &amp;quot;allRenderedMarkdownPost&amp;quot;: {
      &amp;quot;nodes&amp;quot;: [
        {
          &amp;quot;html&amp;quot;: &amp;quot;&amp;lt;p&amp;gt;Hello here is some content for Post 1&amp;lt;/p&amp;gt;\n&amp;lt;ol&amp;gt;\n&amp;lt;li&amp;gt;Hello&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;World&amp;lt;/li&amp;gt;\n&amp;lt;/ol&amp;gt;&amp;quot;,
          &amp;quot;name&amp;quot;: &amp;quot;post-1&amp;quot;,
          &amp;quot;slug&amp;quot;: &amp;quot;/blog/post-1&amp;quot;,
          &amp;quot;metaData&amp;quot;: {
            &amp;quot;body&amp;quot;: &amp;quot;Hello world, how are you&amp;quot;,
            &amp;quot;image&amp;quot;: &amp;quot;/posts/1.jpg&amp;quot;,
            &amp;quot;title&amp;quot;: &amp;quot;Post 1&amp;quot;
          }
        },
        {
          &amp;quot;html&amp;quot;: &amp;quot;&amp;lt;p&amp;gt;Hello here is some content for Post 2&amp;lt;/p&amp;gt;\n&amp;lt;ol&amp;gt;\n&amp;lt;li&amp;gt;Hello&amp;lt;/li&amp;gt;\n&amp;lt;li&amp;gt;World&amp;lt;/li&amp;gt;\n&amp;lt;/ol&amp;gt;&amp;quot;,
          &amp;quot;name&amp;quot;: &amp;quot;post-2&amp;quot;,
          &amp;quot;slug&amp;quot;: &amp;quot;/blog/post-2&amp;quot;,
          &amp;quot;metaData&amp;quot;: {
            &amp;quot;body&amp;quot;: &amp;quot;Hello world, I am fine&amp;quot;,
            &amp;quot;image&amp;quot;: &amp;quot;/posts/2.jpg&amp;quot;,
            &amp;quot;title&amp;quot;: &amp;quot;Post 2&amp;quot;
          }
        }
      ]
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Create Pages&lt;/h2&gt;
&lt;p&gt;Now that we&apos;ve got all our data for the pages in one place we can use the &lt;code&gt;onCreatePages&lt;/code&gt; API to create our posts, and the &lt;code&gt;Post&lt;/code&gt; component to render the pages&lt;/p&gt;
&lt;h3&gt;Setting Up&lt;/h3&gt;
&lt;p&gt;Before we really do anything we need to rename the &lt;code&gt;Blog.js&lt;/code&gt; file to &lt;code&gt;blog.js&lt;/code&gt; as well as create the &lt;code&gt;src/components&lt;/code&gt; directory and move the &lt;code&gt;Post.js&lt;/code&gt; file into it, you may need to restart your application again using &lt;code&gt;yarn start&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Create Pages Dynamically&lt;/h3&gt;
&lt;p&gt;In our site root create a &lt;code&gt;gatsby-node.js&lt;/code&gt; file which exposes an &lt;code&gt;onCreatePages&lt;/code&gt; function:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gatsby-node.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const path = require(&apos;path&apos;)

exports.createPages = async ({ graphql, actions }) =&amp;gt; {
  const { createPage } = actions
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From this function we need to do the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Query for the PostData using the &lt;code&gt;graphql&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Create a page for each &lt;code&gt;renderedMarkdownPost&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;gatsby-node.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const path = require(&apos;path&apos;)

exports.createPages = async ({ graphql, actions }) =&amp;gt; {
  const { createPage } = actions

  // 1. Query for the PostData using the `graphql` function
  const result = await graphql(`
    query AllPostData {
      allRenderedMarkdownPost {
        nodes {
          html
          name
          slug
          metaData {
            body
            image
            title
          }
        }
      }
    }
  `)

  result.data.allRenderedMarkdownPost.nodes.forEach((node) =&amp;gt; {
    // 2. Create a page for each `renderedMarkdownPost`
    createPage({
      path: node.slug,
      component: path.resolve(`./src/components/Post.js`),
      context: node,
    })
  })
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Render the Page Data&lt;/h3&gt;
&lt;p&gt;From the Post component we need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Export the &lt;code&gt;query&lt;/code&gt; for the data&lt;/li&gt;
&lt;li&gt;Get the data for the Post&lt;/li&gt;
&lt;li&gt;Render the data&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;components/post.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { graphql } from &apos;gatsby&apos;
import App from &apos;../App&apos;

const Post = ({ data }) =&amp;gt; {
  // 2. Get the data for the Post
  const postData = data.renderedMarkdownPost

  // 3. Render the data
  return (
    &amp;lt;App&amp;gt;
      &amp;lt;div className=&amp;quot;Post&amp;quot;&amp;gt;
        &amp;lt;p&amp;gt;
          This is the &amp;lt;code&amp;gt;{postData.slug}&amp;lt;/code&amp;gt; page
        &amp;lt;/p&amp;gt;
        &amp;lt;h1&amp;gt;{postData.metaData.title}&amp;lt;/h1&amp;gt;
        &amp;lt;div
          className=&amp;quot;markdown&amp;quot;
          dangerouslySetInnerHTML={{ __html: postData.html }}
        &amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/App&amp;gt;
  )
}

export default Post

// 1. Export the `query` for the data
export const query = graphql`
  query PostData($slug: String!) {
    renderedMarkdownPost(slug: { eq: $slug }) {
      html
      name
      slug
      metaData {
        body
        image
        title
      }
    }
  }
`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the &lt;code&gt;Post&lt;/code&gt; component above we use the &lt;code&gt;slug&lt;/code&gt; to determine which page to render, we also set the HTML content for the &lt;code&gt;markdown&lt;/code&gt; element above using the HTML we generated. We also now have our pages dynamically created based on the data in our &lt;code&gt;static&lt;/code&gt; directory&lt;/p&gt;
&lt;p&gt;You can also see that we have significantly reduced the complexity in the &lt;code&gt;Post&lt;/code&gt; component now that we don&apos;t need to handle the data fetching from the component&lt;/p&gt;
&lt;p&gt;If you look at the site now you should be able to navigate through all the pages as you&apos;d expect to be able to&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;By now we have completed the the entire migration process - converting our static and dynamic pages to use Gatsby. In order to bring the dynamic page generation functionality to our site we&apos;ve done the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Used the &lt;code&gt;gatsby-source-filesystem&lt;/code&gt; plugin to read our file data&lt;/li&gt;
&lt;li&gt;Created a local plugin to get the data for each post and convert the markdown to HTML&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;onCreatePages&lt;/code&gt; API to dynamically create pages based on the post data&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;Post&lt;/code&gt; component to render from the data supplied by the &lt;code&gt;graphql&lt;/code&gt; query&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And that&apos;s about it, through this series we&apos;ve covered most of the basics on building a Gatsby site and handling a few scenarios for processing data using plugins and rendering content using Gatsby&apos;s available APIs&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>The Gatsby Migration, pt.2 - Dumb Pages</title><link>https://nabeelvalley.co.za/blog/2020/01-02/gatsby-migration-2/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/01-02/gatsby-migration-2/</guid><description>Migrating a React.js website to Gatsby.js</description><pubDate>Sat, 01 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&quot;/blog/2020/21-01/gatsby-migration-1&quot;&gt;last post&lt;/a&gt; we looked setting up an application with a few basic routes. These routes were all assigned to Components in the &lt;code&gt;src/pages&lt;/code&gt; directory.&lt;/p&gt;
&lt;p&gt;This post will be going throught the Gatsby Setup necessary in order to migrate our current site to Gatsby, we will be looking at the second step in the process that was outlined in the last post:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2020/21-01/gatsby-migration-1&quot;&gt;Creating the initial React App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rendering the &amp;quot;Dumb&amp;quot; pages with Gatsby&lt;/strong&gt; (This post)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2020/15-03/gatsby-migration-3&quot;&gt;Rendering the &amp;quot;Smart&amp;quot; page with Gatsby&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Getting Ready&lt;/h2&gt;
&lt;p&gt;In order to &lt;code&gt;Gatsbyify&lt;/code&gt; the application, there are three steps that we will need to take before we can start updating our pages to work with the new system&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update folder structure&lt;/li&gt;
&lt;li&gt;Install Gatsby&lt;/li&gt;
&lt;li&gt;Create the necessary Gatsby Config files&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Update Folder Structure&lt;/h3&gt;
&lt;p&gt;Gatsby Builds are placed into the &lt;code&gt;public&lt;/code&gt; directory. This currently is the output directory of a React build if we are using the standard React configuration&lt;/p&gt;
&lt;p&gt;Before we do anything more we should rename our &lt;code&gt;public&lt;/code&gt; directory to &lt;code&gt;static&lt;/code&gt; as this is what Gatsby uses for static files, and then make a &lt;code&gt;git commit&lt;/code&gt; before we add the &lt;code&gt;public&lt;/code&gt; directory to our &lt;code&gt;.gitignore&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Now we need to add the following lines to the end of our &lt;code&gt;.gitignore&lt;/code&gt; file so that we do not track the gatsby build files:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.gitignore&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;## gatsby
public
.cache
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Install Gatsby&lt;/h3&gt;
&lt;p&gt;To add Gataby to our project we need to add the &lt;code&gt;gatsby&lt;/code&gt; package from &lt;code&gt;npm&lt;/code&gt; as a dependency to our project. From the project&apos;s root directory run:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn add gatsby
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we&apos;ll add/update the following commands in our &lt;code&gt;package.json&lt;/code&gt; file so that we can start the Gatsby Dev Server as well as build the application&lt;/p&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;&amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;gatsby develop&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;gatsby build&amp;quot;,
    &amp;quot;clean&amp;quot;: &amp;quot;gatsby clean&amp;quot;,
    ...
},
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create Config Files&lt;/h3&gt;
&lt;p&gt;In order to enable gatsby we need to add the &lt;code&gt;gatsby-config.js&lt;/code&gt; file to our root directory, we can use the starter file with the following content, as it currently stands this doesn&apos;t do anything&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gatsby-config.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;module.exports = {
  plugins: [],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we&apos;ll create an &lt;code&gt;html.js&lt;/code&gt; file in the &lt;code&gt;src&lt;/code&gt; directory with any relevant content from your &lt;code&gt;index.html&lt;/code&gt; file if any of it has been updated. Also be sure to remove the &lt;code&gt;%PUBLIC_URL%&lt;/code&gt; stuff from the file content&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;html.js&lt;/code&gt; file needs to be a React Component with the following basic structure for a standard CRA app&lt;/p&gt;
&lt;p&gt;&lt;code&gt;src/html.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import PropTypes from &apos;prop-types&apos;

export default function HTML(props) {
  return (
    &amp;lt;html {...props.htmlAttributes}&amp;gt;
      &amp;lt;head&amp;gt;
        &amp;lt;meta charSet=&amp;quot;utf-8&amp;quot; /&amp;gt;
        &amp;lt;link rel=&amp;quot;shortcut icon&amp;quot; href=&amp;quot;/favicon.png&amp;quot; /&amp;gt;
        &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1&amp;quot; /&amp;gt;
        &amp;lt;meta name=&amp;quot;theme-color&amp;quot; content=&amp;quot;#ffffff&amp;quot; /&amp;gt;

        &amp;lt;link rel=&amp;quot;manifest&amp;quot; href=&amp;quot;/manifest.json&amp;quot; /&amp;gt;

        &amp;lt;title&amp;gt;React App&amp;lt;/title&amp;gt;

        &amp;lt;script
          dangerouslySetInnerHTML={{
            __html: `
                        // Any scripts that need to be included in the HTML itself
                        // Like tracking code, etc.
                        console.log(&amp;quot;Inline Javascript&amp;quot;)
                    `,
          }}
        &amp;gt;&amp;lt;/script&amp;gt;

        {props.headComponents}
      &amp;lt;/head&amp;gt;
      &amp;lt;body {...props.bodyAttributes}&amp;gt;
        {props.preBodyComponents}
        &amp;lt;div
          key={`body`}
          id=&amp;quot;___gatsby&amp;quot;
          dangerouslySetInnerHTML={{ __html: props.body }}
        /&amp;gt;
        {props.postBodyComponents}
      &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  )
}

HTML.propTypes = {
  htmlAttributes: PropTypes.object,
  headComponents: PropTypes.array,
  bodyAttributes: PropTypes.object,
  preBodyComponents: PropTypes.array,
  body: PropTypes.string,
  postBodyComponents: PropTypes.array,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can add or remove any elements in that file as per your specific requirements but most of the time the above should be fine&lt;/p&gt;
&lt;p&gt;Now that we have updated the &lt;code&gt;index.js&lt;/code&gt; file delete the &lt;code&gt;static/index.html&lt;/code&gt; file you can run the Gatsby Dev Server&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;yarn clean
yarn start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your application should now be running on &lt;code&gt;http://localhost:8000/&lt;/code&gt;, if started correctly you should see the Gatsby Development 404 Page:&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Development 404 Page&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;h1&amp;gt;Gatsby.js development 404 page&amp;lt;/h1&amp;gt;&lt;/p&gt;
&lt;p&gt;There&apos;s not a page yet at /&lt;/p&gt;
&lt;p&gt;&amp;lt;button&amp;gt;Preview custom 404 page&amp;lt;/button&amp;gt;&lt;/p&gt;
&lt;p&gt;Create a React.js component in your site directory at src/pages/index.js and this page will automatically refresh to show the new page component you created.&lt;/p&gt;
&lt;p&gt;If you were trying to reach another page, perhaps you can find it below.&lt;/p&gt;
&lt;p&gt;&amp;lt;h2&amp;gt;Pages (4)&amp;lt;/h2&amp;gt;&lt;/p&gt;
&lt;p&gt;Search:&lt;/p&gt;
&lt;p&gt;&amp;lt;label&amp;gt;Search:&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;search&amp;quot; placeholder=&amp;quot;Search pages...&amp;quot; value=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/label&amp;gt;&amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Submit&amp;quot;&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/Blog/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Home/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/NotFound/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Post/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;Page Setup&lt;/h2&gt;
&lt;p&gt;From the Development 404 Page we can see that Gatsby has found our previously created pages - this is because Gatsby looks for pages in the &lt;code&gt;pages&lt;/code&gt; directory, however when we click on a the links we will notice the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Home&lt;/code&gt; and &lt;code&gt;404&lt;/code&gt; render correctly&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Blog&lt;/code&gt; results in an error message&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Post&lt;/code&gt; results in an error message (we will address this page in the next post)&lt;/li&gt;
&lt;li&gt;Routes aren&apos;t aligned with our initial setup&lt;/li&gt;
&lt;li&gt;Components no longer have the layout we setup in the &lt;code&gt;App.js&lt;/code&gt; file&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are, for the most part, easy problems to solve&lt;/p&gt;
&lt;h3&gt;Fix the Blog Error Message&lt;/h3&gt;
&lt;p&gt;If we look at the &lt;code&gt;Blog&lt;/code&gt; page we will see that there is an issue with the Page render, this is because we need to change the &lt;code&gt;Link&lt;/code&gt; components to be imported from &lt;code&gt;gatsby&lt;/code&gt; instead of &lt;code&gt;react-router-dom&lt;/code&gt; because with Gatsby we are no longer using the React Router&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Blog.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { Link } from &apos;gatsby&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Fix the Routes&lt;/h3&gt;
&lt;p&gt;We can also see that our routes are capitalized which is not what we want. Gatsby uses the file organization to do routing, so in order to correct our routes to align what we defined previously in our &lt;code&gt;App.js&lt;/code&gt; we will first need to rename our files:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Old Name&lt;/th&gt;
&lt;th&gt;New Name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Home&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Home.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blog&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/blog&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Blog.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;blog.js&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NotFound&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;NotFound.js&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;404.js&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;We&apos;re not going to handle the &lt;code&gt;Post&lt;/code&gt; component for now because this uses a dynamic route which is something I&apos;ll cover in the next part of this series&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You should stop and restart the Gatsby Dev server with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn clean
yarn start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the page loads up we should now see our &lt;code&gt;Home&lt;/code&gt; content rendered on the &lt;code&gt;/&lt;/code&gt; route&lt;/p&gt;
&lt;h3&gt;Fix the Layout&lt;/h3&gt;
&lt;p&gt;When we were using the standard React Routing we made use of the &lt;code&gt;App&lt;/code&gt; component to wrap our page routes as well as our navigation. We&apos;ll convert our &lt;code&gt;App.js&lt;/code&gt; file into a component that we can use in our other pages&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Remove the &lt;code&gt;Router&lt;/code&gt; and &lt;code&gt;Switch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;Link&lt;/code&gt;s to use &lt;code&gt;gatsby&lt;/code&gt; instead of &lt;code&gt;react-router-dom&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;children&lt;/code&gt; input parameter&lt;/li&gt;
&lt;li&gt;Render the &lt;code&gt;children&lt;/code&gt; in the &lt;code&gt;main&lt;/code&gt; section&lt;/li&gt;
&lt;li&gt;Remove unused imports&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;App.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import &apos;./App.css&apos;
import { Link } from &apos;gatsby&apos;

const App = ({ children }) =&amp;gt; (
  &amp;lt;div className=&amp;quot;App&amp;quot;&amp;gt;
    &amp;lt;header&amp;gt;
      &amp;lt;nav&amp;gt;
        &amp;lt;h1&amp;gt;My Website Title&amp;lt;/h1&amp;gt;
        &amp;lt;Link to=&amp;quot;/&amp;quot;&amp;gt;Home&amp;lt;/Link&amp;gt;
        &amp;lt;Link to=&amp;quot;/blog&amp;quot;&amp;gt;Blog&amp;lt;/Link&amp;gt;
      &amp;lt;/nav&amp;gt;
    &amp;lt;/header&amp;gt;
    &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
  &amp;lt;/div&amp;gt;
)

export default App
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Use the Layout&lt;/h3&gt;
&lt;p&gt;Now that we&apos;ve essentially created a &lt;code&gt;Layout&lt;/code&gt; component in the form of the &lt;code&gt;App&lt;/code&gt; component we can use it to wrap the pages that we&apos;ve exported. We can do this for the &lt;code&gt;Home&lt;/code&gt; page like so:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import App from &apos;../App&apos;

const Home = () =&amp;gt; (
  &amp;lt;App&amp;gt;
    &amp;lt;div className=&amp;quot;Home&amp;quot;&amp;gt;
      &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;This is the Home page&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/App&amp;gt;
)

export default Home
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same applies for the &lt;code&gt;blog&lt;/code&gt; and &lt;code&gt;404&lt;/code&gt; pages&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Blog&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;blog.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import { Link } from &apos;gatsby&apos;
import App from &apos;../App&apos;

const Blog = () =&amp;gt; (
  &amp;lt;App&amp;gt;
    &amp;lt;div className=&amp;quot;Blog&amp;quot;&amp;gt;
      &amp;lt;h1&amp;gt;Blog&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;This is the Blog page&amp;lt;/p&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;Link to=&amp;quot;/blog/post-1&amp;quot;&amp;gt;Post 1&amp;lt;/Link&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div&amp;gt;
        &amp;lt;Link to=&amp;quot;/blog/post-2&amp;quot;&amp;gt;Post 2&amp;lt;/Link&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/App&amp;gt;
)

export default Blog
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;404&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;404.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import App from &apos;../App&apos;

const NotFound = () =&amp;gt; (
  &amp;lt;App&amp;gt;
    &amp;lt;div className=&amp;quot;NotFound&amp;quot;&amp;gt;
      &amp;lt;h1&amp;gt;404&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;Page Not Found&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/App&amp;gt;
)

export default NotFound
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h3&gt;Fix the CSS&lt;/h3&gt;
&lt;p&gt;Before we can use the &lt;code&gt;App&lt;/code&gt; component we need to add the &lt;code&gt;gatsby-plugin-postcss&lt;/code&gt; and &lt;code&gt;postcss-preset-env&lt;/code&gt; plugins so that Gatsby knows how to interpret the default &lt;code&gt;create-react-app&lt;/code&gt; method of importing our CSS into a component&lt;/p&gt;
&lt;p&gt;Stop the Dev Server and install the required packages:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn add gatsby-plugin-postcss postcss-preset-env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We then need to update the &lt;code&gt;gatsby-config.js&lt;/code&gt; file to use the plugin we just added:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gatsby-config.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-postcss`,
      options: {
        postCssPlugins: [require(`postcss-preset-env`)({ stage: 0 })],
      },
    },
  ],
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you start the application now you&apos;ll notice that the font is not correct, this is because we specify the font styles in the &lt;code&gt;index.css&lt;/code&gt; file. In order to fix this we need to import the &lt;code&gt;index.css&lt;/code&gt; file into our application, in the default React application this is done via the &lt;code&gt;src/index.js&lt;/code&gt; file, but since we don&apos;t use that to load up the application anymore we need to create another file to do that with Gatsby&lt;/p&gt;
&lt;p&gt;In the root directory create a file called &lt;code&gt;gatsby-browser.js&lt;/code&gt;, in this we just need to import the &lt;code&gt;index.css&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gatsby-browser.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import &apos;./src/index.css&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can now run the following commands and start up the application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn clean
yarn start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assuming everything went as planned the application should start up correctly and the styling from our &lt;code&gt;index.css&lt;/code&gt; file will be correctly applied&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;By now we have completed the first part of the migration process - converting our static pages to use Gatsby - by taking the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Updating our file structure to better align with Gatsby&lt;/li&gt;
&lt;li&gt;Create the relevant Gatsby config files&lt;/li&gt;
&lt;li&gt;Update our &lt;code&gt;Link&lt;/code&gt; usage&lt;/li&gt;
&lt;li&gt;Update our Routing&lt;/li&gt;
&lt;li&gt;Use a shared layout component&lt;/li&gt;
&lt;li&gt;Fixing the CSS to work with Gatsby&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the next part we&apos;ll look at how we can go about providing the data needed for our &lt;code&gt;Post&lt;/code&gt; component using GraphQL and show our posts. We&apos;ll also look at how we can pre-process the data that we provide to our component so that we can enhance our content while improving our content creation process&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>The Gatsby Migration, pt.1 - Setting the Scene</title><link>https://nabeelvalley.co.za/blog/2020/21-01/gatsby-migration-1/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2020/21-01/gatsby-migration-1/</guid><description>Building a basic React site with basic dynamic data loading</description><pubDate>Tue, 21 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Lately I&apos;ve been a little concerned with my current SPA approach on my personal site as well as a few others. More specifically the high initial load time due to the calls to the backend to retrieve content&lt;/p&gt;
&lt;p&gt;With the aim of solving this problem I&apos;ve spent a lot of time looking at and playing with Static Site Generators.Foreword: they&apos;re all a lot more complicated than one would think&lt;/p&gt;
&lt;p&gt;So for a static site the &amp;quot;static&amp;quot; content only changes so often, based on this we can generate page content with the data we&apos;re planning to load in - that&apos;s what we&apos;re going to try to do&lt;/p&gt;
&lt;p&gt;Now we&apos;ll be starting off with a React app generated with &lt;code&gt;create-react-app&lt;/code&gt; so that we can have a starting point for our Gatsby site as well as understanding how we can approach some of the challenges when switching over to a site generator like Gatsby&lt;/p&gt;
&lt;p&gt;For the sake of completeness, this series will be broken into four posts covering the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Creating the initial React App&lt;/strong&gt; (This post)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2020/01-02/gatsby-migration-2&quot;&gt;Rendering the &amp;quot;Dumb&amp;quot; pages with Gatsby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/blog/2020/15-03/gatsby-migration-3&quot;&gt;Rendering the &amp;quot;Smart&amp;quot; page with Gatsby&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The React App&lt;/h2&gt;
&lt;p&gt;First we&apos;re going to be starting off with a new React app that we will work on changing into a Gatsby one parts &lt;code&gt;2&lt;/code&gt; and &lt;code&gt;3&lt;/code&gt;, we&apos;ll then focus on using plugins to enhance our content in &lt;code&gt;4&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For this part we&apos;ll build a basic React app that has the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Two &amp;quot;hard-coded&amp;quot; pages and a 404 page&lt;/li&gt;
&lt;li&gt;A dynamic page with an API call to retrieve data&lt;/li&gt;
&lt;li&gt;Overall app layout with child routes for &lt;code&gt;1&lt;/code&gt; - &lt;code&gt;3&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To get started, we&apos;ll create a fresh React App:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npx create-react-app gatsby-to-be
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And add the &lt;code&gt;react-router&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;yarn add react-router-dom
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this command should set up the application, if you don&apos;t know much about React I&apos;d suggest taking a look at &lt;a href=&quot;https://create-react-app.dev/docs/getting-started&quot;&gt;the documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next &lt;code&gt;cd gatsby-to-be&lt;/code&gt; and run &lt;code&gt;yarn start&lt;/code&gt;, you should be able to visit the application in your browser at &lt;code&gt;http://localhost:3000/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Looking at the generated files we have a &lt;code&gt;public&lt;/code&gt; directory with some icons, an &lt;code&gt;index.html&lt;/code&gt; file into which our React application will run once built, and a &lt;code&gt;src&lt;/code&gt; directory that has the application code. The &lt;code&gt;index.js&lt;/code&gt; file is what loads the application into the DOM and the &lt;code&gt;App.js&lt;/code&gt; file which is the main component for our application&lt;/p&gt;
&lt;h2&gt;Hard Coded Pages&lt;/h2&gt;
&lt;p&gt;We will create the following three hard-coded pages in the &lt;code&gt;src/pages&lt;/code&gt; directory&lt;/p&gt;
&lt;p&gt;These pages are just React components that we will assign Routes to.&lt;/p&gt;
&lt;p&gt;The pages we are using are known as &lt;code&gt;functional&lt;/code&gt; components because they are javascript functions that return JSX&lt;/p&gt;
&lt;p&gt;If we intend to use JSX in a file we need to ensure that we import &lt;code&gt;React&lt;/code&gt;. The other component we are importing is the &lt;code&gt;Link&lt;/code&gt; component which is a lot like a normal HTML &lt;code&gt;a&lt;/code&gt; tag but with some special functionality to make the client-side navigation work&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Blog.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import { Link } from &apos;react-router-dom&apos;

const Blog = () =&amp;gt; (
  &amp;lt;div className=&amp;quot;Blog&amp;quot;&amp;gt;
    &amp;lt;h1&amp;gt;Blog&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;This is the Blog page&amp;lt;/p&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;Link to=&amp;quot;/blog/post-1&amp;quot;&amp;gt;Post 1&amp;lt;/Link&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;Link to=&amp;quot;/blog/post-2&amp;quot;&amp;gt;Post 2&amp;lt;/Link&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
)

export default Blog
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additionally we have the &lt;code&gt;Home.js&lt;/code&gt; and &lt;code&gt;NotFound.js&lt;/code&gt; files which are similar to the &lt;code&gt;Blog.js&lt;/code&gt; file we created&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Home&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Home.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;

const Home = () =&amp;gt; (
  &amp;lt;div className=&amp;quot;Home&amp;quot;&amp;gt;
    &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;This is the Home page&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
)

export default Home
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Not Found&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NotFound.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;

const NotFound = () =&amp;gt; (
  &amp;lt;div className=&amp;quot;NotFound&amp;quot;&amp;gt;
    &amp;lt;h1&amp;gt;404&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Page Not Found&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
)

export default NotFound
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;Dynamic Post Page&lt;/h2&gt;
&lt;p&gt;Next up we&apos;ll create a component that can render out content for a blog post. This will consist of a few &lt;code&gt;hooks&lt;/code&gt; which are react functions that we can use to sort of control the data in a function&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Post&lt;/code&gt; component will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Display a loading indicator initially&lt;/li&gt;
&lt;li&gt;Figure out what post we&apos;re trying to render based on the URL&lt;/li&gt;
&lt;li&gt;Retrieve a JSON file from the &lt;code&gt;public&lt;/code&gt; directory based&lt;/li&gt;
&lt;li&gt;Set the component state after reading the file&lt;/li&gt;
&lt;li&gt;Display the content from the file in a JSX template&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;useState&lt;/code&gt; hook is used to initialize the state the component, in this case using the &lt;code&gt;hasError&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt; variables, as well as providing the functions necessary for updating those in the form of &lt;code&gt;setHasError&lt;/code&gt; and &lt;code&gt;setData&lt;/code&gt; respectively&lt;/p&gt;
&lt;p&gt;We use &lt;code&gt;fetch&lt;/code&gt; in the &lt;code&gt;useEffect&lt;/code&gt; hook to retrieve the data from the &lt;code&gt;public&lt;/code&gt; directory. The &lt;code&gt;useEffect&lt;/code&gt; hook allows us to pass a function that will be called to update side effects. The second input, in our case &lt;code&gt;[]&lt;/code&gt; is the array of objects that, when are changed, we want the hook to run - since we only want it to run once and don&apos;t care about any other state changes we pass in an empty array for this value&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Post.js&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React, { useEffect, useState } from &apos;react&apos;

const Post = ({ match }) =&amp;gt; {
  const slug = match.params.slug

  const [hasError, setHasError] = useState(false)
  const [data, setData] = useState(null)

  useEffect(() =&amp;gt; {
    const fetchData = async () =&amp;gt; {
      try {
        const res = await fetch(`/posts/${slug}.json`)
        const json = await res.json()
        setData(json)
      } catch (error) {
        console.log(error.toString())
        setHasError(true)
      }
    }

    fetchData()
  }, [])

  return (
    &amp;lt;div className=&amp;quot;Post&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;
        This is the &amp;lt;code&amp;gt;{slug}&amp;lt;/code&amp;gt; page
      &amp;lt;/p&amp;gt;
      {data ? (
        &amp;lt;div className=&amp;quot;content&amp;quot;&amp;gt;
          &amp;lt;h1&amp;gt;{data.title}&amp;lt;/h1&amp;gt;
          &amp;lt;p&amp;gt;{data.body}&amp;lt;/p&amp;gt;
          &amp;lt;img src={data.image} alt=&amp;quot;&amp;quot; /&amp;gt;
        &amp;lt;/div&amp;gt;
      ) : hasError ? (
        &amp;lt;div className=&amp;quot;error&amp;quot;&amp;gt;
          &amp;lt;h1&amp;gt;Error&amp;lt;/h1&amp;gt;
          &amp;lt;p&amp;gt;{hasError}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      ) : (
        &amp;lt;p&amp;gt;Loading .. &amp;lt;/p&amp;gt;
      )}
    &amp;lt;/div&amp;gt;
  )
}

export default Post
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above component we&apos;re making use of the following pattern to decide what to render conditionally:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If the data is loaded then show the data&lt;/li&gt;
&lt;li&gt;Else if there is an error then show the error data&lt;/li&gt;
&lt;li&gt;Otherwise show a loading message&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The way we are rendering the &lt;code&gt;Post&lt;/code&gt; component with a parameter for &lt;code&gt;match&lt;/code&gt;. The &lt;code&gt;match&lt;/code&gt; parameter will be passed in as a &lt;code&gt;prop&lt;/code&gt; from the &lt;code&gt;Router&lt;/code&gt; that we will configure next, this allows us to use the &lt;code&gt;slug&lt;/code&gt; from the URL to retrieve the content for the page&lt;/p&gt;
&lt;p&gt;The two data files we have to pull content from in the &lt;code&gt;public/posts&lt;/code&gt; directory are &lt;code&gt;post-1.json&lt;/code&gt; and &lt;code&gt;post-2.json&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Post 1 - JSON&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;post-1.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;title&amp;quot;: &amp;quot;Post 1&amp;quot;,
  &amp;quot;body&amp;quot;: &amp;quot;Hello world, how are you&amp;quot;,
  &amp;quot;image&amp;quot;: &amp;quot;/posts/1.jpg&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt;Post 2 - JSON&amp;lt;/summary&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;post-2.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &amp;quot;title&amp;quot;: &amp;quot;Post 2&amp;quot;,
  &amp;quot;body&amp;quot;: &amp;quot;Hello world, I am fine&amp;quot;,
  &amp;quot;image&amp;quot;: &amp;quot;/posts/2.jpg&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The images &lt;code&gt;posts/1.jpg&lt;/code&gt; and &lt;code&gt;posts/2.jpg&lt;/code&gt; can also just be any images in that directory&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;/details&amp;gt;&lt;/p&gt;
&lt;h2&gt;App Layout and Routes&lt;/h2&gt;
&lt;p&gt;Lastly, we&apos;ll specify our application layout with the relevant routes in the &lt;code&gt;App.js&lt;/code&gt; file, referencing the components we have created, we do this using the &lt;code&gt;BrowserRouter&lt;/code&gt;. When we switch the project over to a Gatsby one, the &lt;code&gt;App.js&lt;/code&gt; file will be converted into our &lt;code&gt;Layout&lt;/code&gt; component to wrap our different pages&lt;/p&gt;
&lt;p&gt;We use the &lt;code&gt;Router&lt;/code&gt; component and the page inside of it, this essentially handles Routing via the &lt;code&gt;Link&lt;/code&gt; components. Next we have a &lt;code&gt;div&lt;/code&gt; as a wrapper for our component as well as a &lt;code&gt;header&lt;/code&gt;, &lt;code&gt;nav&lt;/code&gt;, and &lt;code&gt;main&lt;/code&gt; tags to organise the page&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Route&lt;/code&gt; component takes in the component that we would like to display for a given route, and the &lt;code&gt;Switch&lt;/code&gt; helps us to ensure that only route is actively being fisplayed at a time. The &lt;code&gt;Switch&lt;/code&gt; will navigate from the first to last &lt;code&gt;Route&lt;/code&gt; and render the first one that matches the given &lt;code&gt;path&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Fow now, our &lt;code&gt;App.js&lt;/code&gt; file is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import &apos;./App.css&apos;
import { BrowserRouter as Router, Link, Switch, Route } from &apos;react-router-dom&apos;
import Home from &apos;./pages/Home&apos;
import Blog from &apos;./pages/Blog&apos;
import Post from &apos;./pages/Post&apos;
import NotFound from &apos;./pages/NotFound&apos;

const App = () =&amp;gt; (
  &amp;lt;Router&amp;gt;
    &amp;lt;div className=&amp;quot;App&amp;quot;&amp;gt;
      &amp;lt;header&amp;gt;
        &amp;lt;nav&amp;gt;
          &amp;lt;h1&amp;gt;My Website Title&amp;lt;/h1&amp;gt;
          &amp;lt;Link to=&amp;quot;/&amp;quot;&amp;gt;Home&amp;lt;/Link&amp;gt;
          &amp;lt;Link to=&amp;quot;/blog&amp;quot;&amp;gt;Blog&amp;lt;/Link&amp;gt;
        &amp;lt;/nav&amp;gt;
      &amp;lt;/header&amp;gt;
      &amp;lt;main&amp;gt;
        &amp;lt;Switch&amp;gt;
          &amp;lt;Route exact path=&amp;quot;/&amp;quot; component={Home}&amp;gt;&amp;lt;/Route&amp;gt;

          &amp;lt;Route exact path=&amp;quot;/blog&amp;quot; component={Blog}&amp;gt;&amp;lt;/Route&amp;gt;

          &amp;lt;Route exact path=&amp;quot;/blog/:slug&amp;quot; component={Post}&amp;gt;&amp;lt;/Route&amp;gt;

          &amp;lt;Route path=&amp;quot;/*&amp;quot; component={NotFound}&amp;gt;&amp;lt;/Route&amp;gt;
        &amp;lt;/Switch&amp;gt;
      &amp;lt;/main&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/Router&amp;gt;
)

export default App
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above component we can see that where we are rendering the &lt;code&gt;Post&lt;/code&gt; component we have a parameter in the route called &lt;code&gt;slug&lt;/code&gt;, this parameter will be passed in to the &lt;code&gt;Post&lt;/code&gt; component as part of the &lt;code&gt;match&lt;/code&gt; object&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;We have built a fairly simple application that makes use of both static and data-based pages, we have also tied all of these together using the &lt;code&gt;App&lt;/code&gt; component and a &lt;code&gt;Router&lt;/code&gt; with the following routes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;/&lt;/code&gt; which will render the &lt;code&gt;Home&lt;/code&gt; component&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/blog&lt;/code&gt; which will render the &lt;code&gt;Blog&lt;/code&gt; component&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/blog/:slug&lt;/code&gt; which will render the &lt;code&gt;Post&lt;/code&gt; component and retrieve the data based on the given &lt;code&gt;slug&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/*&lt;/code&gt; which will match any other routes and render the &lt;code&gt;NotFound&lt;/code&gt; component&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the next post we&apos;re going to look at how to take what we have so far and transform this application into a Gatsby one, but for now it may be useful to think about what kind of steps we may need to take if we&apos;d like to make this a static website based on the way our current routes work&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Real-time Communication with MQTT</title><link>https://nabeelvalley.co.za/blog/2019/12-11/rtc-with-mqtt/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2019/12-11/rtc-with-mqtt/</guid><description>MQTT and real-time communication with the browser, JavaScript, Web Sockets and a Mosquitto message broker</description><pubDate>Tue, 12 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;MQTT is an open standard for communication and is especially useful for communication between IoT devices due to its low bandwidth requirements&lt;/p&gt;
&lt;p&gt;Today we&apos;re going to be taking a look at using MQTT to easily communicate between multiple applications. We&apos;ll look at using a static website and Eclipse Mosquitto as a message broker to enable communication between two instances of the application, but the same principles can be extended to other programming languages and MQTT clients. For our clients we&apos;ll be using &lt;code&gt;MQTT.js&lt;/code&gt; which runs in the browser via CDN and we interact with it using JavaScript, but can also be added from &lt;code&gt;npm&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If you&apos;d like to follow along with the completed code you can get it &amp;lt;a href=&amp;quot;https://github.com/nabeelvalley/RTCWithMQTT&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;here&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h2&gt;Broker&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Eclipse Mosquitto is an open-source (EPL/EDL licensed) message broker that implements the MQTT protocol versions 5.0, 3.1.1 and 3.1. Mosquitto is lightweight and is suitable for use on all devices from low power single board computers to full servers. (&amp;lt;a href=&amp;quot;https://mosquitto.org/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;Eclipse Mosquitto&amp;lt;/a&amp;gt; )&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Message brokers are a method of intra-application communication, MQTT makes use of a publish/subscribe model for application communication. In this model different applications, or clients, can publish messages to a topic which can then be picked up and operated on by any other applications that are subscribed to the topic&lt;/p&gt;
&lt;h3&gt;Setting Up the Broker&lt;/h3&gt;
&lt;p&gt;You will first need to download Mosquitto from &amp;lt;a href=&amp;quot;https://mosquitto.org/download/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;here&amp;lt;/a&amp;gt; , all &lt;code&gt;1.5mb&lt;/code&gt; of it, and run through the installer and then ensure that &lt;code&gt;mosquitto&lt;/code&gt; is in your path. If you need to know how to add something to your path take a look at &amp;lt;a href=&amp;quot;https://gist.github.com/nex3/c395b2f8fd4b02068be37c961301caa7&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;this Gist&amp;lt;/a&amp;gt; . For a Windows 64 bit installation of Mosquitto you should add the following to your path &lt;code&gt;C:\Program Files\mosquitto&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The MQTT installation should include the following three commands&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;mosquitto&lt;/code&gt; - This runs the MQTT server/broker&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mosquitto_pub&lt;/code&gt; - A simple message publisher&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mosquitto_sub&lt;/code&gt; - A simple message subscriber&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can get more information by running either of the above commands with the &lt;code&gt;--help&lt;/code&gt; flag, e.g. &lt;code&gt;mosquitto --help&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Basic Messaging&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Let&apos;s start the message broker in verbose mode by opening a new shell and running the &lt;code&gt;mosquitto -v&lt;/code&gt; command, you should see some output like the following:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-raw&quot;&gt;1573494107: mosquitto version 1.6.7 starting
1573494107: Using default config.
1573494107: Opening ipv6 listen socket on port 1883.
1573494107: Opening ipv4 listen socket on port 1883.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see from the above that the message broker is running on our local port &lt;code&gt;1883&lt;/code&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;In a new shell, we can create a client which is subscribed to a topic. We&apos;ll name this topic &lt;code&gt;messages&lt;/code&gt; but it can be pretty much anything you want, to start the subscriber client we can run &lt;code&gt;mosquitto_sub -t &amp;quot;messages&amp;quot; -v&lt;/code&gt;, you won&apos;t see any output in the subscriber shell as yet, but looking at the broker shell you should logging which says that a client was connected&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-raw&quot;&gt;1573494642: New connection from ::1 on port 1883.
1573494642: New client connected from ::1 as mosq-fwbsJxdXOnQW0LOaIn (p2, c1, k60).
1573494642: No will message specified.
1573494642: Sending CONNACK to mosq-fwbsJxdXOnQW0LOaIn (0, 0)
1573494642: Received SUBSCRIBE from mosq-fwbsJxdXOnQW0LOaIn
1573494642:     messages (QoS 0)
1573494642: mosq-fwbsJxdXOnQW0LOaIn 0 messages
1573494642: Sending SUBACK to mosq-fwbsJxdXOnQW0LOaIn
1573494702: Received PINGREQ from mosq-fwbsJxdXOnQW0LOaIn
1573494702: Sending PINGRESP to mosq-fwbsJxdXOnQW0LOaIn
&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;To publish a message open another shell and run &lt;code&gt;mosquitto_pub -t &amp;quot;messages&amp;quot; -m &amp;quot;This is my message!&amp;quot;&lt;/code&gt;, in our subscriber shell we should see the following output:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-raw&quot;&gt;messages This is my message!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And in the broker we&apos;ll see the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-raw&quot;&gt;1573494844: New connection from ::1 on port 1883.
1573494844: New client connected from ::1 as mosq-MWbaa2TpZGV0FrTmcF (p2, c1, k60).
1573494844: No will message specified.
1573494844: Sending CONNACK to mosq-MWbaa2TpZGV0FrTmcF (0, 0)
1573494844: Received PUBLISH from mosq-MWbaa2TpZGV0FrTmcF (d0, q0, r0, m0, &apos;messages&apos;, ... (19 bytes))
1573494844: Sending PUBLISH to mosq-fwbsJxdXOnQW0LOaIn (d0, q0, r0, m0, &apos;messages&apos;, ... (19 bytes))
1573494844: Received DISCONNECT from mosq-MWbaa2TpZGV0FrTmcF
1573494844: Client mosq-MWbaa2TpZGV0FrTmcF disconnected.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you&apos;re done with this you can close the open shell windows&lt;/p&gt;
&lt;h3&gt;Broker with WebSockets&lt;/h3&gt;
&lt;p&gt;For our usecase, we will make use of WebSockets so we can communicate directly from the browser. When starting up the message broker we have the option to pass in a configuration file. Let&apos;s create one that states the port and the protocol we would like to use. Create a new directory called &lt;code&gt;mqtt&lt;/code&gt;, and in it create a new file called &lt;code&gt;mosquitto.conf&lt;/code&gt; and place the following contents which simply tell it to listen on port &lt;code&gt;9001&lt;/code&gt; and use the &lt;code&gt;websockets&lt;/code&gt; protocol&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mosquitto.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;listener 9001
protocol websockets
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you&apos;d like to know what else can be done in the configuration file you can &amp;lt;a href=&amp;quot;https://mosquitto.org/man/mosquitto-conf-5.html&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;read the documentation&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;We can start the broker again from the &lt;code&gt;mqtt&lt;/code&gt; directory using &lt;code&gt;mosquitto -c mosquitto.conf -v&lt;/code&gt;, this time we should see that it is running on &lt;code&gt;9001&lt;/code&gt; with &lt;code&gt;websockets&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1573499281: mosquitto version 1.6.7 starting
1573499281: Config loaded from mosquitto.conf.
1573499281: Opening websockets listen socket on port 9001.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have configured the broker to use Web Sockets we can start connecting to it from a web page and publish some messages&lt;/p&gt;
&lt;h2&gt;Client&lt;/h2&gt;
&lt;p&gt;We&apos;ll be using &amp;lt;a href=&amp;quot;https://github.com/mqttjs/MQTT.js&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;MQTT.js&amp;lt;/a&amp;gt; to connect to our message broker. MQTT.js is a simple MQTT Client Library for connecting to message brokers, we&apos;ll be using it via CDN for the sake of simplicity and will also be using &amp;lt;a href=&amp;quot;https://materializecss.com/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;Materialize&amp;lt;/a&amp;gt; for our CSS because I&apos;m not going to write a bunch of CSS and I don&apos;t want this to look completely terrible&lt;/p&gt;
&lt;h3&gt;HTML&lt;/h3&gt;
&lt;p&gt;Let&apos;s first setup the &lt;code&gt;index.html&lt;/code&gt;. It consists of a two-column layout with the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Main Heading with a badge to indicate if we successfully connected to the broker&lt;/li&gt;
&lt;li&gt;Inputs to Publish Message&lt;/li&gt;
&lt;li&gt;Table of all received messages&lt;/li&gt;
&lt;li&gt;Materialize and MQTT.js files via CDN&lt;/li&gt;
&lt;li&gt;Script tag for all our JavaScript, because we don&apos;t need two files for this&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;gt;
    &amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;ie=edge&amp;quot; /&amp;gt;
    &amp;lt;title&amp;gt;Real-time Communication with MQTT&amp;lt;/title&amp;gt;

    &amp;lt;!-- MQTT.js --&amp;gt;
    &amp;lt;script src=&amp;quot;https://unpkg.com/mqtt@3.0.0/dist/mqtt.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;

    &amp;lt;!-- Materialize --&amp;gt;
    &amp;lt;!-- Compiled and minified CSS --&amp;gt;
    &amp;lt;link
      rel=&amp;quot;stylesheet&amp;quot;
      href=&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css&amp;quot;
    /&amp;gt;
  &amp;lt;/head&amp;gt;

  &amp;lt;body&amp;gt;
    &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;
      &amp;lt;!-- Page Content goes here --&amp;gt;
      &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;col s12&amp;quot;&amp;gt;
          &amp;lt;h1&amp;gt;
            Messages
            &amp;lt;span
              id=&amp;quot;connect-badge&amp;quot;
              class=&amp;quot;new badge orange&amp;quot;
              data-badge-caption=&amp;quot;&amp;quot;
              &amp;gt;connecting&amp;lt;/span
            &amp;gt;
          &amp;lt;/h1&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;col s12 m6&amp;quot;&amp;gt;
          &amp;lt;h2&amp;gt;Input&amp;lt;/h2&amp;gt;
          &amp;lt;div class=&amp;quot;input-field&amp;quot;&amp;gt;
            &amp;lt;input id=&amp;quot;name&amp;quot; type=&amp;quot;text&amp;quot; class=&amp;quot;validate&amp;quot; /&amp;gt;
            &amp;lt;label class=&amp;quot;active&amp;quot; for=&amp;quot;name&amp;quot;&amp;gt;First Name&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;

          &amp;lt;div class=&amp;quot;input-field&amp;quot;&amp;gt;
            &amp;lt;textarea
              id=&amp;quot;message&amp;quot;
              class=&amp;quot;materialize-textarea&amp;quot;
              data-length=&amp;quot;120&amp;quot;
            &amp;gt;&amp;lt;/textarea&amp;gt;
            &amp;lt;label for=&amp;quot;message&amp;quot;&amp;gt;Message&amp;lt;/label&amp;gt;
          &amp;lt;/div&amp;gt;

          &amp;lt;button class=&amp;quot;waves-effect waves-light btn&amp;quot; onclick=&amp;quot;handleSubmit()&amp;quot;&amp;gt;
            Publish Message
          &amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class=&amp;quot;col s12 m6&amp;quot;&amp;gt;
          &amp;lt;h2&amp;gt;Output&amp;lt;/h2&amp;gt;
          &amp;lt;table&amp;gt;
            &amp;lt;thead&amp;gt;
              &amp;lt;tr&amp;gt;
                &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Message&amp;lt;/th&amp;gt;
              &amp;lt;/tr&amp;gt;
            &amp;lt;/thead&amp;gt;
            &amp;lt;tbody id=&amp;quot;messages&amp;quot;&amp;gt;&amp;lt;/tbody&amp;gt;
          &amp;lt;/table&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;script&amp;gt;
      // Our Javascript will go here
    &amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;

  &amp;lt;!-- Materialize --&amp;gt;
  &amp;lt;!-- Compiled and minified JavaScript --&amp;gt;
  &amp;lt;script src=&amp;quot;https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Running the Website&lt;/h3&gt;
&lt;p&gt;Since we are including resources from other domains your browser may have some issues with you using the &apos;double click&apos; method of running the files, so we&apos;re going to need to use a web server&lt;/p&gt;
&lt;p&gt;A list of quick one-line web servers can be found on this &amp;lt;a href=&amp;quot;https://gist.github.com/willurd/5720255&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;Gist&amp;lt;/a&amp;gt; and if you&apos;re using Visual Studio Code you can use the Live Server Extension&lt;/p&gt;
&lt;h3&gt;Connecting to the Message Broker&lt;/h3&gt;
&lt;p&gt;Now that we&apos;re up and running we can connect to the broker that we set up previously. The Mosquitto Broker should be running on &lt;code&gt;127.0.0.1:9001&lt;/code&gt;, using the &lt;code&gt;mqtt&lt;/code&gt; object that is exposed in the global space by &lt;code&gt;MQTT.js&lt;/code&gt; we can simply create an instance of the client in our &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; section with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const client = mqtt.connect(&apos;mqtt://127.0.0.1:9001&apos;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives us a &lt;code&gt;client&lt;/code&gt; object that is the MQTT Client connected to our broker. Next, we need to set a handler for the &lt;code&gt;connect&lt;/code&gt; event which is when the client successfully connects to the message broker, we do this with the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;client.on(&apos;connect&apos;, function () {
  client.subscribe(&apos;messages&apos;, function (err) {
    if (!err) {
      const badge = document.getElementById(&apos;connect-badge&apos;)
      badge.innerText = &apos;connected&apos;
      badge.classList.remove(&apos;orange&apos;)
      badge.classList.add(&apos;green&apos;)
    }
  })
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see that the &lt;code&gt;client.on&lt;/code&gt; function takes a callback, in which we tell our client to subscribe to the &lt;code&gt;messages&lt;/code&gt; topic as we did previously via the &lt;code&gt;mosquitto_sub&lt;/code&gt;, and then once it has successfully subscribed we change the badge status to indicate that we are connected&lt;/p&gt;
&lt;p&gt;Since we have successfully subscribed the client to the broker we should be able to publish messages. We&apos;ll do that using the data from the input fields in on the page and the &lt;code&gt;Publish Message&lt;/code&gt; button&apos;s handler&lt;/p&gt;
&lt;h3&gt;Publishing Messages&lt;/h3&gt;
&lt;p&gt;Create a handler for the &lt;code&gt;Publish Message&lt;/code&gt; button called &lt;code&gt;handleSubmit&lt;/code&gt;, we&apos;ve already referenced this in our button&apos;s HTML. The handler simply needs to read the values from the input fields and call &lt;code&gt;client.publish&lt;/code&gt; with a stringified form of the data&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function handleSubmit() {
  const nameInput = document.getElementById(&apos;name&apos;)
  const messageInput = document.getElementById(&apos;message&apos;)

  const data = {
    name: nameInput.value,
    message: messageInput.value,
  }

  const payload = JSON.stringify(data)

  client.publish(&apos;messages&apos;, payload)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;client.publish&lt;/code&gt; function above takes in a &lt;code&gt;topic&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt; as its inputs, in our case we want to publish to the &lt;code&gt;messages&lt;/code&gt; topic and we are publishing the JSON object as a string&lt;/p&gt;
&lt;p&gt;Refreshing the page, entering some text into the fields and clicking the &lt;code&gt;Publish Message&lt;/code&gt; button should publish the message to the broker, we should see this in the message broker&apos;s output&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-raw&quot;&gt;1573506416: Received PUBLISH from mqttjs_d5cdbc8e (d0, q0, r0, m0, &apos;messages&apos;, ... (34 bytes))
1573506416: Sending PUBLISH to mqttjs_d5cdbc8e (d0, q0, r0, m0, &apos;messages&apos;, ... (34 bytes))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we can publish messages to the topic, we will need to create a handler for the &lt;code&gt;message&lt;/code&gt; event which is triggered every time one of our subscribed topics has something published to it. We can do this again with the &lt;code&gt;client.on&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;client.on(&apos;message&apos;, function (topic, message) {
  const data = JSON.parse(message)

  document.getElementById(&apos;messages&apos;).innerHTML += `&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;${
    data.name
  }&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;${data.message.replace(/\n/g, &apos;&amp;lt;br&amp;gt;&apos;)}&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;`
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Our message handler receives the &lt;code&gt;topic&lt;/code&gt;, which in our case will always be &lt;code&gt;messages&lt;/code&gt; and the &lt;code&gt;message&lt;/code&gt; which is a buffer of the data published to the topic, this will be the same data that we published using the &lt;code&gt;client.publish&lt;/code&gt; function, this time we read the JSON back into an object and add it to the messages table as HTML&lt;/p&gt;
&lt;p&gt;You should be able to open a few different windows of the web page and they should all be able to Publish Messages to one another&lt;/p&gt;
&lt;h2&gt;What Next?&lt;/h2&gt;
&lt;p&gt;If you&apos;re not familiar with message brokers this could be a lot to take in and that&apos;s okay. I think playing around with the &lt;code&gt;mosquitto_pub&lt;/code&gt; and &lt;code&gt;mosquitto_sub&lt;/code&gt; tools can be helpful to get a more interactive feel for the way everything works. You can also just play with the MQTT.js code we used via your browser console and looking at the documentation on the website&lt;/p&gt;
&lt;p&gt;If you want to take a look at a free instance of an MQTT Broker that you can play around with take a look at &amp;lt;a href=&amp;quot;https://www.cloudmqtt.com/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;Cloud MQTT&amp;lt;/a&amp;gt; , and if you want to look at how you can take the concepts covered here today and play around with some IoT concepts as well then it may also be worth taking a look at this &amp;lt;a href=&amp;quot;https://developer.ibm.com/tutorials/iot-mobile-phone-iot-device-bluemix-apps-trs/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;IBM Developer Tutorial&amp;lt;/a&amp;gt; using IBM Cloud and Watson IoT&lt;/p&gt;
&lt;p&gt;If you&apos;re interested in spinning up your own MQTT broker with custom functionality you can take a look at &amp;lt;a href=&amp;quot;http://www.mosca.io/&amp;quot;&amp;gt;Mosca&amp;lt;/a&amp;gt; or get an even deeper understanding of the MQTT Protocol &amp;lt;a href=&amp;quot;https://developer.ibm.com/articles/iot-mqtt-why-good-for-iot/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;on IBM Developer&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We&apos;ve used a couple of different technologies and depending on your background you may not be familiar with everything here. The best thing I&apos;d say to get to understand what we&apos;ve covered would be to play around with the code as well as look at some of the other services and use-cases for message brokers and get a feel for what&apos;s out there&lt;/p&gt;
&lt;p&gt;Good luck&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Intro to F# Web APIs</title><link>https://nabeelvalley.co.za/blog/2019/30-10/fsharp-webapi/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2019/30-10/fsharp-webapi/</guid><description>Introduction to .NET Core Web APIs with F#</description><pubDate>Wed, 30 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So we&apos;re going to be taking a bit of a look on how you can go about building your first F# Web API using .NET Core. I&apos;m going to cover a lot of the basics, a lot of which should be familiar to anyone who has worked with .NET Web Applications and F# in general.&lt;/p&gt;
&lt;p&gt;Along the way I&apos;m also going to go through some important concepts that I feel are maybe not that clear from a documentation perspective that are actually super relevant to using this F# in a real-life context&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you&apos;re totally new to F# though you may want to take a look at &amp;lt;a href=&amp;quot;https://fsharpforfunandprofit.com/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;F# for Fun and Profit&amp;lt;/a&amp;gt; or my personal quick reference documentation over &lt;a href=&quot;/docs/dotnet/intro-to-fs&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;Assuming you&apos;ve got the .NET Core SDK with F# installed, you can simply create a new project with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet new webapi --language F# --name FSharpWebApi

code .\FSharpWebApi
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Alternatively, if you&apos;re feeling a little &lt;em&gt;unexperimental&lt;/em&gt; you can use the Visual Studio project creation wizard, psshhtt&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once you have the project open you can run the following command to launch the application:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dotnet run
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which should start the application on &lt;code&gt;https://localhost:5001&lt;/code&gt; and &lt;code&gt;http://localhost:5000&lt;/code&gt;, you can see the current existing endpoint at &lt;code&gt;/weatherforecast&lt;/code&gt;, this is handled by the &lt;code&gt;Controllers/WeatherForecastController.fs&lt;/code&gt; file&lt;/p&gt;
&lt;h2&gt;Looking Around&lt;/h2&gt;
&lt;p&gt;Looking at the structure of the project files you should see the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FSharpWebApi
│   appsettings.Development.json
│   appsettings.json
│   FSharpWebApi.fsproj
│   Program.fs
│   Startup.fs
│   WeatherForecast.fs
│
├───Controllers
│       WeatherForecastController.fs
│
└───Properties
        launchSettings.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, mostly we see the typical Web API stuff that we&apos;d expect for a C# project such as the &lt;code&gt;startup&lt;/code&gt; and &lt;code&gt;program&lt;/code&gt; files. In F# they serve pretty much the same purpose.&lt;/p&gt;
&lt;p&gt;Looking at the &lt;code&gt;Program.fs&lt;/code&gt; file we can see that it contains the &lt;code&gt;main&lt;/code&gt; function and configures the Web Host, next we can see that the &lt;code&gt;Startup.fs&lt;/code&gt; file contains the usual configuration methods. We should note that the method calls within these functions are piped to an &lt;code&gt;ignore&lt;/code&gt; so the the functions to not return their respective &lt;code&gt;Builders&lt;/code&gt; as this will break the application&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Program.fs&lt;/code&gt; and &lt;code&gt;Startup.fs&lt;/code&gt; files can be seen below&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Program.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;namespace FSharpWebApi

module Program =
    let exitCode = 0

    let CreateHostBuilder args =
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(fun webBuilder -&amp;gt;
                webBuilder.UseStartup&amp;lt;Startup&amp;gt;() |&amp;gt; ignore
            )

    [&amp;lt;EntryPoint&amp;gt;]
    let main args =
        CreateHostBuilder(args).Build().Run()

        exitCode
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Startup.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;namespace FSharpWebApi

type Startup private () =
    new (configuration: IConfiguration) as this =
        Startup() then
        this.Configuration &amp;lt;- configuration

    // This method gets called by the runtime. Use this method to add services to the container.
    member this.ConfigureServices(services: IServiceCollection) =
        // Add framework services.
        services.AddControllers() |&amp;gt; ignore

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    member this.Configure(app: IApplicationBuilder, env: IWebHostEnvironment) =
        if (env.IsDevelopment()) then
            app.UseDeveloperExceptionPage() |&amp;gt; ignore

        app.UseHttpsRedirection() |&amp;gt; ignore
        app.UseRouting() |&amp;gt; ignore

        app.UseAuthorization() |&amp;gt; ignore

        app.UseEndpoints(fun endpoints -&amp;gt;
            endpoints.MapControllers() |&amp;gt; ignore
            ) |&amp;gt; ignore

    member val Configuration : IConfiguration = null with get, set
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we have the &lt;code&gt;FSharpWebApi.fsproj&lt;/code&gt; file which contains references to the relevant code files. It&apos;s important to note that the order of the files in the &lt;code&gt;ItemGroup&lt;/code&gt; specifies the order that files depend on each other. Lower files depend on files higher up&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;Project Sdk=&amp;quot;Microsoft.NET.Sdk.Web&amp;quot;&amp;gt;

  &amp;lt;PropertyGroup&amp;gt;
    &amp;lt;TargetFramework&amp;gt;netcoreapp3.0&amp;lt;/TargetFramework&amp;gt;
  &amp;lt;/PropertyGroup&amp;gt;

  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;Compile Include=&amp;quot;WeatherForecast.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Controllers/WeatherForecastController.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Startup.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Program.fs&amp;quot; /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;

&amp;lt;/Project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lastly, we have a controller that resides in the &lt;code&gt;Controllers/WeatherForecastController.fs&lt;/code&gt; with its types defined in the &lt;code&gt;WeatherForecast.fs&lt;/code&gt; file. Looking at the &lt;code&gt;WeatherForecast.fs&lt;/code&gt; file we can see that the type has a few simple properties and one function&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WeatherForecast.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;namespace FSharpWebApi

open System

type WeatherForecast =
    { Date: DateTime
      TemperatureC: int
      Summary: string }

    member this.TemperatureF =
        32 + (int (float this.TemperatureC / 0.5556))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next up, we can see the controller which contains a single &lt;code&gt;GET&lt;/code&gt; endpoint which delivers a random array of weather forecasts. Here we can see a few different things. First, the namespace is &lt;code&gt;FSharpWebApi.Controllers&lt;/code&gt;, this pretty much follows the .NET standard of the Namespace being related to the Folder name, we can also see the &lt;code&gt;ApiController&lt;/code&gt; attribute that adds &amp;lt;a href=&amp;quot;https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-3.0#apicontroller-attribute&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;some useful functionality&amp;lt;/a&amp;gt; for basic API handling and the &lt;code&gt;Route&lt;/code&gt; attribute that states the controller route&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;WeatherForecastController&lt;/code&gt; type defines the controller and that it inherits from &lt;code&gt;ControllerBase&lt;/code&gt;, additionally the constructor requires the &lt;code&gt;ILogger&lt;/code&gt; service which will be provided by DependencyInjection&lt;/p&gt;
&lt;p&gt;Lastly, looking at the &lt;code&gt;__Get&lt;/code&gt; method we can see the &lt;code&gt;HttpGet&lt;/code&gt; attribute that specifies that this is a Get Method, and the &lt;code&gt;__&lt;/code&gt; shows that we don&apos;t care about references to the function&apos;s &lt;code&gt;this&lt;/code&gt;, and the return type for the function is an &lt;code&gt;array&lt;/code&gt; of &lt;code&gt;WeatherForecast&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WeatherForecastController.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;namespace FSharpWebApi.Controllers

open System
open Microsoft.AspNetCore.Mvc
open Microsoft.Extensions.Logging
open FSharpWebApi

[&amp;lt;ApiController&amp;gt;]
[&amp;lt;Route(&amp;quot;[controller]&amp;quot;)&amp;gt;]
type WeatherForecastController (logger : ILogger&amp;lt;WeatherForecastController&amp;gt;) =
    inherit ControllerBase()

    let summaries = [| &amp;quot;Freezing&amp;quot;; &amp;quot;Bracing&amp;quot;; &amp;quot;Chilly&amp;quot;; &amp;quot;Cool&amp;quot;; &amp;quot;Mild&amp;quot;; &amp;quot;Warm&amp;quot;; &amp;quot;Balmy&amp;quot;; &amp;quot;Hot&amp;quot;; &amp;quot;Sweltering&amp;quot;; &amp;quot;Scorching&amp;quot; |]

    [&amp;lt;HttpGet&amp;gt;]
    member __.Get() : WeatherForecast[] =
        let rng = System.Random()
        [|
            for index in 0..4 -&amp;gt;
                { Date = DateTime.Now.AddDays(float index)
                  TemperatureC = rng.Next(-20,55)
                  Summary = summaries.[rng.Next(summaries.Length)] }
        |]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Creating a Controller&lt;/h2&gt;
&lt;p&gt;Creating a new controller is not particularly complex given that we have the above as a starting point.&lt;/p&gt;
&lt;h2&gt;Get Handler&lt;/h2&gt;
&lt;p&gt;We&apos;re going to create a handler that is able to return a simple message for an &lt;code&gt;even&lt;/code&gt; param, and a &lt;code&gt;404&lt;/code&gt; for a &lt;code&gt;odd&lt;/code&gt; param in order to look at how we can return actual response codes in cases where we aren&apos;t always able to return something of a constant type&lt;/p&gt;
&lt;p&gt;First, we can create a &lt;code&gt;Controllers/MessageController.fs&lt;/code&gt; file with just some basic scaffolding to start with. We&apos;ll define a &lt;code&gt;Get&lt;/code&gt; controller that just returns the &lt;code&gt;id&lt;/code&gt; it receives as a route param multiplied by two if the the result &lt;code&gt;shouldDouble&lt;/code&gt; param is set to &lt;code&gt;true&lt;/code&gt;. Additionally we can see the &lt;code&gt;sprint&lt;/code&gt; function used to format the output as a string&lt;/p&gt;
&lt;p&gt;Before we can add the data to the actual controller we need to add the &lt;code&gt;&amp;lt;Compile Include=&amp;quot;Controllers/MessageController.fs&amp;quot; /&amp;gt;&lt;/code&gt; to the &lt;code&gt;ItemGroup&lt;/code&gt; in the &lt;code&gt;FSharpWebApi.fsproj&lt;/code&gt; file, :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;FSharpWebApi.fsproj&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;  &amp;lt;ItemGroup&amp;gt;
    &amp;lt;Compile Include=&amp;quot;WeatherForecast.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Controllers/WeatherForecastController.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Controllers/MessageController.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Startup.fs&amp;quot; /&amp;gt;
    &amp;lt;Compile Include=&amp;quot;Program.fs&amp;quot; /&amp;gt;
  &amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then we can put together the controller in the &lt;code&gt;MessageController.fs&lt;/code&gt; file:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MessageController.fs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;namespace FSharpWebApi.Controllers

open Microsoft.AspNetCore.Mvc
open Microsoft.Extensions.Logging

[&amp;lt;ApiController&amp;gt;]
[&amp;lt;Route(&amp;quot;[controller]&amp;quot;)&amp;gt;]
type MessageController (logger : ILogger&amp;lt;MessageController&amp;gt;) =
    inherit ControllerBase()

    [&amp;lt;HttpGet(&amp;quot;{id}&amp;quot;)&amp;gt;]
    member __.Get (id : int, shouldDouble : bool) : string=
        logger.LogInformation(&amp;quot;I am a controller&amp;quot;)

        let result =
            match shouldDouble with
            | true -&amp;gt; id * 2
            | false -&amp;gt; id

        sprintf &amp;quot;Hello %d&amp;quot; result
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From the function&apos;s signature we can see that it has an &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;shouldDouble&lt;/code&gt; values as inputs and that it returns a string. We have made these explicit however if we were to leave them out it would be fine too as F# would be able to infer the types, see that below:&lt;/p&gt;
&lt;p&gt;We can open the following URLs in our browser and should be able to open the &lt;code&gt;/message/3&lt;/code&gt; and &lt;code&gt;/message/3?shouldDouble=true&lt;/code&gt; routes and see &lt;code&gt;hello 3&lt;/code&gt; and &lt;code&gt;hello 6&lt;/code&gt; respectively&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that if not specified the handler inputs will try to be parsed from the body&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, if we would want to update this to return some sort of general HTTP Response Code when a user sends some kind of input, for example if the &lt;code&gt;result&lt;/code&gt; is 4, we will need to modify the function such that we are able to reference the &lt;code&gt;this&lt;/code&gt; and the return type of the function is now an &lt;code&gt;IActionResult&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;[&amp;lt;HttpGet(&amp;quot;{id}&amp;quot;)&amp;gt;]
member this.Get (id : int, shouldDouble : bool) : IActionResult =
    logger.LogInformation(&amp;quot;I am a controller&amp;quot;)

    let result =
        match shouldDouble with
        | true -&amp;gt; id * 2
        | false -&amp;gt; id

    match result with
    | 4 -&amp;gt; this.NoContent() :&amp;gt; IActionResult
    | _ -&amp;gt;
        sprintf &amp;quot;Hello %d&amp;quot; result
        |&amp;gt; this.Ok
        :&amp;gt; IActionResult
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From this we can see that we are using an additional match to either return &lt;code&gt;this.NoContent()&lt;/code&gt; as an &lt;code&gt;IActionResult&lt;/code&gt; or &lt;code&gt;this.Ok&lt;/code&gt; with the piped message as an &lt;code&gt;IActionResult&lt;/code&gt;. Just note that the following matches are equivalent:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;

// call the `this.Ok` function with
match result with
| 4 -&amp;gt; this.NoContent() :&amp;gt; IActionResult
| _ -&amp;gt;
    this.Ok(sprintf &amp;quot;Hello %d&amp;quot; result) :&amp;gt; IActionResult

// pipe the result of the format through
match result with
| 4 -&amp;gt; this.NoContent() :&amp;gt; IActionResult
| _ -&amp;gt;
    sprintf &amp;quot;Hello %d&amp;quot; result
    |&amp;gt; this.Ok
    :&amp;gt; IActionResult

// pipe the result of the format through on a single line
match result with
| 4 -&amp;gt; this.NoContent() :&amp;gt; IActionResult
| _ -&amp;gt; sprintf &amp;quot;Hello %d&amp;quot; result |&amp;gt; this.Ok :&amp;gt; IActionResult
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Post Handler&lt;/h2&gt;
&lt;p&gt;We can also create a &lt;code&gt;POST&lt;/code&gt; handler that will pretty much do the same as the above handler, we can pretty much just take the values from the function body and pass it to the previous handler we put together&lt;/p&gt;
&lt;p&gt;Before we can create the handler, we need to create a type called &lt;code&gt;PostData&lt;/code&gt; that can be used by the method to receive data, we can define this towards the top of the file, above the type definition for our &lt;code&gt;MessageController&lt;/code&gt;. The type also needs to have the &lt;code&gt;CLIMutable&lt;/code&gt; attribute so that the JSON deserializer can parse the data from the post body into it correctly&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;[&amp;lt;CLIMutable&amp;gt;]
type PostData =
    { id : int
      shouldDouble : bool }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we simply need to define the &lt;code&gt;Post&lt;/code&gt; method with an &lt;code&gt;HttpPost&lt;/code&gt; attribute which will just call the &lt;code&gt;this.Get&lt;/code&gt; using the input params. this can be done pretty simply too&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-fs&quot;&gt;[&amp;lt;HttpPost&amp;gt;]
member this.Post(data : PostData) : IActionResult =
    this.Get(data.id, data.shouldDouble)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s really all that&apos;s needed&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So yeah, that&apos;s pretty much it - Not that bad right? I feel like there are a couple of things that feel a little bit weird because of the pieces of OOP running around from C# that add a bit more overhead than I&apos;d like, but it&apos;s .NET, that&apos;s inevitable&lt;/p&gt;
&lt;p&gt;Still a few more to posts on F# to come, so stay in tuned&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Looky, a wild HTML!</title><link>https://nabeelvalley.co.za/blog/2019/12-10/looky-a-wild-html/</link><guid isPermaLink="true">https://nabeelvalley.co.za/blog/2019/12-10/looky-a-wild-html/</guid><description>The first blog post, A quick journey through my design and development process for the site</description><pubDate>Tue, 01 Oct 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Here at last&lt;/h2&gt;
&lt;p&gt;So, after far too long, we are here. A mostly-functional website, that I have not tested on a single iOS device which may prove to be problematic&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note to self, test on an iPhone or something&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For the past six months or so I&apos;ve looked at myself with a full stack of irony knowing that I, a web developer, do not have &lt;strong&gt;my own&lt;/strong&gt; website. Or well, not one I&apos;d actually want anyone to see (*cough cough* I&apos;m talking to you, Weebly)&lt;/p&gt;
&lt;h2&gt;The Design Process&lt;/h2&gt;
&lt;p&gt;Well, the design process, especially when you&apos;re trying to satisfy your unattainable standard of perfection, can be difficult. I actually ran through a shocking number of iterations and end-to-end redesigns but I just could not seem to find something that satisfied me. Until one day, it all just sort of hit me at once&lt;/p&gt;
&lt;p&gt;None of this nonsensical &amp;quot;cards and shadows&amp;quot; drama, no random floopy animations, none of that, just a blank slate, with some text and imagery.&lt;/p&gt;
&lt;p&gt;I think I have a fair stock of those&lt;/p&gt;
&lt;h3&gt;Design v1&lt;/h3&gt;
&lt;p&gt;The first iteration that I have saved is this one, I had big dreams, there were going to be things moving all over the place, I was going to break the norm with &lt;strong&gt;horizontal scrolling&lt;/strong&gt;, and just basically turn the site into a slide-show. But I didn&apos;t like the lack of fluidity with the overall design. Regardless, here are the first few screens:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2019/12-10/design1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;During this initial phase I had sort figured out what my key goals were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Unique experience on every device.&lt;/li&gt;
&lt;li&gt;Unobtrusive elements&lt;/li&gt;
&lt;li&gt;Clean lines&lt;/li&gt;
&lt;li&gt;I needed to take emphasis away from the design, and onto the content&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Basically, I wanted something basic&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;By now I had decided on the three most important things, &lt;strong&gt;#E44D90&lt;/strong&gt;, &lt;em&gt;Montserrat&lt;/em&gt;, and &lt;code&gt;Nova Mono&lt;/code&gt;, but there&apos;s still a lot I was unsure of&lt;/p&gt;
&lt;h3&gt;Design v2&lt;/h3&gt;
&lt;p&gt;This version mostly morphed out of the first one, I was trying to address two things primarily&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How can I not confuse people&lt;/li&gt;
&lt;li&gt;Actually yeah, just the first thing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Personally, I hate this design. But It was definitely valuable in telling me what I didn&apos;t want this site to be&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2019/12-10/design2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ve always disliked cards, and abusing it the way I was in that further deepened my hate. I felt kind of like &lt;em&gt;&amp;quot;Well if everyone else does it, maybe I should give it a shot?&amp;quot;&lt;/em&gt;, to be fair it&apos;s probably not the cards, it&apos;s me&lt;/p&gt;
&lt;h3&gt;Design v3&lt;/h3&gt;
&lt;p&gt;This is what you&apos;re seeing now (Assuming you&apos;re reading this in October 2019) I love how this design places a strong emphasis on the imagery and text, there isn&apos;t really much else in the way of it aside from occasional underline. Simplicity&lt;/p&gt;
&lt;p&gt;I addressed my remaining goals by sticking to a basic site layout with a fairly aggressive grid to deliver interesting layouts for different devices&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/content/blog/2019/12-10/design3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;That being said, and my heart being content. It was time to code&lt;/p&gt;
&lt;h2&gt;The &lt;em&gt;&amp;quot;Bashing your head against a wall&amp;quot;&lt;/em&gt; Process&lt;/h2&gt;
&lt;p&gt;I used React - Why? Because I used React. Sure, I could have went the Server-Side route and made sure I was sending normal HTML to people, but I wanted a sustainable component library that I could develop as well as super-quick responsiveness on the client, and from experience, I knew I could knock this out fastest with React. That being said, I kind of wish I had looked at setting up pre-rendering before I started, because I feel like it&apos;s going to be admin to add after (will basically need to refactor out all the &lt;code&gt;&amp;lt;Suspense/&amp;gt;&lt;/code&gt;) tags&lt;/p&gt;
&lt;p&gt;Now, as any front-end developer should know in 2019, you gotta start with &lt;code&gt;npx create-react-app my-app&lt;/code&gt; and after about three years of &lt;code&gt;node_modules&lt;/code&gt; you&apos;re ready to go&lt;/p&gt;
&lt;h3&gt;Content Management System?&lt;/h3&gt;
&lt;p&gt;I&apos;m not going to go into the details of the development because there isn&apos;t really anything too fancy going on here - the site is mostly static anyway. I will however just talk about the Content Management System&lt;/p&gt;
&lt;p&gt;Well ..., I think it depends on your view of a CMS. I really didn&apos;t want to go overkill on this so I&apos;m making use of a fairly simple system. Each post consists of a &lt;code&gt;post.md&lt;/code&gt; and a &lt;code&gt;post.json&lt;/code&gt; file&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.md&lt;/code&gt; file is the Markdown file, it&apos;s the file that I write in as I write the post, and potentially every post in future&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.json&lt;/code&gt; file is also very simple at the moment and contains some &lt;code&gt;metadata&lt;/code&gt; for the post such as the title and the date. I made this separation so that I would not have to get funky with my file processing, and I&apos;m fairly happy with it&lt;/p&gt;
&lt;p&gt;To process and render the Markdown I&apos;m using a library that I fell in love with just over a year ago called &lt;a href=&quot;https://github.com/showdownjs/showdown&quot;&gt;&lt;code&gt;Showdown.js&lt;/code&gt;&lt;/a&gt;, and to add syntax highlighting I&apos;m using some flavour of &lt;a href=&quot;https://highlightjs.org/&quot;&gt;&lt;code&gt;Highlight.js&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&apos;ve then simply rendered the content by &lt;code&gt;fetch&lt;/code&gt;ing it from the &lt;em&gt;Folder-cms&lt;/em&gt; and passing it through a Markdown Component&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import React from &apos;react&apos;
import { Converter } from &apos;showdown&apos;
import * as showdownHighlighter from &apos;showdown-highlight&apos;

import &apos;./Markdown.css&apos;

const convertMarkdownToHtml = (text) =&amp;gt; {
  const converter = new Converter({
    headerLevelStart: 2,
    parseImgDimensions: true,
    extensions: [showdownHighlighter],
  })
  const html = converter.makeHtml(text)
  return html
}
const Markdown = ({ text }) =&amp;gt; (
  &amp;lt;div
    className=&amp;quot;Markdown&amp;quot;
    dangerouslySetInnerHTML={{ __html: convertMarkdownToHtml(text) }}
  &amp;gt;&amp;lt;/div&amp;gt;
)

export default Markdown
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&apos;s pretty much it. It gets rendered into the page you&apos;re looking at now and that&apos;s all it takes really. It&apos;s a bit of a shame that my syntax highlighting CSS theme doesn&apos;t really do justice on JS, another TODO I suppose&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There were a couple of new things I learnt during this entire process, simple little things really like how to change the colour of the scrolly thing on your browser, or how to put together a mildly-reasonable file system to store the posts, but more than anything I enjoyed being able to just take something from pure concept to a final build that lines up pretty well with my initial vision&lt;/p&gt;
&lt;p&gt;That&apos;s all for now, stay tuned, lots more to come. But in the mean time take a look around, let me know what bugs you find (as I said, very untested)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nabeel Valley&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item></channel></rss>